初链主网Beta版上线的技术解读----部分代码解读

从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(&currentBlock); 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
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值