Blockchain Key Elements

  • Db: Persist to the underlying data store, levelDB;
  • GenesisBlock: the original block
  • CurrentBlock: the currentBlock. Instead of storing all the blocks in the chain, the blockchain traces back through currentBlock to genesisBlock, thus forming a blockchain
  • BodyCache, bodyRLPCache, blockCache, futureBlocks: Cache structures in blockchains used to speed up the reading and building of blockchains;
  • Hc: Headerchain is an additional chain maintained by the blockchain. Since the storage space of Header and Block is very different, but the Hash value of Block is the Hash value of Header (RLP), Therefore, maintaining a Headerchain can be used to quickly extend the chain, download the blockchain after verification, or verify with the blockchain mutually;
  • Processor: an interface that executes blockchain transactions. When a new block is received, it executes all transactions in the block. On the one hand, it validates the block and on the other hand, it updates the world state.
  • Validator: indicates the interface for verifying data validity
  • FutureBlocks: blocks whose received block time is more than 15s but less than 30s of the current header block time can be used as blocks to be processed by the current node.

Function is introduced

// BadBlocks processes the list of the most recent bad blocks retrieved by the client from the network
func (bc *BlockChain) BadBlocks(a)[] *types.Block {}

// addBadBlock puts the bad block in the cache
func (bc *BlockChain) addBadBlock(block *types.Block) {}
Copy the code
// CurrentBlock retrieves the first block of the main chain from blockchian's internal cache
func (bc *BlockChain) CurrentBlock(a) *types.Block {}
 
CurrentHeader Retrieves the current block header of the specification chain. Retrieves the header from the internal cache of HeaderChain.
func (bc *BlockChain) CurrentHeader(a) *types.Header{}
 
// CurrentFastBlock retrieves the main chain's current fast-sync header block from blockchian's internal cache
func (bc *BlockChain) CurrentFastBlock(a) *types.Block {}
Copy the code
// Writes the activity chain or a subset of it to the given writer.
func (bc *BlockChain) Export(w io.Writer) error {}
func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {}
Copy the code
// FastSyncCommitHead Fast synchronization that sets the current header block to a hash specific block.
func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {}
Copy the code
// GasLimit returns the gas limit for the current header block
func (bc *BlockChain) GasLimit(a) uint64 {}
Copy the code
// Genesis fetch Genesis block
func (bc *BlockChain) Genesis(a) *types.Block {}
Copy the code
And I hash a transactions and uncles (RLP) data out of the database or cache
func (bc *BlockChain) GetBody(hash common.Hash) *types.Body {}
func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue {}
Copy the code
// GetBlock retrieves the block using the hash and number
func (bc *BlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {}
// GetBlockByHash Retrieves the block using the hash
func (bc *BlockChain) GetBlockByHash(hash common.Hash) *types.Block {}
// GetBlockByNumber Fetches the block by number
func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block {}
Copy the code
// Get the header for the given hash and number blocks
func (bc *BlockChain) GetHeader(hash common.Hash, number uint64) *types.Header{}
 
// Get the block header for the given hash
func (bc *BlockChain) GetHeaderByHash(hash common.Hash) *types.Header{}
 
// Get the block header for the given number
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header{}
Copy the code
HasBlock verifies that the block corresponding to the hash exists fully in the database
func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool {}
 
// Check whether the block header for the given hash and number has a database
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool{}
 
HasState verifies that the state trie is fully present in the database
func (bc *BlockChain) HasState(hash common.Hash) bool {}
 
HasBlockAndState verifies that the block and state trie corresponding to the hash are fully present in the database
func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool {}
Copy the code
// The total difficulty of getting the blocks of the given hash
func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int{}
Copy the code
// Get all hashes from the given hash block to the Genesis block
func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash{}
 
// GetReceiptsByHash retrieves receipts for all transactions in a specific block
func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {}
 
// GetBlocksFromHash takes the block of a specific hash and its n-1 parent block
func (bc *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) {}
 
// GetUnclesInChain retrieves all tertiary blocks from a given block to a given distance back to the block
func (bc *BlockChain) GetUnclesInChain(block *types.Block, length int)[] *types.Header {}
Copy the code
// insert inserts the new header block into the current block chain. This method assumes that the block is indeed the real head.
It also resets the header header and the header fast sync block to the same block if they are older or if they are on different side chains.
func (bc *BlockChain) insert(block *types.Block) {}
 
// InsertChain attempts to insert a given batch of blocks into the specification chain, otherwise, a fork is created. If an error is returned, it returns the index number of the failed block and an error describing the error.
// After the insertion is complete, all accumulated events will be fired.
func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error){}
 
// insertChain will perform the actual chain insertion and event aggregation.
// The only reason this method exists as a separate method is to use delayed statements to make locking clearer.
func (bc *BlockChain) insertChain(chain types.Blocks) (intAnd []interface{}, []*types.Log, error){}
 
// InsertHeaderChain attempts to insert the given headerchain into the local chain, possibly creating a recombination
func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error){}
 
// InsertReceiptChain uses transaction and receipt data to complete the existing Headerchain
func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {}
Copy the code
//loadLastState loads the last known chain state from the database.
func (bc *BlockChain) loadLastState(a) error {}
Copy the code
// Processor Returns the current Processor.
func (bc *BlockChain) Processor(a) Processor {}
Copy the code
// Reset clears the entire blockchain and restores it to genesis State.
func (bc *BlockChain) Reset(a) error {}
 
// ResetWithGenesisBlock clears the entire blockchain, reshaping it with a specific Genesis state, referenced by Reset
func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {}
 
// Repair Attempts to repair the current blockchain by rolling back the current block until a block with an associated state is found.
// Used to fix incomplete database writes caused by crashes/power outages or simple non-commit attempts.
// This method only rolls back the current block. The current header and current fast block remain unchanged.
func (bc *BlockChain) repair(head **types.Block) error {}
 
// Reorgs requires two blocks, an old chain, and a new chain, and will rebuild the blocks and insert them into the new specification chain, accumulating potential missing transactions and publishing events about them
func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error{}
 
Rollback aims to remove indeterminate valid chain fragments from the database
func (bc *BlockChain) Rollback(chain []common.Hash) {}
Copy the code

// SetReceiptsData calculates all non-consensus fields of the receipt
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) error {}
 
// SetHead rolls back the local chain to the specified header.
// This can be used to re-select the main chain when dealing with forks. For headers, everything above the new Header is deleted and the new Header is set.
// However, if the block is lost, further fallbacks will occur (non-archive nodes after fast synchronization).
func (bc *BlockChain) SetHead(head uint64) error {}
 
// SetProcessor Sets the processor required for state modification
func (bc *BlockChain) SetProcessor(processor Processor) {}
 
// SetValidator Sets the validator for future blocks
func (bc *BlockChain) SetValidator(validator Validator) {}
 
// State returns a modifiable State based on the current header block
func (bc *BlockChain) State(a) (*state.StateDB, error) {}
 
// StateAt returns a new mutable state based on a specific point in time
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {}
 
// Stop Stops the blockchain service. If there is a process being imported, it cancels it with procInterrupt.
// it will abort them using the procInterrupt.
func (bc *BlockChain) Stop(a) {}
 
// The TrieNode retrieves the data associated with the Hash of the Trie node from the memory cache or storage.
func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) {}
 
Validator Returns the current Validator.
func (bc *BlockChain) Validator(a) Validator {}
 
Copy the code
// WriteBlockWithoutState writes only blocks and their metadata to the database, but does not write any state. This is used to build competing forks until the total difficulty exceeds the specification.
func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (err error){}
 
// WriteBlockWithState writes the block and all associated states to the database.
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) {}
 
// writeHeader writes the header to the local chain because its parent is known. If the total difficulty of the newly inserted header becomes greater than the currently known TD, the specification chain is rerrouted
func (bc *BlockChain) writeHeader(header *types.Header) error{}
 
// Handle future blockchains
func (bc *BlockChain) update(a) {}
Copy the code

Blockchain initialization

Main steps:

① create a new headerChain structure

bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.getProcInterrupt)
Copy the code
  1. Get the genesisHeader based on number (0)
  2. Read HeadBlock from RAWDB and store it in currentHeader

② : Obtain genesisBlock

bc.genesisBlock = bc.GetBlockByNumber(0)
Copy the code

If the chain is not empty, initialize the chain with the old chain data

if bc.empty() {
		rawdb.InitDatabaseFromFreezer(bc.db)
	}
Copy the code

④ Load the latest status data

iferr := bc.loadLastState(); err ! =nil {
		return nil, err
	}
Copy the code

⑤ : Check the current state of the block hash and make sure there are no bad blocks in the chain

for hash := range BadHashes {
		ifheader := bc.GetHeaderByHash(hash); header ! =nil {
			headerByNumber := bc.GetHeaderByNumber(header.Number.Uint64())
			ifheaderByNumber ! =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")}}}Copy the code

⑥ : Future blocks are processed regularly

go bc.update()
	->procFutureBlocks
		->InsertChain
Copy the code

In general, the following things have been done:

  1. Configure cacheConfig to create various LRU caches
  2. Initialize triegc
  3. Initialize stateDb: state.newDatabase (db)
  4. Initializing blocks and state validation: NewBlockValidator()
  5. Initialize the state processor: NewStateProcessor()
  6. Initializing the block header chain: NewHeaderChain()
  7. Find the creation block: bc.genesisBlock = bc.getBlockByNumber (0)
  8. Load the latest state data: bc.loadLastState()
  9. Check the current state of the block hash and make sure there are no bad blocks in the chain
  10. Go bc.update() periodically processes future blocks

Load the blockchain state

① : Restores headblock from the database. If the headblock is empty, reset chain is triggered

head := rawdb.ReadHeadBlockHash(bc.db)
	if head == (common.Hash{}) {
		log.Warn("Empty database, resetting chain")
		return bc.Reset()
	}
Copy the code

② : Ensure that the whole head block is available. If the head block is empty, reset chain is triggered

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()
	}
Copy the code

Open the state trie of the latest block from stateDb. If it fails to open, call bC.repair (&currentBlock) to repair it. The fix is to start with the currentBlock and work your way up until you find a good block and assign it to currentBlock.

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())
		iferr := bc.repair(&currentBlock); err ! =nil {
			return err
		}
		rawdb.WriteHeadBlockHash(bc.db, currentBlock.Hash())
	}
Copy the code

④ : Stores the current headblock and sets the current headHeader and header fast block

bc.currentBlock.Store(currentBlock)
....
bc.hc.SetCurrentHeader(currentHeader)
...
bc.currentFastBlock.Store(currentBlock)
Copy the code

Insert data into the blockchain

① : If the chain is breaking, return directly

② : Enables parallel signature recovery

③ : verifies the header

abort, results := bc.engine.VerifyHeaders(bc, headers, seals)
Copy the code

④ : cyclic check body

block, err := it.next()
	-> ValidateBody
		-> VerifyUncles
Copy the code

Including the following errors:

  • Block known
  • Uncle too much
  • Repeat the uncle
  • Uncle is the ancestral block
  • Uncle hashes don’t match
  • Transaction hashes do not match
  • Unknown ancestors
  • The state of the ancestor block could not be obtained

If a block exists and is a known block, the known block is written.

If the state of the ancestor block is not available, insert it as a side chain:

bc.insertSideChain(block, it)
Copy the code

If it is a future block or unknown ancestor, add a future block:

bc.addFutureBlock(block);
Copy the code

If it is any other error, break it and report the bad block.

bc.futureBlocks.Remove(block.Hash())
...
bc.reportBlock(block, nil, err)
Copy the code

⑤ : There is no verification error

If it is a bad block, report it. If it is an unknown block, the unknown block is written; Based on the given trie, create state;

Execute transactions in blocks:

receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
Copy the code

Use the default Validator state:

bc.validator.ValidateState(block, statedb, receipts, usedGas);
Copy the code

Write the block to the blockchain and get the state:

status, err := bc.writeBlockWithState(block, receipts, logs, statedb, false)
Copy the code

⑥ : Verifies the state of the written block

  • CanonStatTy: successfully inserted a new block
  • SideStatTy: a new fork block was inserted successfully
  • Default: Insert unknown blocks

If there are any future blocks, add them to the cache for future blocks

bc.addFutureBlock(block)
Copy the code

So far insertChain has been roughly introduced.


Writes block and association state to the database

Function: WriteBlockWithState

① : Calculate the total TD of the parent block

ptd := bc.GetTd(block.ParentHash(), block.NumberU64()- 1)
Copy the code

② : Add the TD of the block to be inserted, and store the latest total TD in the database.

bc.hc.WriteTd(block.Hash(), block.NumberU64(), externTd)
Copy the code

Serialize the header and body of the block to the database, respectively

rawdb.WriteBlock(bc.db, block)
	->WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
	->WriteHeader(db, block.Header())
Copy the code

④ : Write the status to the underlying memory Trie database

state.Commit(bc.chainConfig.IsEIP158(block.Number()))
Copy the code

⑤ : Store all transaction data of a block

rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts)
Copy the code

⑥ : Inject the new head block into the current chain

if status == CanonStatTy {
		bc.insert(block)
	}
Copy the code
  • Stores hashes assigned to canonical blocks
  • Stores the hash of the header block
  • Store the latest fast
  • Update currentFastBlock

It can be seen from the above that insertChain finally calls the insert method of writeBlockWithState to complete the final insertion action.


thinking

  1. Why import known blocks? writeKnownBlock

Reference:

Github.com/mindcarver/… (Excellent blockchain learning camp)