// reportBlock reports the given block and error using the canonical block // reporting tool. Reporting the block to the service is handled in a separate // goroutine. func reportBlock(block *types.Block, err error) { if glog.V(logger.Error) { glog.Errorf("Bad block #%v (%s)\n", block.Number(), block.Hash().Hex()) glog.Errorf(" %v", err) } go ReportBlock(block, err) }
func (bc *ChainManager) insert(block *types.Block) { key := append(blockNumPre, block.Number().Bytes()...) bc.blockDb.Put(key, block.Hash().Bytes()) bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes()) bc.currentBlock = block bc.lastBlockHash = block.Hash() }
// WriteCanonNumber writes the canonical hash for the given block func WriteCanonNumber(db common.Database, block *types.Block) error { key := append(blockNumPre, block.Number().Bytes()...) err := db.Put(key, block.Hash().Bytes()) if err != nil { return err } return nil }
// WriteHead force writes the current head func WriteHead(db common.Database, block *types.Block) error { key := append(blockNumPre, block.Number().Bytes()...) err := db.Put(key, block.Hash().Bytes()) if err != nil { return err } err = db.Put([]byte("LastBlock"), block.Hash().Bytes()) if err != nil { return err } return nil }
func makeHeader(parent *types.Block, state *state.StateDB) *types.Header { time := parent.Time() + 10 // block time is fixed at 10 seconds return &types.Header{ Root: state.Root(), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), Difficulty: CalcDifficulty(int64(time), int64(parent.Time()), parent.Difficulty()), GasLimit: CalcGasLimit(parent), GasUsed: new(big.Int), Number: new(big.Int).Add(parent.Number(), common.Big1), Time: uint64(time), } }
func (bc *ChainManager) write(block *types.Block) { tstart := time.Now() enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block)) key := append(blockHashPre, block.Hash().Bytes()...) err := bc.blockDb.Put(key, enc) if err != nil { glog.Fatal("db write fail:", err) } if glog.V(logger.Debug) { glog.Infof("wrote block #%v %s. Took %v\n", block.Number(), common.PP(block.Hash().Bytes()), time.Since(tstart)) } }
// insert injects a block into the current chain block chain. Note, this function // assumes that the `mu` mutex is held! func (bc *ChainManager) insert(block *types.Block) { key := append(blockNumPre, block.Number().Bytes()...) err := bc.blockDb.Put(key, block.Hash().Bytes()) if err != nil { glog.Fatal("db write fail:", err) } err = bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes()) if err != nil { glog.Fatal("db write fail:", err) } bc.currentBlock = block bc.lastBlockHash = block.Hash() }
// diff takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them // to be part of the new canonical chain. func (self *ChainManager) diff(oldBlock, newBlock *types.Block) (types.Blocks, error) { var ( newChain types.Blocks commonBlock *types.Block oldStart = oldBlock newStart = newBlock ) // first reduce whoever is higher bound if oldBlock.NumberU64() > newBlock.NumberU64() { // reduce old chain for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) { } } else { // reduce new chain and append new chain blocks for inserting later on for newBlock = newBlock; newBlock != nil && newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = self.GetBlock(newBlock.ParentHash()) { newChain = append(newChain, newBlock) } } if oldBlock == nil { return nil, fmt.Errorf("Invalid old chain") } if newBlock == nil { return nil, fmt.Errorf("Invalid new chain") } numSplit := newBlock.Number() for { if oldBlock.Hash() == newBlock.Hash() { commonBlock = oldBlock break } newChain = append(newChain, newBlock) oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash()) if oldBlock == nil { return nil, fmt.Errorf("Invalid old chain") } if newBlock == nil { return nil, fmt.Errorf("Invalid new chain") } } if glog.V(logger.Debug) { commonHash := commonBlock.Hash() glog.Infof("Chain split detected @ %x. Reorganising chain from #%v %x to %x", commonHash[:4], numSplit, oldStart.Hash().Bytes()[:4], newStart.Hash().Bytes()[:4]) } return newChain, nil }
// Process block will attempt to process the given block's transactions and applies them // on top of the block's parent state (given it exists) and will return wether it was // successful or not. func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, receipts types.Receipts, err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() if sm.bc.HasBlock(block.Hash()) { return nil, nil, &KnownBlockError{block.Number(), block.Hash()} } if !sm.bc.HasBlock(block.ParentHash()) { return nil, nil, ParentError(block.ParentHash()) } parent := sm.bc.GetBlock(block.ParentHash()) return sm.processWithParent(block, parent) }
// See YP section 4.3.4. "Block Header Validity" // Validates a block. Returns an error if the block is invalid. func ValidateHeader(pow pow.PoW, block *types.Header, parent *types.Block, checkPow, uncle bool) error { if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 { return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) } if uncle { if block.Time.Cmp(common.MaxBig) == 1 { return BlockTSTooBigErr } } else { if block.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 { return BlockFutureErr } } if block.Time.Cmp(parent.Time()) != 1 { return BlockEqualTSErr } expd := CalcDifficulty(block.Time.Uint64(), parent.Time().Uint64(), parent.Number(), parent.Difficulty()) if expd.Cmp(block.Difficulty) != 0 { return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) } var a, b *big.Int a = parent.GasLimit() a = a.Sub(a, block.GasLimit) a.Abs(a) b = parent.GasLimit() b = b.Div(b, params.GasLimitBoundDivisor) if !(a.Cmp(b) < 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) { return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b) } num := parent.Number() num.Sub(block.Number, num) if num.Cmp(big.NewInt(1)) != 0 { return BlockNumberErr } if checkPow { // Verify the nonce of the block. Return an error if it's not valid if !pow.Verify(types.NewBlockWithHeader(block)) { return ValidationError("Block's nonce is invalid (= %x)", block.Nonce) } } return nil }
// Process block will attempt to process the given block's transactions and applies them // on top of the block's parent state (given it exists) and will return wether it was // successful or not. func (sm *BlockProcessor) Process(block *types.Block) (logs vm.Logs, receipts types.Receipts, err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() if sm.bc.HasBlock(block.Hash()) { if _, err := state.New(block.Root(), sm.chainDb); err == nil { return nil, nil, &KnownBlockError{block.Number(), block.Hash()} } } if parent := sm.bc.GetBlock(block.ParentHash()); parent != nil { if _, err := state.New(parent.Root(), sm.chainDb); err == nil { return sm.processWithParent(block, parent) } } return nil, nil, ParentError(block.ParentHash()) }
// WriteBlock writes a block to the database func WriteBlock(db common.Database, block *types.Block) error { tstart := time.Now() enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block)) key := append(blockHashPre, block.Hash().Bytes()...) err := db.Put(key, enc) if err != nil { glog.Fatal("db write fail:", err) return err } if glog.V(logger.Debug) { glog.Infof("wrote block #%v %s. Took %v\n", block.Number(), common.PP(block.Hash().Bytes()), time.Since(tstart)) } return nil }
func makeHeader(parent *types.Block, state *state.StateDB) *types.Header { var time *big.Int if parent.Time() == nil { time = big.NewInt(10) } else { time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds } return &types.Header{ Root: state.IntermediateRoot(), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), Difficulty: CalcDifficulty(time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()), GasLimit: CalcGasLimit(parent), GasUsed: new(big.Int), Number: new(big.Int).Add(parent.Number(), common.Big1), Time: time, } }
func AccumulateRewards(statedb *state.StateDB, block *types.Block) { reward := new(big.Int).Set(BlockReward) for _, uncle := range block.Uncles() { num := new(big.Int).Add(big.NewInt(8), uncle.Number) num.Sub(num, block.Number()) r := new(big.Int) r.Mul(BlockReward, num) r.Div(r, big.NewInt(8)) statedb.AddBalance(uncle.Coinbase, r) reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32))) } // Get the account associated with the coinbase statedb.AddBalance(block.Header().Coinbase, reward) }
func NewBlockRes(block *types.Block, td *big.Int, fullTx bool) *BlockRes { if block == nil { return nil } res := new(BlockRes) res.fullTx = fullTx res.BlockNumber = newHexNum(block.Number()) res.BlockHash = newHexData(block.Hash()) res.ParentHash = newHexData(block.ParentHash()) res.Nonce = newHexData(block.Nonce()) res.Sha3Uncles = newHexData(block.UncleHash()) res.LogsBloom = newHexData(block.Bloom()) res.TransactionRoot = newHexData(block.TxHash()) res.StateRoot = newHexData(block.Root()) res.ReceiptRoot = newHexData(block.ReceiptHash()) res.Miner = newHexData(block.Coinbase()) res.Difficulty = newHexNum(block.Difficulty()) res.TotalDifficulty = newHexNum(td) res.Size = newHexNum(block.Size().Int64()) res.ExtraData = newHexData(block.Extra()) res.GasLimit = newHexNum(block.GasLimit()) res.GasUsed = newHexNum(block.GasUsed()) res.UnixTimestamp = newHexNum(block.Time()) txs := block.Transactions() res.Transactions = make([]*TransactionRes, len(txs)) for i, tx := range txs { res.Transactions[i] = NewTransactionRes(tx) res.Transactions[i].BlockHash = res.BlockHash res.Transactions[i].BlockNumber = res.BlockNumber res.Transactions[i].TxIndex = newHexNum(i) } uncles := block.Uncles() res.Uncles = make([]*UncleRes, len(uncles)) for i, uncle := range uncles { res.Uncles[i] = NewUncleRes(uncle) } return res }
// diff takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them // to be part of the new canonical chain. func (self *ChainManager) diff(oldBlock, newBlock *types.Block) types.Blocks { glog.V(logger.Debug).Infof("Applying diff to %x & %x\n", oldBlock.Hash().Bytes()[:4], newBlock.Hash().Bytes()[:4]) var newChain types.Blocks // first find common number for newBlock = newBlock; newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = self.GetBlock(newBlock.ParentHash()) { newChain = append(newChain, newBlock) } glog.V(logger.Debug).Infoln("Found common number", newBlock.Number()) for { if oldBlock.Hash() == newBlock.Hash() { break } newChain = append(newChain, newBlock) oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash()) } return newChain }
// ValidateBlock validates the given block's header and uncles and verifies the // the block header's transaction and uncle roots. // // ValidateBlock does not validate the header's pow. The pow work validated // separately so we can process them in parallel. // // ValidateBlock also validates and makes sure that any previous state (or present) // state that might or might not be present is checked to make sure that fast // sync has done it's job proper. This prevents the block validator form accepting // false positives where a header is present but the state is not. func (v *BlockValidator) ValidateBlock(block *types.Block) error { if v.bc.HasBlock(block.Hash()) { if _, err := state.New(block.Root(), v.bc.chainDb); err == nil { return &KnownBlockError{block.Number(), block.Hash()} } } parent := v.bc.GetBlock(block.ParentHash()) if parent == nil { return ParentError(block.ParentHash()) } if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil { return ParentError(block.ParentHash()) } header := block.Header() // validate the block header if err := ValidateHeader(v.config, v.Pow, header, parent.Header(), false, false); err != nil { return err } // verify the uncles are correctly rewarded if err := v.VerifyUncles(block, parent); err != nil { return err } // Verify UncleHash before running other uncle validations unclesSha := types.CalcUncleHash(block.Uncles()) if unclesSha != header.UncleHash { return fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha) } // The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]])) // can be used by light clients to make sure they've received the correct Txs txSha := types.DeriveSha(block.Transactions()) if txSha != header.TxHash { return fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha) } return nil }
// reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them // to be part of the new canonical chain and accumulates potential missing transactions and post an // event about them func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { var ( newChain types.Blocks commonBlock *types.Block oldStart = oldBlock newStart = newBlock deletedTxs types.Transactions ) // first reduce whoever is higher bound if oldBlock.NumberU64() > newBlock.NumberU64() { // reduce old chain for oldBlock = oldBlock; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) { deletedTxs = append(deletedTxs, oldBlock.Transactions()...) } } else { // reduce new chain and append new chain blocks for inserting later on for newBlock = newBlock; newBlock != nil && newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = self.GetBlock(newBlock.ParentHash()) { newChain = append(newChain, newBlock) } } if oldBlock == nil { return fmt.Errorf("Invalid old chain") } if newBlock == nil { return fmt.Errorf("Invalid new chain") } numSplit := newBlock.Number() for { if oldBlock.Hash() == newBlock.Hash() { commonBlock = oldBlock break } newChain = append(newChain, newBlock) deletedTxs = append(deletedTxs, oldBlock.Transactions()...) oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash()) if oldBlock == nil { return fmt.Errorf("Invalid old chain") } if newBlock == nil { return fmt.Errorf("Invalid new chain") } } if glog.V(logger.Debug) { commonHash := commonBlock.Hash() glog.Infof("Chain split detected @ %x. Reorganising chain from #%v %x to %x", commonHash[:4], numSplit, oldStart.Hash().Bytes()[:4], newStart.Hash().Bytes()[:4]) } var addedTxs types.Transactions // insert blocks. Order does not matter. Last block will be written in ImportChain itself which creates the new head properly for _, block := range newChain { // insert the block in the canonical way, re-writing history self.insert(block) // write canonical receipts and transactions if err := PutTransactions(self.chainDb, block, block.Transactions()); err != nil { return err } receipts := GetBlockReceipts(self.chainDb, block.Hash()) // write receipts if err := PutReceipts(self.chainDb, receipts); err != nil { return err } // Write map map bloom filters if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil { return err } addedTxs = append(addedTxs, block.Transactions()...) } // calculate the difference between deleted and added transactions diff := types.TxDifference(deletedTxs, addedTxs) // When transactions get deleted from the database that means the // receipts that were created in the fork must also be deleted for _, tx := range diff { DeleteReceipt(self.chainDb, tx.Hash()) DeleteTransaction(self.chainDb, tx.Hash()) } // Must be posted in a goroutine because of the transaction pool trying // to acquire the chain manager lock go self.eventMux.Post(RemovedTransactionEvent{diff}) return nil }
// copyBlock makes a deep copy of a block suitable for local modifications. func copyBlock(block *types.Block) *types.Block { return createBlock(int(block.Number().Int64()), block.ParentHeaderHash, block.HeaderHash) }
// reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them // to be part of the new canonical chain and accumulates potential missing transactions and post an // event about them func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { var ( newChain types.Blocks oldChain types.Blocks commonBlock *types.Block oldStart = oldBlock newStart = newBlock deletedTxs types.Transactions deletedLogs vm.Logs deletedLogsByHash = make(map[common.Hash]vm.Logs) // collectLogs collects the logs that were generated during the // processing of the block that corresponds with the given hash. // These logs are later announced as deleted. collectLogs = func(h common.Hash) { // Coalesce logs receipts := GetBlockReceipts(self.chainDb, h) for _, receipt := range receipts { deletedLogs = append(deletedLogs, receipt.Logs...) deletedLogsByHash[h] = receipt.Logs } } ) // first reduce whoever is higher bound if oldBlock.NumberU64() > newBlock.NumberU64() { // reduce old chain for ; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = self.GetBlock(oldBlock.ParentHash()) { oldChain = append(oldChain, oldBlock) deletedTxs = append(deletedTxs, oldBlock.Transactions()...) collectLogs(oldBlock.Hash()) } } else { // reduce new chain and append new chain blocks for inserting later on for ; newBlock != nil && newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = self.GetBlock(newBlock.ParentHash()) { newChain = append(newChain, newBlock) } } if oldBlock == nil { return fmt.Errorf("Invalid old chain") } if newBlock == nil { return fmt.Errorf("Invalid new chain") } numSplit := newBlock.Number() for { if oldBlock.Hash() == newBlock.Hash() { commonBlock = oldBlock break } oldChain = append(oldChain, oldBlock) newChain = append(newChain, newBlock) deletedTxs = append(deletedTxs, oldBlock.Transactions()...) collectLogs(oldBlock.Hash()) oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash()) if oldBlock == nil { return fmt.Errorf("Invalid old chain") } if newBlock == nil { return fmt.Errorf("Invalid new chain") } } if glog.V(logger.Debug) { commonHash := commonBlock.Hash() glog.Infof("Chain split detected @ %x. Reorganising chain from #%v %x to %x", commonHash[:4], numSplit, oldStart.Hash().Bytes()[:4], newStart.Hash().Bytes()[:4]) } var addedTxs types.Transactions // insert blocks. Order does not matter. Last block will be written in ImportChain itself which creates the new head properly for _, block := range newChain { // insert the block in the canonical way, re-writing history self.insert(block) // write canonical receipts and transactions if err := WriteTransactions(self.chainDb, block); err != nil { return err } receipts := GetBlockReceipts(self.chainDb, block.Hash()) // write receipts if err := WriteReceipts(self.chainDb, receipts); err != nil { return err } // Write map map bloom filters if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil { return err } addedTxs = append(addedTxs, block.Transactions()...) } // calculate the difference between deleted and added transactions diff := types.TxDifference(deletedTxs, addedTxs) // When transactions get deleted from the database that means the // receipts that were created in the fork must also be deleted for _, tx := range diff { DeleteReceipt(self.chainDb, tx.Hash()) DeleteTransaction(self.chainDb, tx.Hash()) } // Must be posted in a goroutine because of the transaction pool trying // to acquire the chain manager lock if len(diff) > 0 { go self.eventMux.Post(RemovedTransactionEvent{diff}) } if len(deletedLogs) > 0 { go self.eventMux.Post(RemovedLogsEvent{deletedLogs}) } if len(oldChain) > 0 { go func() { for _, block := range oldChain { self.eventMux.Post(ChainSideEvent{Block: block, Logs: deletedLogsByHash[block.Hash()]}) } }() } return nil }
// Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. // // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) { var ( receipts types.Receipts totalUsedGas = big.NewInt(0) err error header = block.Header() allLogs vm.Logs gp = new(GasPool).AddGas(block.GasLimit()) ) // Mutate the the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { ApplyDAOHardFork(statedb) } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { statedb.StartRecord(tx.Hash(), block.Hash(), i) receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) if err != nil { return nil, nil, totalUsedGas, err } receipts = append(receipts, receipt) allLogs = append(allLogs, logs...) } AccumulateRewards(statedb, header, block.Uncles()) return receipts, allLogs, totalUsedGas, err }