请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

课程外碰到的奇怪问题,希望老师帮助

尝试了好几次没能复现错误。我直接把主要代码搬过来。我做区块链相关,刚开始不久,感觉找不到问题的根源。希望老师帮忙看一看。都在我打了注释的行后面。

文件blockchain.go
bc的结构体

type Blockchain struct {
	tips [][]byte
	db   *bolt.DB //boltdb address
}

下面的代码之前已经对bc.tips[0]做过赋值,其余为[]byte{}

文件Serve.go
节点模拟通信用的是不同的终端窗口
都是一些跳转,不需要关注,从handleconection->handleblock->addblock

// StartServer starts a node
func StartServer(nodeID, minerAddress string) {
	nodeAddress = fmt.Sprintf("localhost:%s", nodeID)
	miningAddress = minerAddress
	ln, err := net.Listen(protocol, nodeAddress)
	if err != nil {
		log.Panic(err)
	}
	defer ln.Close()

	bc := NewBlockchain(nodeID)

	if nodeAddress != knownNodes[0] {
		sendVersion(knownNodes[0], bc)
	}

	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Panic(err)
		}
		// go rountine
		go handleConnection(conn, bc)
	}
}
func handleConnection(conn net.Conn, bc *Blockchain) {

	request, err := ioutil.ReadAll(conn)
	if err != nil {
		log.Panic(err)
	}
	command := bytesToCommand(request[:commandLength])
	fmt.Printf("Received %s command\n", command)

	switch command {
	case "addr":
		handleAddr(request)
	//这个情况下
	case "block":
		handleBlock(request, bc)
	...
	...
	default:
		fmt.Println("Unknown command!")
	}

	conn.Close()
}
func handleBlock(request []byte, bc *Blockchain) {
	var buff bytes.Buffer
	var payload block

	buff.Write(request[commandLength:])
	dec := gob.NewDecoder(&buff)
	err := dec.Decode(&payload)
	if err != nil {
		log.Panic(err)
	}

	blockData := payload.Block
	block := DeserializeBlock(blockData)

	fmt.Println("Recevied a new block!")
//主要问题的函数
	bc.AddBlock(block)

	fmt.Printf("Added block %x\n", block.Hash)
//检查
	for i, v := range bc.tips {
		fmt.Printf("addretuened----  %d:%x\n", i, v)
	}

	if len(blocksInTransit) > 0 {
		blockHash := blocksInTransit[0]
		sendGetData(payload.AddrFrom, "block", blockHash)

		blocksInTransit = blocksInTransit[1:]
	} else {
		UTXOSet := UTXOSet{bc}
		UTXOSet.Reindex()
		//UTXOSet.Update(block)
	}
}

文件blockchain.go

func (bc *Blockchain) AddBlock(block *Block) {
	var lastHeight int
	var newestLastKey string
	var thisKeyBlockHeight int

	err := bc.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(blocksBucket))
		blockInDb := b.Get(block.Hash)
		if blockInDb == nil {
			//return nil
			blockData := block.Serialize()
			err := b.Put(block.Hash, blockData)
			if err != nil {
				log.Panic(err)
			}
		}

		for _, key := range MostLastBlockKeys {
			if len(b.Get([]byte(key))) != 0 {
				thisKeyBlockHeight = DeserializeBlock(b.Get(b.Get([]byte(key)))).Height
				if thisKeyBlockHeight > lastHeight {
					lastHeight = thisKeyBlockHeight
					newestLastKey = key
				}
			}
		}

		newestheights := make([]int, MaxSideChainNumber+1)
		for i, key := range MostLastBlockKeys {
			lasth := b.Get([]byte(key))
			if len(lasth) != 0 {
				newestheights[i] = DeserializeBlock(b.Get(lasth)).Height
			} else { 
				newestheights[i] = lastHeight
			}
		}
	
		if block.Height >= newestheights[getIndex(block.ChainFlag+"l", MostLastBlockKeys)] {
			err := b.Put([]byte(block.ChainFlag+"l"), block.Hash)
			if err != nil {
				log.Panic(err)
			}
//对tips的更改
			bc.tips[getIndex(block.ChainFlag+"l", MostLastBlockKeys)] = block.Hash
		return nil
	})
	if err != nil {
		log.Panic(err)
	}
}

问题:

在bc.addblock之后加上打印显示如下bc.tip本来只有[0]有值。
Addblock一次
图片描述
Addblock第二次及之后
图片描述

发现是在bc.db.update之后更改的【这个是一个bolt数据库更新函数】。我很奇怪的是这里db和tips是不干扰的啊。

我在想可不可能是文件结构的原因。但是想不明白。我的文件结构是除了main其余都在一个package里不同的go文件。
想不明白问题出在哪里。希望老师可以看看。

正在回答

2回答

这个应该是代码的问题,不是文件结构或是逻辑的问题。也说了代码比较繁琐,我的建议是想办法写一小段独立的代码来重现这个问题,然后贴上来看。写的过程中会把问题从业务逻辑中剥离出来,自己也会看的更清楚

0 回复 有任何疑惑可以回复我~
  • 提问者 qq_白澤_0 #1
    非常感谢!
    回复 有任何疑惑可以回复我~ 2020-08-05 10:53:23
  • 提问者 qq_白澤_0 #2
    谢谢老师。我找到原因了。是代码出了问题。map并没有实际存储下来,需要重新写一遍。如果不重新写会刷新。map[string][]byte。奇怪的是刷新不是置为nil,而是置为了全零。这里好像是我漏掉了一些go的基本知识。
    回复 有任何疑惑可以回复我~ 2020-08-05 10:58:40
  • 提问者 qq_白澤_0 #3
    还是我的代码逻辑问题。
    我只是疑惑这里的清零覆盖问题。
    已有一个slice项,逻辑是这个slice是每次重新填充的,随时写随时用。之前写的,如果不重新写一遍,第一次可以读出来,返回后被覆盖是置为全0而不是nil。
    我不知道我的理解对不对。
    回复 有任何疑惑可以回复我~ 2020-08-05 11:06:19
提问者 qq_白澤_0 2020-08-01 10:30:05

准确的说。在进入gorountine之前。m1有第一个键值对。进入之后一次添加了第二个或者对第二个更改。然后f1内部打印除了第一次更改,之后m1的第一个键值对都是全零。新更改的值是对的。

因为设定是第一个已经存在的键值对是不用改的。结果之后就变为全0了。想不懂为什么。


覆盖第一个键值对解决了问题。但是感觉很奇怪。

0 回复 有任何疑惑可以回复我~
  • ccmouse #1
    看起来似乎找到了问题的点。但描述还是有歧义,可以尝试写一小段代码来重现这个问题,我们针对代码讨论。
    回复 有任何疑惑可以回复我~ 2020-08-07 09:11:48
  • 提问者 qq_白澤_0 回复 ccmouse #2
    我没能复现。大概贴了一下代码。关键的地方就一两处。老师您帮忙看看。
    回复 有任何疑惑可以回复我~ 2020-08-07 16:31:40
  • ccmouse 回复 提问者 qq_白澤_0 #3
    err := bc.db.Update(func(tx *bolt.Tx) error {...
    这里的Update参数是一个函数。这个函数体里面写了一大堆,都不会立刻执行,只是创建了一个函数,作为参数传给bc.db.Update。此时主函数返回,传给Update的函数还来不及执行。而它执行的时机就是bc.db.Update真正去修改数据库的时候。
    回复 有任何疑惑可以回复我~ 2020-08-07 18:40:59
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信