// GetUnclesInChain retrieves all the uncles from a given block backwards until // a specific distance is reached. func (self *BlockChain) GetUnclesInChain(block *types.Block, length int) []*types.Header { uncles := []*types.Header{} for i := 0; block != nil && i < length; i++ { uncles = append(uncles, block.Uncles()...) block = self.GetBlock(block.ParentHash()) } return uncles }
// WriteBlock serializes a block into the database, header and body separately. func WriteBlock(db ethdb.Database, block *types.Block) error { // Store the body first to retain database consistency if err := WriteBody(db, block.Hash(), &types.Body{block.Transactions(), block.Uncles()}); err != nil { return err } // Store the header too, signaling full block ownership if err := WriteHeader(db, block.Header()); err != nil { return err } return nil }
// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { fields := map[string]interface{}{ "number": rpc.NewHexNumber(b.Number()), "hash": b.Hash(), "parentHash": b.ParentHash(), "nonce": b.Header().Nonce, "sha3Uncles": b.UncleHash(), "logsBloom": b.Bloom(), "stateRoot": b.Root(), "miner": b.Coinbase(), "difficulty": rpc.NewHexNumber(b.Difficulty()), "totalDifficulty": rpc.NewHexNumber(s.bc.GetTd(b.Hash())), "extraData": fmt.Sprintf("0x%x", b.Extra()), "size": rpc.NewHexNumber(b.Size().Int64()), "gasLimit": rpc.NewHexNumber(b.GasLimit()), "gasUsed": rpc.NewHexNumber(b.GasUsed()), "timestamp": rpc.NewHexNumber(b.Time()), "transactionsRoot": b.TxHash(), "receiptRoot": b.ReceiptHash(), } if inclTx { formatTx := func(tx *types.Transaction) (interface{}, error) { return tx.Hash(), nil } if fullTx { formatTx = func(tx *types.Transaction) (interface{}, error) { return newRPCTransaction(b, tx.Hash()) } } txs := b.Transactions() transactions := make([]interface{}, len(txs)) var err error for i, tx := range b.Transactions() { if transactions[i], err = formatTx(tx); err != nil { return nil, err } } fields["transactions"] = transactions } uncles := b.Uncles() uncleHashes := make([]common.Hash, len(uncles)) for i, uncle := range uncles { uncleHashes[i] = uncle.Hash() } fields["uncles"] = uncleHashes return fields, nil }
// VerifyUncles verifies the given block's uncles and applies the Ethereum // consensus rules to the various block headers included; it will return an // error if any of the included uncle headers were invalid. It returns an error // if the validation failed. func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error { // validate that there at most 2 uncles included in this block if len(block.Uncles()) > 2 { return ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles())) } uncles := set.New() ancestors := make(map[common.Hash]*types.Block) for _, ancestor := range v.bc.GetBlocksFromHash(block.ParentHash(), 7) { ancestors[ancestor.Hash()] = ancestor // Include ancestors uncles in the uncle set. Uncles must be unique. for _, uncle := range ancestor.Uncles() { uncles.Add(uncle.Hash()) } } ancestors[block.Hash()] = block uncles.Add(block.Hash()) for i, uncle := range block.Uncles() { hash := uncle.Hash() if uncles.Has(hash) { // Error not unique return UncleError("uncle[%d](%x) not unique", i, hash[:4]) } uncles.Add(hash) if ancestors[hash] != nil { branch := fmt.Sprintf(" O - %x\n |\n", block.Hash()) for h := range ancestors { branch += fmt.Sprintf(" O - %x\n |\n", h) } glog.Infoln(branch) return UncleError("uncle[%d](%x) is ancestor", i, hash[:4]) } if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == parent.Hash() { return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4]) } if err := ValidateHeader(v.Pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil { return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err)) } } return nil }
// 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 // seperately so we can process them in paralel. // // 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.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 }
// 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) (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()) ) for i, tx := range block.Transactions() { statedb.StartRecord(tx.Hash(), block.Hash(), i) receipt, logs, _, err := ApplyTransaction(p.bc, gp, statedb, header, tx, totalUsedGas) 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 }