文件blockchain.go
bc的结构体
type Blockchain struct {
tips [][]byte
db *bolt.DB //boltdb address
}
文件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文件。
想不明白问题出在哪里。希望老师可以看看。