Nebulas采用和比特币/以太币一样的区块链结构:区块链由一个个区块串链构成,交易打包在区块中。BlockChain定义在core/blockchain.go中,其中包括BlockPool和TransactionPool:
1.// BlockChain the BlockChain core type.
2.type BlockChainstruct{
3.chainID uint32 //区块链编号
4.
5.genesis *corepb.Genesis //创世纪块描述
6.
7.genesisBlock *Block //创世纪块
8.tailBlock *Block //最新区块
9.
10.bkPool *BlockPool //BlockPool区块池(从网络节点广播)
11.txPool *TransactionPool //TransactionPool(交易池)
12.
13.consensusHandler Consensus //共识模块
14.syncService SyncService //区块同步服务
15.
16.cachedBlocks *lru.Cache //验证过的区块缓存
17.detachedTailBlocks *lru.Cache //可能的最新的区块
18.
19.// latest irreversible block
20.lib *Block //最新的不可逆的确认区块
21.
22.storage storage.Storage //存储
23.
24.eventEmitter *EventEmitter //消息发射器
25.
26.nvm NVM //NVM虚拟机
27.
28.quitCh chanint//退出Chan
29.
30.superNodebool//是否是超级节点
31.
32.unsupportedKeyword string //
33.}
BlockPool定义在core/block_pool.go中:
1.// BlockPool a pool of all received blocks from network.
2.// Blocks will be sent to Consensus when it passes signature verification.
3.type BlockPoolstruct{
4.sizeint//区块池中的区块的固定个数
5.receiveBlockMessageCh chan net.Message //接受区块的Chan
6.receiveDownloadBlockMessageCh chan net.Message //下载区块的Chan
7.quitCh chanint
8.
9.bc *BlockChain
10.cache *lru.Cache //区块的cache
11.
12.ns net.Service //NetService
13.mu sync.RWMutex //同步锁
14.}
BlockPool通过NetService监听网络消息或者本地生成区块,收集区块相关的信息:
handleReceivedBlock函数处理NewBlock以及BlockDownloadResponse区块消息,handleParentDownloadRequest函数处理ParentBlockDownloadRequest区块消息,也就是老区块的下载处理。
BlockPool中的区块间的关系通过linkedBlock类型表示,一个区块只存在一个父区块,但是有可能有多个子区块:
1.type linkedBlockstruct{
2.block *Block //区块信息
3.chain *BlockChain //区块链信息
4.hash byteutils.Hash //区块Hash
5.parentHash byteutils.Hash //父区块Hash
6.
7.parentBlock *linkedBlock //父区块的linkedBlock
8.childBlocks map[byteutils.HexHash]*linkedBlock //子区块的linkedBlock
9.}
TransactionPool定义在core/transaction_pool.go中:
1.// TransactionPool cache txs, is thread safe
2.type TransactionPoolstruct{
3.receivedMessageCh chan net.Message //监听网络上NewTx消息的chan
4.quitCh chanint//退出chan
5.
6.sizeint//交易池的大小
7.candidates *sorted.Slice //交易列表,按GasPrice降序排列
8.buckets map[byteutils.HexHash]*sorted.Slice //交易桶,每个桶装交易地址的所有交易,一个桶中的交易按nonce排列
9.all map[byteutils.HexHash]*Transaction //交易Map,按照交易的Hash进行Map
10.bucketsLastUpdate map[byteutils.HexHash]time.Time //交易桶,记录每个交易地址最后提交交易的时间
11.
12.ns net.Service //NetService
13.mu sync.RWMutex //同步锁
14.
15.minGasPrice *util.Uint128// the lowest gasPrice.//最小Gas Price
16.maxGasLimit *util.Uint128// the maximum gasLimit.//最大Gas Limit
17.
18.eventEmitter *EventEmitter //消息发射器
19.bc *BlockChain
20.}
TransactionPool收集并管理本地和网络上的新交易。这些交易的Gas Price以及Gas Limit必须符合以下的范围:
为了方便查询管理收集到的交易,TransactionPool用三个数据结构进行管理:
TransactionPool收集处理网络或者本地的Transaction。对于本地的Transaction,加入TransactionPool并广播到网络。对于网络的Transaction,加入TransactionPool,并传递给其他网络节点(relay)。
TransactionPool每隔1分钟剔除超时的交易,每隔1秒钟更新性能检测。一个交易的生命周期是90分钟,也就是说,超过90分钟没打包进区块的交易会被剔除。通过NetService的Register接口注册一个Subscriber,通过receivedMessageCh监听网络消息。
其他模块调用TransactionPool提供的接口函数添加/删除/查询交易。AdminService在提交本地创建的交易时,就是调用TransactionPool的PushAndBroadcast接口添加交易。
1.// PushAndBroadcast push tx into pool and broadcast it
2.func (pool *TransactionPool) PushAndBroadcast(tx *Transaction) error {
3.iferr := pool.Push(tx); err != nil { //Push交易到TransactionPool
4.logging.VLog().WithFields(logrus.Fields{
5."tx": tx.StringWithoutData(),
6."err": err,
7.}).Debug("Failed to push tx")
8.returnerr
9.}
10.
11.pool.ns.Broadcast(MessageTypeNewTx, tx, net.MessagePriorityNormal) //广播NewTx消息
12.returnnil
13.}
TransactionPool的Push函数会检查一个交易的合理性。验证ok的交易,加入交易池。并通过消息总线广播TopicPendingTransaction消息给其他模块:
1.// trigger pending transaction
2.event := &state.Event{
3.Topic:TopicPendingTransaction,
4.Data: tx.JSONString(),
5.}
6.pool.eventEmitter.Trigger(event)
一个本地交易如何加入到TransactionPool已经讲解结束。在DPOS的共识机制的介绍中,介绍从TransactionPool中提取交易,打包区块,以及形成共识的过程。
领取专属 10元无门槛券
私享最新 技术干货