超级账本源码解析之Commit

本系列目录:超级账本源码(V1.3)解析目录

当peer收到leader发来的block后,需要进行VSCC、MVCC、commit三步操作。

前两篇博客里我们讲了【VSCC】【MVCC】这两个过程,下面分析Commit这个过程的核心代码(HLF v1.3)。

前置

  1. gossip/state/state.golisten函数中收到payload(其中有block和private data),通过queueNewMessage将其放入payloads中等待后续处理。
  2. 然后在deliverPayloads函数中开始处理payloads中的payload,得到block和pvtData后,做了一些简单的检查,之后调用commitBlock函数。
  3. commitBblock中,调用了gossip/privdata/coordinator.go中的StoreBlock函数和UpdateLedgerHeight函数(TODO)。
  4. StoreBlock函数中,先进行了【VSCC】,然后调用core/ledger/kvledger/lv_ledger.go中的CommitWithPvtData函数。

Commit

  1. CommitWithPvtData主要做了三件事情:1,MVCC(ValidateAndPrepare);2,存储block(block_commit);3,更新world state数据库(state_commit)。(可选的4,更新history数据库l.historyDB.Commit,可以在sampleconfig/core.yaml中配置)。我们在上一篇博客中已经讲了【MVCC】这个过程,接下来主要讲解后两个过程。

block_commit

  1. 调用了core/ledger/ledgerstorage/store.go中的CommitWithPvtData函数:

    a. core/ledger/pvtdatastorage/store_impl.go中的s.pvtdataStore.Prepare ,往数据库中写入了pendingCommitKey“锁”,并准备好private data(其实已经put in db)

    b. 调用common/ledger/blkstorage/fsblkstorage/fs_blockstore.go中的AddBlock,接着在common/ledger/blkstorage/fsblkstorage/blockfile_mgr.goaddBlock中,先获取了账本文件的最新信息(偏移量),然后写入了新block的长度与内容。接着更新了checkpoint信息,并调用saveCurrentInfo将checkpoint信息存储数据库。然后调用了common/ledger/blkstorage/fsblkstorage/blockindex.go中的indexBlock(见7)建立了各个tx的索引,存到数据库中。

    c. 如果b失败,那么会调用Rollback撤销a中的操作(也就是删除db中新插入的这些key);如果b成功, s.pvtdataStore.Commit删除了pendingCommitKey“锁”,并更新commit信息

    这里private data其实就是两阶段提交(2PC),因为需要保证block commit与private data commit的原子性(都成功commit或者失败)。使用2PC,如果commit block之前或者之后机器crash了,就可以根据情况来rollback或者commit private data。 (不过1.3版本的代码里Rollback还没有实现=_=||,这里可以看一下最新版本的代码)
    具体可以看core/ledger/ledgerstorage/store.go中的syncPvtdataStoreWithBlockStore函数的实现。

  2. indexBlock中,依次建立了如下索引:(是否建立该类型的索引在core/ledger/ledgerstorage/store.go中的NewProvider硬编码)

    1. map[blockHash] = blockchain[block]
      其中blockchain是保存block的所有文件,blockchain[block]包含了该block的文件名和偏移量。
    2. map[blockNum] = blockchain[block]
      以上两个索引使得我们可以快速根据blockNum或者blockHash定位到该block
    3. 对该block中的每一个tx,map[txid] = blockchain[tx]
      blockchain[tx]包含了该tx所在的文件名以及偏移量,可以根据txid定位到该tx。
      需要注意的是这一步还检查了txid是否重复,如果重复就不再对该tx建立索引。
    4. 对该block中的每一个tx,map[blockNum + TxNumber] = blockchain[tx]
    5. 对该block中的每一个tx,map[txid] = blockchain[block]
      可以根据txid获得该tx所在block的位置。
    6. 对该block中的每一个tx,map[txid] = valid/invalid,记录交易是否有效
    7. 最后记录该checkpoint对应的blockNum(也就是当前block的number), map[checkpoint] = blockNumber

state_commit

  1. core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr/lockbased_txmgr.go中的Commit函数中进行了state_commit,也就是更新world state DB。其中调用了core/ledger/kvledger/txmgmt/privacyenabledstate/common_storage_db.go中的ApplyPrivacyAwareUpdates来将【MVCC】中得到的write set(txmgr.current.batch)更新到DB。

总结

我们总结一下整个【VSCC】【MVCC】【Commit】阶段涉及到的和数据库有关的操作,可以更好地理清整个流程,并对细节更加清晰。
TODO.

get file location: 
get state:  chaincode
get state: tx key


batch pvt pending:  ` private data write sets for block`
put in db: `jyp: checkpoint put in db`
get file location:
batch index:   `Indexing block `
batch pvt data: `Committing private data for b`


batch state: 
batch history:

猜你喜欢

转载自blog.csdn.net/yijiull/article/details/108410220