课程外碰到的奇怪问题,希望老师帮助
来源: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回答
-
这个应该是代码的问题,不是文件结构或是逻辑的问题。也说了代码比较繁琐,我的建议是想办法写一小段独立的代码来重现这个问题,然后贴上来看。写的过程中会把问题从业务逻辑中剥离出来,自己也会看的更清楚
032020-08-05 -
qq_白澤_0
提问者
2020-08-01
准确的说。在进入gorountine之前。m1有第一个键值对。进入之后一次添加了第二个或者对第二个更改。然后f1内部打印除了第一次更改,之后m1的第一个键值对都是全零。新更改的值是对的。
因为设定是第一个已经存在的键值对是不用改的。结果之后就变为全0了。想不懂为什么。
覆盖第一个键值对解决了问题。但是感觉很奇怪。
042020-08-08
相似问题