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

来源:3-4 Map

qq_白澤_0

2020-08-01

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

文件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回答

ccmouse

2020-08-02

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

0
3
qq_白澤_0
还是我的代码逻辑问题。 我只是疑惑这里的清零覆盖问题。 已有一个slice项,逻辑是这个slice是每次重新填充的,随时写随时用。之前写的,如果不重新写一遍,第一次可以读出来,返回后被覆盖是置为全0而不是nil。 我不知道我的理解对不对。
2020-08-05
共3条回复

qq_白澤_0

提问者

2020-08-01

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

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


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

0
4
qq_白澤_0
回复
ccmouse
好的,谢谢老师。我再想想怎么改代码。 我也想过这个,但是也不太对。如果update未执行,主函数先返回的话,新增的应该没改。现在是每次返回时之前的值如果不更改的话置为0,本次更改是正确的。就好像每次只能看见更改的。这里感觉就像旧的数据丢失了一样。我在想是不是变量作用域的问题,因为addblock和bc.addblock在不同的go文件,需要来回跳转。 我再仔细看看代码想想吧。
2020-08-08
共4条回复

Google资深工程师深度讲解Go语言 由浅入深掌握Go语言

语法+分布式爬虫实战 为转型工程师量身打造

5995 学习 · 1908 问题

查看课程