Ethereum determines the longest chain based on the total difficulty, which is embedded in the block header. Ties are broken randomly.
Go https://github.com/ethereum/go-ethereum/blob/525116dbff916825463931361f75e75e955c12e2/core/blockchain.go#L863 to see more information.
WriteBlock()
writes the block to the chain.
func (self *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err error) {
-
wg
issync.WaitGroup
in BlockChain struct which is chain processing wait group for shutting down. -
Reserve termination of WaitGroup.
self.wg.Add(1)
defer self.wg.Done()
-
Calculate the total difficulty of the block.
GetTd
retrieves a block's total difficulty in the canonical chain from the database by hash and number, caching it if found. -
Stop if error occurs.
ptd := self.GetTd(block.ParentHash(), block.NumberU64()-1)
if ptd == nil {
return NonStatTy, ParentError(block.ParentHash())
}
-
Make sure no inconsistent state is leaked during insertion.
mu
issync.RWMutex
in BlockChain struct which is global mutex for locking chain operations. -
Reserve unlocking mutex.
self.mu.Lock()
defer self.mu.Unlock()
localTd := self.GetTd(self.currentBlock.Hash(), self.currentBlock.NumberU64())
externTd := new(big.Int).Add(block.Difficulty(), ptd)
if err := self.hc.WriteTd(block.Hash(), block.NumberU64(), externTd); err != nil {
log.Crit("Failed to write block total difficulty", "err", err)
}
if err := WriteBlock(self.chainDb, block); err != nil {
log.Crit("Failed to write block contents", "err", err)
}
-
If the total difficulty is higher than our known, add it to the canonical chain. Second clause in the if statement reduces the vulnerability to selfish mining. A de facto statement is
externTd.Cmp(localTd) >= 0
. -
Ties are broken randomly by
mrand.Float64() < 0.5
.
if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) {
- Reorganise the chain if the parent is not the head block.
if block.ParentHash() != self.currentBlock.Hash() {
if err := self.reorg(self.currentBlock, block); err != nil {
return NonStatTy, err
}
}
- Insert the block as the new head of the chain.
self.insert(block)
status = CanonStatTy
} else {
status = SideStatTy
}
self.futureBlocks.Remove(block.Hash())
return
}
CalcDifficulty()
is the difficulty adjustment algorithm. It returns the difficulty by given the parent block's time and difficulty that a new block should have when created at time.
Difficulty is computed based on parent difficulty and timestamp, block timestamp, and block number, without reference to uncles. Also Total difficulty Td
is the simple sum of block difficulty values without explicitly counting uncles.
func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
} else {
return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff)
}
}
// BlockChain represents the canonical chain given a database with a genesis
// block. The Blockchain manages chain imports, reverts, chain reorganisations.
//
// Importing blocks in to the block chain happens according to the set of rules
// defined by the two stage Validator. Processing of blocks is done using the
// Processor which processes the included transaction. The validation of the state
// is done in the second part of the Validator. Failing results in aborting of
// the import.
//
// The BlockChain also helps in returning blocks from **any** chain included
// in the database as well as blocks that represents the canonical chain. It's
// important to note that GetBlock can return any block and does not need to be
// included in the canonical one where as GetBlockByNumber always represents the
// canonical chain.
type BlockChain struct {
config *params.ChainConfig // chain & network configuration
hc *HeaderChain
chainDb ethdb.Database
eventMux *event.TypeMux
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 *types.Block // Current head of the block chain
currentFastBlock *types.Block // Current head of the fast-sync chain (may be above the block chain!)
stateCache *state.StateDB // State database to reuse between imports (contains state cache)
bodyCache *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
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
pow pow.PoW
processor Processor // block processor interface
validator Validator // block and state validator interface
vmConfig vm.Config
badBlocks *lru.Cache // Bad block cache
}