从2017年11月启动至今,经过历时近一年的研究、开发与测试,初链主网Beta版于新加坡时间2018年09月28日08:00正式上线。从2018年的4月份左右的时间加入初链技术社区到Beta版上线,亲眼看到,初链的一步一步的发展,经历着接近于从无到有的过程,心里说不出的愉悦感。所以在参与翻译并解读黄皮书任务之后,接下了Beta版的技术解读。初链对于我而言,感觉像是亲人,看着初链一步一步的发展壮大,到现在这么庞大的技术社区的运营,真的很快,也很迅速,希望以后会越来越好。
下面进入正题。总所周知,初链主网Beta版在新加坡已经正式上线。Beta版的亮点主要有以下几点,且听我慢慢道来:
1、全球首家实现无许可(Permissionless)环境下的混合共识公链,科学采用双链结构,并已在美国获得先行专利
2、全球首家在工程上实现将水果链整合到PoW,发布自己的FPOW机制的公链
3、原创性的推出TrueHash,实现不依赖手动调整,从而根本上抗ASIC的挖矿算法
4、原创性实现安全的混合共识PBFT委员会的随机选举机制
5、在尚未实现Sharding技术情况下,在内测阶段的每秒钟交易速度TPS均值达到1200左右,峰值达到1900左右
TrueScan浏览器的URL地址是: www.truescan.net 。
truechain源码GitHub地址:https://github.com/truechain/truechain-engineering-code
下面的图是初链一句源码生成的的UML类图,可以大致的了解一下:
下面,我只针对一个部分,进行部分源码的分析 -- 。
BlockChain表示给定具有起源的数据库的规范链。BlockChain 的结构如下:
type BlockChain struct {
chainConfig *params.ChainConfig // Chain & network configuration
cacheConfig *CacheConfig // Cache configuration for pruning
db ethdb.Database // Low level persistent database to store final content in
triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
gcproc time.Duration // Accumulates canonical block processing for trie dumping
hc *HeaderChain
sc *snailchain.SnailBlockChain
rmLogsFeed event.Feed
chainFeed event.Feed
chainSideFeed event.Feed
chainHeadFeed event.Feed
logsFeed event.Feed
RewardNumberFeed event.Feed
scope event.SubscriptionScope
genesisBlock *types.Block
mu sync.RWMutex // global mutex for locking chain operations
chainmu sync.RWMutex // blockchain insertion lock
procmu sync.RWMutex // block processor lock
checkpoint int // checkpoint counts towards the new checkpoint
currentBlock atomic.Value // Current head of the block chain
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
currentReward atomic.Value // Current head of the currentReward
stateCache state.Database // State database to reuse between imports (contains state cache)
bodyCache *lru.Cache // Cache for the most recent block bodies
signCache *lru.Cache // Cache for the most recent block bodies
bodyRLPCache *lru.Cache // Cache for the most recent block bodies in RLP encoded format
blockCache *lru.Cache // Cache for the most recent entire blocks
futureBlocks *lru.Cache // future blocks are blocks added for later processing
rewardCache *lru.Cache
quit chan struct{} // blockchain quit channel
running int32 // running must be called atomically
// procInterrupt must be atomically called
procInterrupt int32 // interrupt signaler for block processing
wg sync.WaitGroup // chain processing wait group for shutting down
engine consensus.Engine
processor Processor // block processor interface
validator Validator // block and state validator interface
vmConfig vm.Config
badBlocks *lru.Cache // Bad block cache
}
NewBlockChain使用信息返回完全初始化的块链在数据库中可用。 它初始化默认的以太坊验证器和处理器。
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig,
chainConfig *params.ChainConfig, engine consensus.Engine,
vmConfig vm.Config) (*BlockChain, error) {
if cacheConfig == nil {
cacheConfig = &CacheConfig{
TrieNodeLimit: 256 * 1024 * 1024,
TrieTimeLimit: 5 * time.Minute,
}
}
bodyCache, _ := lru.New(bodyCacheLimit)
bodyRLPCache, _ := lru.New(bodyCacheLimit)
blockCache, _ := lru.New(blockCacheLimit)
futureBlocks, _ := lru.New(maxFutureBlocks)
badBlocks, _ := lru.New(badBlockLimit)
signCache, _ := lru.New(bodyCacheLimit)
rewardCache, _ := lru.New(bodyCacheLimit)
bc := &BlockChain{
chainConfig: chainConfig,
cacheConfig: cacheConfig,
db: db,
triegc: prque.New(),
stateCache: state.NewDatabase(db),
quit: make(chan struct{}),
bodyCache: bodyCache,
signCache: signCache,
bodyRLPCache: bodyRLPCache,
blockCache: blockCache,
futureBlocks: futureBlocks,
rewardCache: rewardCache,
engine: engine,
vmConfig: vmConfig,
badBlocks: badBlocks,
}
bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine))
var err error
bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.getProcInterrupt)
if err != nil {
return nil, err
}
bc.genesisBlock = bc.GetBlockByNumber(0)
if bc.genesisBlock == nil {
return nil, ErrNoGenesis
}
if err := bc.loadLastState(); err != nil {
return nil, err
}
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
//for hash := range BadHashes {
// if header := bc.GetHeaderByHash(hash); header != nil {
//
// // get the canonical block corresponding to the offending header's number
// headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64())
//
// // make sure the headerByNumber (if present) is in our current canonical chain
// if headerByNumber != nil && headerByNumber.Hash() == header.Hash() {
// log.Error("Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash)
// bc.SetHead(header.Number.Uint64() - 1)
// log.Error("Chain rewind was successful, resuming normal operation")
// }
// }
//}
// Take ownership of this particular state
go bc.update()
return bc, nil
}
loadLastState从数据库加载最后一个已知的链状态。 这种方法假设链管理器互斥锁被保留。
func (bc *BlockChain) loadLastState() error {
// Restore the last known head block
head := rawdb.ReadHeadBlockHash(bc.db)
if head == (common.Hash{}) {
// Corrupt or empty database, init from scratch
log.Warn("Empty database, resetting chain")
return bc.Reset()
}
// Make sure the entire head block is available
currentBlock := bc.GetBlockByHash(head)
if currentBlock == nil {
// Corrupt or empty database, init from scratch
log.Warn("Head block missing, resetting chain", "hash", head)
return bc.Reset()
}
// Make sure the state associated with the block is available
if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil {
// Dangling block without a state associated, init from scratch
log.Warn("Head state missing, repairing chain", "number", currentBlock.Number(), "hash", currentBlock.Hash())
if err := bc.repair(¤tBlock); err != nil {
return err
}
}
// Everything seems to be fine, set as the head block
bc.currentBlock.Store(currentBlock)
// Restore the last known head header
currentHeader := currentBlock.Header()
if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) {
if header := bc.GetHeaderByHash(head); header != nil {
currentHeader = header
}
}
bc.hc.SetCurrentHeader(currentHeader)
// Restore the last known head fast block
bc.currentFastBlock.Store(currentBlock)
if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) {
if block := bc.GetBlockByHash(head); block != nil {
bc.currentFastBlock.Store(block)
}
}
// Restore the last known currentReward
rewardHead := rawdb.ReadHeadRewardNumber(bc.db)
if rewardHead != 0 {
reward := rawdb.ReadBlockReward(bc.db, rewardHead)
//reward := bc.GetFastHeightBySnailHeight(rewardHead)
bc.currentReward.Store(reward)
}
// Issue a status log for the user
currentFastBlock := bc.CurrentFastBlock()
//headerTd := bc.GetTd(currentHeader.Hash(), currentHeader..UintNumber64())
//blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
//fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64())
//log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd)
//log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd)
//log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd)
log.Info("Loaded most recent local Fastheader", "number", currentHeader.Number, "hash", currentHeader.Hash())
log.Info("Loaded most recent local full Fastblock", "number", currentBlock.Number(), "hash", currentBlock.Hash())
log.Info("Loaded most recent local fast Fastblock", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash())
return nil
}
SetHead将本地链回卷到新的头部。 在标题的情况下,一切将删除新头部以上的新头部。 在块的情况下但是,如果缺少块体,则可以进一步重绕头部(非存档快速同步后的节点)。
func (bc *BlockChain) SetHead(head uint64) error {
log.Warn("Rewinding blockchain", "target", head)
bc.mu.Lock()
defer bc.mu.Unlock()
// Rewind the header chain, deleting all block bodies until then
delFn := func(db rawdb.DatabaseDeleter, hash common.Hash, num uint64) {
rawdb.DeleteBody(db, hash, num)
}
bc.hc.SetHead(head, delFn)
currentHeader := bc.hc.CurrentHeader()
// Clear out any stale content from the caches
bc.bodyCache.Purge()
bc.bodyRLPCache.Purge()
bc.blockCache.Purge()
bc.futureBlocks.Purge()
// Rewind the block chain, ensuring we don't end up with a stateless head block
if currentBlock := bc.CurrentBlock(); currentBlock != nil && currentHeader.Number.Uint64() < currentBlock.NumberU64() {
bc.currentBlock.Store(bc.GetBlock(currentHeader.Hash(), currentHeader.Number.Uint64()))
}
if currentBlock := bc.CurrentBlock(); currentBlock != nil {
if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil {
// Rewound state missing, rolled back to before pivot, reset to genesis
bc.currentBlock.Store(bc.genesisBlock)
}
}
// If either blocks reached nil, reset to the genesis state
if currentBlock := bc.CurrentBlock(); currentBlock == nil {
bc.currentBlock.Store(bc.genesisBlock)
}
// Restore the last known currentReward
currentReward := bc.GetLastRow()
if currentReward != nil {
bc.currentReward.Store(currentReward)
}
currentBlock := bc.CurrentBlock()
rawdb.WriteHeadBlockHash(bc.db, currentBlock.Hash())
return bc.loadLastState()
}
FastSyncCommitHead将当前头块设置为哈希定义的头块:
func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {
// Make sure that both the block as well at its state trie exists
block := bc.GetBlockByHash(hash)
if block == nil {
return fmt.Errorf("non existent block [%x…]", hash[:4])
}
if _, err := trie.NewSecure(block.Root(), bc.stateCache.TrieDB(), 0); err != nil {
return err
}
// If all checks out, manually set the head block
bc.mu.Lock()
bc.currentBlock.Store(block)
bc.mu.Unlock()
log.Info("Committed new head block", "number", block.Number(), "hash", hash)
return nil
}
GasLimit返回当前HEAD块的gas极限:
func (bc *BlockChain) GasLimit() uint64 {
return bc.CurrentBlock().GasLimit()
}
CurrentBlock检索规范链的当前头块。从区块链的内部缓存中检索块。
func (bc *BlockChain) CurrentBlock() *types.Block {
return bc.currentBlock.Load().(*types.Block)
}
InsertHeaderChain尝试将给定的标题链插入到本地链,可能创建一个reorg。 如果返回错误,它将返回错误失败标头的索引号以及描述错误的错误。验证参数可用于微调nonce验证应该做或不做。 可选检查背后的原因是因为一些标头检索机制已经需要验证nonce,以及因为可以稀疏地验证nonce,而不需要检查每个。
func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) {
start := time.Now()
if i, err := bc.hc.ValidateHeaderChain(chain, checkFreq); err != nil {
return i, err
}
// Make sure only one thread manipulates the chain at once
bc.chainmu.Lock()
defer bc.chainmu.Unlock()
bc.wg.Add(1)
defer bc.wg.Done()
whFunc := func(header *types.Header) error {
bc.mu.Lock()
defer bc.mu.Unlock()
_, err := bc.hc.WriteHeader(header)
return err
}
return bc.hc.InsertHeaderChain(chain, whFunc, start)
}
writeHeader将标头写入本地链,因为它的父节点是已经知道 如果新插入的标题的总难度变为大于当前已知的TD,规范链被重新路由。两种情况:纯标题操作模式(轻客户端)或正确分隔的头/块阶段(非归档客户端)。
func (bc *BlockChain) writeHeader(header *types.Header) error {
bc.wg.Add(1)
defer bc.wg.Done()
bc.mu.Lock()
defer bc.mu.Unlock()
_, err := bc.hc.WriteHeader(header)
return err
}