parent
89156bd899
commit
bb776e9f95
@ -0,0 +1,139 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/ethereum/go-ethereum/consensus" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/params" |
||||
) |
||||
|
||||
// BlockValidator is responsible for validating block headers, uncles and
|
||||
// processed state.
|
||||
//
|
||||
// BlockValidator implements Validator.
|
||||
type BlockValidator struct { |
||||
config *params.ChainConfig // Chain configuration options
|
||||
bc *BlockChain // Canonical block chain
|
||||
engine consensus.Engine // Consensus engine used for validating
|
||||
} |
||||
|
||||
// NewBlockValidator returns a new block validator which is safe for re-use
|
||||
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator { |
||||
validator := &BlockValidator{ |
||||
config: config, |
||||
engine: engine, |
||||
bc: blockchain, |
||||
} |
||||
return validator |
||||
} |
||||
|
||||
// ValidateBody validates the given block's uncles and verifies the block
|
||||
// header's transaction and uncle roots. The headers are assumed to be already
|
||||
// validated at this point.
|
||||
func (v *BlockValidator) ValidateBody(block *types.Block) error { |
||||
// Check whether the block's known, and if not, that it's linkable
|
||||
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { |
||||
return ErrKnownBlock |
||||
} |
||||
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) { |
||||
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) { |
||||
return consensus.ErrUnknownAncestor |
||||
} |
||||
return consensus.ErrPrunedAncestor |
||||
} |
||||
// Header validity is known at this point, check the uncles and transactions
|
||||
header := block.Header() |
||||
if err := v.engine.VerifyUncles(v.bc, block); err != nil { |
||||
return err |
||||
} |
||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash { |
||||
return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash) |
||||
} |
||||
if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash { |
||||
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// ValidateState validates the various changes that happen after a state
|
||||
// transition, such as amount of used gas, the receipt roots and the state root
|
||||
// itself. ValidateState returns a database batch if the validation was a success
|
||||
// otherwise nil and an error is returned.
|
||||
func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { |
||||
header := block.Header() |
||||
if block.GasUsed() != usedGas { |
||||
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) |
||||
} |
||||
// Validate the received block's bloom with the one derived from the generated receipts.
|
||||
// For valid blocks this should always validate to true.
|
||||
rbloom := types.CreateBloom(receipts) |
||||
if rbloom != header.Bloom { |
||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) |
||||
} |
||||
// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
|
||||
receiptSha := types.DeriveSha(receipts) |
||||
if receiptSha != header.ReceiptHash { |
||||
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) |
||||
} |
||||
// Validate the state root against the received state root and throw
|
||||
// an error if they don't match.
|
||||
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { |
||||
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// CalcGasLimit computes the gas limit of the next block after parent. It aims
|
||||
// to keep the baseline gas above the provided floor, and increase it towards the
|
||||
// ceil if the blocks are full. If the ceil is exceeded, it will always decrease
|
||||
// the gas allowance.
|
||||
func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 { |
||||
// contrib = (parentGasUsed * 3 / 2) / 1024
|
||||
contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor |
||||
|
||||
// decay = parentGasLimit / 1024 -1
|
||||
decay := parent.GasLimit()/params.GasLimitBoundDivisor - 1 |
||||
|
||||
/* |
||||
strategy: gasLimit of block-to-mine is set based on parent's |
||||
gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we |
||||
increase it, otherwise lower it (or leave it unchanged if it's right |
||||
at that usage) the amount increased/decreased depends on how far away |
||||
from parentGasLimit * (2/3) parentGasUsed is. |
||||
*/ |
||||
limit := parent.GasLimit() - decay + contrib |
||||
if limit < params.MinGasLimit { |
||||
limit = params.MinGasLimit |
||||
} |
||||
// If we're outside our allowed gas range, we try to hone towards them
|
||||
if limit < gasFloor { |
||||
limit = parent.GasLimit() + decay |
||||
if limit > gasFloor { |
||||
limit = gasFloor |
||||
} |
||||
} else if limit > gasCeil { |
||||
limit = parent.GasLimit() - decay |
||||
if limit < gasCeil { |
||||
limit = gasCeil |
||||
} |
||||
} |
||||
return limit |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,97 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core |
||||
|
||||
import ( |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/consensus" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/core/vm" |
||||
) |
||||
|
||||
// ChainContext supports retrieving headers and consensus parameters from the
|
||||
// current blockchain to be used during transaction processing.
|
||||
type ChainContext interface { |
||||
// Engine retrieves the chain's consensus engine.
|
||||
Engine() consensus.Engine |
||||
|
||||
// GetHeader returns the hash corresponding to their hash.
|
||||
GetHeader(common.Hash, uint64) *types.Header |
||||
} |
||||
|
||||
// NewEVMContext creates a new context for use in the EVM.
|
||||
func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author *common.Address) vm.Context { |
||||
// If we don't have an explicit author (i.e. not mining), extract from the header
|
||||
var beneficiary common.Address |
||||
if author == nil { |
||||
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
|
||||
} else { |
||||
beneficiary = *author |
||||
} |
||||
return vm.Context{ |
||||
CanTransfer: CanTransfer, |
||||
Transfer: Transfer, |
||||
GetHash: GetHashFn(header, chain), |
||||
Origin: msg.From(), |
||||
Coinbase: beneficiary, |
||||
BlockNumber: new(big.Int).Set(header.Number), |
||||
Time: new(big.Int).Set(header.Time), |
||||
Difficulty: new(big.Int).Set(header.Difficulty), |
||||
GasLimit: header.GasLimit, |
||||
GasPrice: new(big.Int).Set(msg.GasPrice()), |
||||
} |
||||
} |
||||
|
||||
// GetHashFn returns a GetHashFunc which retrieves header hashes by number
|
||||
func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { |
||||
var cache map[uint64]common.Hash |
||||
|
||||
return func(n uint64) common.Hash { |
||||
// If there's no hash cache yet, make one
|
||||
if cache == nil { |
||||
cache = map[uint64]common.Hash{ |
||||
ref.Number.Uint64() - 1: ref.ParentHash, |
||||
} |
||||
} |
||||
// Try to fulfill the request from the cache
|
||||
if hash, ok := cache[n]; ok { |
||||
return hash |
||||
} |
||||
// Not cached, iterate the blocks and cache the hashes
|
||||
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) { |
||||
cache[header.Number.Uint64()-1] = header.ParentHash |
||||
if n == header.Number.Uint64()-1 { |
||||
return header.ParentHash |
||||
} |
||||
} |
||||
return common.Hash{} |
||||
} |
||||
} |
||||
|
||||
// CanTransfer checks whether there are enough funds in the address' account to make a transfer.
|
||||
// This does not take the necessary gas in to account to make the transfer valid.
|
||||
func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool { |
||||
return db.GetBalance(addr).Cmp(amount) >= 0 |
||||
} |
||||
|
||||
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
|
||||
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { |
||||
db.SubBalance(sender, amount) |
||||
db.AddBalance(recipient, amount) |
||||
} |
@ -0,0 +1,351 @@ |
||||
// Copyright 2014 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/hex" |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
"github.com/ethereum/go-ethereum/common/math" |
||||
"github.com/ethereum/go-ethereum/core/rawdb" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/ethdb" |
||||
"github.com/ethereum/go-ethereum/log" |
||||
"github.com/ethereum/go-ethereum/params" |
||||
) |
||||
|
||||
//go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
|
||||
//go:generate gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
|
||||
|
||||
var errGenesisNoConfig = errors.New("genesis has no chain configuration") |
||||
|
||||
// Genesis specifies the header fields, state of a genesis block. It also defines hard
|
||||
// fork switch-over blocks through the chain configuration.
|
||||
type Genesis struct { |
||||
Config *params.ChainConfig `json:"config"` |
||||
Nonce uint64 `json:"nonce"` |
||||
Timestamp uint64 `json:"timestamp"` |
||||
ExtraData []byte `json:"extraData"` |
||||
GasLimit uint64 `json:"gasLimit" gencodec:"required"` |
||||
Difficulty *big.Int `json:"difficulty" gencodec:"required"` |
||||
Mixhash common.Hash `json:"mixHash"` |
||||
Coinbase common.Address `json:"coinbase"` |
||||
Alloc GenesisAlloc `json:"alloc" gencodec:"required"` |
||||
|
||||
// These fields are used for consensus tests. Please don't use them
|
||||
// in actual genesis blocks.
|
||||
Number uint64 `json:"number"` |
||||
GasUsed uint64 `json:"gasUsed"` |
||||
ParentHash common.Hash `json:"parentHash"` |
||||
} |
||||
|
||||
// GenesisAlloc specifies the initial state that is part of the genesis block.
|
||||
type GenesisAlloc map[common.Address]GenesisAccount |
||||
|
||||
func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error { |
||||
m := make(map[common.UnprefixedAddress]GenesisAccount) |
||||
if err := json.Unmarshal(data, &m); err != nil { |
||||
return err |
||||
} |
||||
*ga = make(GenesisAlloc) |
||||
for addr, a := range m { |
||||
(*ga)[common.Address(addr)] = a |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GenesisAccount is an account in the state of the genesis block.
|
||||
type GenesisAccount struct { |
||||
Code []byte `json:"code,omitempty"` |
||||
Storage map[common.Hash]common.Hash `json:"storage,omitempty"` |
||||
Balance *big.Int `json:"balance" gencodec:"required"` |
||||
Nonce uint64 `json:"nonce,omitempty"` |
||||
PrivateKey []byte `json:"secretKey,omitempty"` // for tests
|
||||
} |
||||
|
||||
// field type overrides for gencodec
|
||||
type genesisSpecMarshaling struct { |
||||
Nonce math.HexOrDecimal64 |
||||
Timestamp math.HexOrDecimal64 |
||||
ExtraData hexutil.Bytes |
||||
GasLimit math.HexOrDecimal64 |
||||
GasUsed math.HexOrDecimal64 |
||||
Number math.HexOrDecimal64 |
||||
Difficulty *math.HexOrDecimal256 |
||||
Alloc map[common.UnprefixedAddress]GenesisAccount |
||||
} |
||||
|
||||
type genesisAccountMarshaling struct { |
||||
Code hexutil.Bytes |
||||
Balance *math.HexOrDecimal256 |
||||
Nonce math.HexOrDecimal64 |
||||
Storage map[storageJSON]storageJSON |
||||
PrivateKey hexutil.Bytes |
||||
} |
||||
|
||||
// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
|
||||
// unmarshaling from hex.
|
||||
type storageJSON common.Hash |
||||
|
||||
func (h *storageJSON) UnmarshalText(text []byte) error { |
||||
text = bytes.TrimPrefix(text, []byte("0x")) |
||||
if len(text) > 64 { |
||||
return fmt.Errorf("too many hex characters in storage key/value %q", text) |
||||
} |
||||
offset := len(h) - len(text)/2 // pad on the left
|
||||
if _, err := hex.Decode(h[offset:], text); err != nil { |
||||
fmt.Println(err) |
||||
return fmt.Errorf("invalid hex storage key/value %q", text) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (h storageJSON) MarshalText() ([]byte, error) { |
||||
return hexutil.Bytes(h[:]).MarshalText() |
||||
} |
||||
|
||||
// GenesisMismatchError is raised when trying to overwrite an existing
|
||||
// genesis block with an incompatible one.
|
||||
type GenesisMismatchError struct { |
||||
Stored, New common.Hash |
||||
} |
||||
|
||||
func (e *GenesisMismatchError) Error() string { |
||||
return fmt.Sprintf("database already contains an incompatible genesis block (have %x, new %x)", e.Stored[:8], e.New[:8]) |
||||
} |
||||
|
||||
// SetupGenesisBlock writes or updates the genesis block in db.
|
||||
// The block that will be used is:
|
||||
//
|
||||
// genesis == nil genesis != nil
|
||||
// +------------------------------------------
|
||||
// db has no genesis | main-net default | genesis
|
||||
// db has genesis | from DB | genesis (if compatible)
|
||||
//
|
||||
// The stored chain configuration will be updated if it is compatible (i.e. does not
|
||||
// specify a fork block below the local head block). In case of a conflict, the
|
||||
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
|
||||
//
|
||||
// The returned chain configuration is never nil.
|
||||
func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { |
||||
if genesis != nil && genesis.Config == nil { |
||||
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig |
||||
} |
||||
|
||||
// Just commit the new block if there is no stored genesis block.
|
||||
stored := rawdb.ReadCanonicalHash(db, 0) |
||||
if (stored == common.Hash{}) { |
||||
if genesis == nil { |
||||
log.Info("Writing default main-net genesis block") |
||||
genesis = DefaultGenesisBlock() |
||||
} else { |
||||
log.Info("Writing custom genesis block") |
||||
} |
||||
block, err := genesis.Commit(db) |
||||
return genesis.Config, block.Hash(), err |
||||
} |
||||
|
||||
// Check whether the genesis block is already written.
|
||||
if genesis != nil { |
||||
hash := genesis.ToBlock(nil).Hash() |
||||
if hash != stored { |
||||
return genesis.Config, hash, &GenesisMismatchError{stored, hash} |
||||
} |
||||
} |
||||
|
||||
// Get the existing chain configuration.
|
||||
newcfg := genesis.configOrDefault(stored) |
||||
storedcfg := rawdb.ReadChainConfig(db, stored) |
||||
if storedcfg == nil { |
||||
log.Warn("Found genesis block without chain config") |
||||
rawdb.WriteChainConfig(db, stored, newcfg) |
||||
return newcfg, stored, nil |
||||
} |
||||
// Special case: don't change the existing config of a non-mainnet chain if no new
|
||||
// config is supplied. These chains would get AllProtocolChanges (and a compat error)
|
||||
// if we just continued here.
|
||||
if genesis == nil && stored != params.MainnetGenesisHash { |
||||
return storedcfg, stored, nil |
||||
} |
||||
|
||||
// Check config compatibility and write the config. Compatibility errors
|
||||
// are returned to the caller unless we're already at block zero.
|
||||
height := rawdb.ReadHeaderNumber(db, rawdb.ReadHeadHeaderHash(db)) |
||||
if height == nil { |
||||
return newcfg, stored, fmt.Errorf("missing block number for head header hash") |
||||
} |
||||
compatErr := storedcfg.CheckCompatible(newcfg, *height) |
||||
if compatErr != nil && *height != 0 && compatErr.RewindTo != 0 { |
||||
return newcfg, stored, compatErr |
||||
} |
||||
rawdb.WriteChainConfig(db, stored, newcfg) |
||||
return newcfg, stored, nil |
||||
} |
||||
|
||||
func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { |
||||
switch { |
||||
case g != nil: |
||||
return g.Config |
||||
case ghash == params.MainnetGenesisHash: |
||||
return params.MainnetChainConfig |
||||
case ghash == params.TestnetGenesisHash: |
||||
return params.TestnetChainConfig |
||||
default: |
||||
return params.AllEthashProtocolChanges |
||||
} |
||||
} |
||||
|
||||
// ToBlock creates the genesis block and writes state of a genesis specification
|
||||
// to the given database (or discards it if nil).
|
||||
func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { |
||||
if db == nil { |
||||
db = ethdb.NewMemDatabase() |
||||
} |
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) |
||||
for addr, account := range g.Alloc { |
||||
statedb.AddBalance(addr, account.Balance) |
||||
statedb.SetCode(addr, account.Code) |
||||
statedb.SetNonce(addr, account.Nonce) |
||||
for key, value := range account.Storage { |
||||
statedb.SetState(addr, key, value) |
||||
} |
||||
} |
||||
root := statedb.IntermediateRoot(false) |
||||
head := &types.Header{ |
||||
Number: new(big.Int).SetUint64(g.Number), |
||||
Nonce: types.EncodeNonce(g.Nonce), |
||||
Time: new(big.Int).SetUint64(g.Timestamp), |
||||
ParentHash: g.ParentHash, |
||||
Extra: g.ExtraData, |
||||
GasLimit: g.GasLimit, |
||||
GasUsed: g.GasUsed, |
||||
Difficulty: g.Difficulty, |
||||
MixDigest: g.Mixhash, |
||||
Coinbase: g.Coinbase, |
||||
Root: root, |
||||
} |
||||
if g.GasLimit == 0 { |
||||
head.GasLimit = params.GenesisGasLimit |
||||
} |
||||
if g.Difficulty == nil { |
||||
head.Difficulty = params.GenesisDifficulty |
||||
} |
||||
statedb.Commit(false) |
||||
statedb.Database().TrieDB().Commit(root, true) |
||||
|
||||
return types.NewBlock(head, nil, nil, nil) |
||||
} |
||||
|
||||
// Commit writes the block and state of a genesis specification to the database.
|
||||
// The block is committed as the canonical head block.
|
||||
func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) { |
||||
block := g.ToBlock(db) |
||||
if block.Number().Sign() != 0 { |
||||
return nil, fmt.Errorf("can't commit genesis block with number > 0") |
||||
} |
||||
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty) |
||||
rawdb.WriteBlock(db, block) |
||||
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil) |
||||
rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) |
||||
rawdb.WriteHeadBlockHash(db, block.Hash()) |
||||
rawdb.WriteHeadHeaderHash(db, block.Hash()) |
||||
|
||||
config := g.Config |
||||
if config == nil { |
||||
config = params.AllEthashProtocolChanges |
||||
} |
||||
rawdb.WriteChainConfig(db, block.Hash(), config) |
||||
return block, nil |
||||
} |
||||
|
||||
// MustCommit writes the genesis block and state to db, panicking on error.
|
||||
// The block is committed as the canonical head block.
|
||||
func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { |
||||
block, err := g.Commit(db) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
return block |
||||
} |
||||
|
||||
// GenesisBlockForTesting creates and writes a block in which addr has the given wei balance.
|
||||
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block { |
||||
g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}} |
||||
return g.MustCommit(db) |
||||
} |
||||
|
||||
// DefaultGenesisBlock returns the Ethereum main net genesis block.
|
||||
func DefaultGenesisBlock() *Genesis { |
||||
return &Genesis{ |
||||
Config: params.MainnetChainConfig, |
||||
Nonce: 66, |
||||
ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), |
||||
GasLimit: 5000, |
||||
Difficulty: big.NewInt(17179869184), |
||||
Alloc: decodePrealloc("empty"), |
||||
} |
||||
} |
||||
|
||||
// DeveloperGenesisBlock returns the 'geth --dev' genesis block. Note, this must
|
||||
// be seeded with the
|
||||
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis { |
||||
// Override the default period to the user requested one
|
||||
config := *params.AllCliqueProtocolChanges |
||||
config.Clique.Period = period |
||||
|
||||
// Assemble and return the genesis with the precompiles and faucet pre-funded
|
||||
return &Genesis{ |
||||
Config: &config, |
||||
ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, 65)...), |
||||
GasLimit: 6283185, |
||||
Difficulty: big.NewInt(1), |
||||
Alloc: map[common.Address]GenesisAccount{ |
||||
common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover
|
||||
common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256
|
||||
common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD
|
||||
common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity
|
||||
common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp
|
||||
common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd
|
||||
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
||||
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
||||
faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))}, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func decodePrealloc(data string) GenesisAlloc { |
||||
var p []struct{ Addr, Balance *big.Int } |
||||
|
||||
// Create empty allocation for now
|
||||
// TODO: create genesis block with actual content
|
||||
//if err := rlp.NewStream(strings.NewReader(data), 0).Decode(&p); err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
_ = data |
||||
ga := make(GenesisAlloc, len(p)) |
||||
for _, account := range p { |
||||
ga[common.BigToAddress(account.Addr)] = GenesisAccount{Balance: account.Balance} |
||||
} |
||||
return ga |
||||
} |
@ -0,0 +1,507 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core |
||||
|
||||
import ( |
||||
crand "crypto/rand" |
||||
"errors" |
||||
"fmt" |
||||
"math" |
||||
"math/big" |
||||
mrand "math/rand" |
||||
"sync/atomic" |
||||
"time" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/consensus" |
||||
"github.com/ethereum/go-ethereum/core/rawdb" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/ethdb" |
||||
"github.com/ethereum/go-ethereum/log" |
||||
"github.com/ethereum/go-ethereum/params" |
||||
"github.com/hashicorp/golang-lru" |
||||
) |
||||
|
||||
const ( |
||||
headerCacheLimit = 512 |
||||
tdCacheLimit = 1024 |
||||
numberCacheLimit = 2048 |
||||
) |
||||
|
||||
// HeaderChain implements the basic block header chain logic that is shared by
|
||||
// core.BlockChain and light.LightChain. It is not usable in itself, only as
|
||||
// a part of either structure.
|
||||
// It is not thread safe either, the encapsulating chain structures should do
|
||||
// the necessary mutex locking/unlocking.
|
||||
type HeaderChain struct { |
||||
config *params.ChainConfig |
||||
|
||||
chainDb ethdb.Database |
||||
genesisHeader *types.Header |
||||
|
||||
currentHeader atomic.Value // Current head of the header chain (may be above the block chain!)
|
||||
currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time)
|
||||
|
||||
headerCache *lru.Cache // Cache for the most recent block headers
|
||||
tdCache *lru.Cache // Cache for the most recent block total difficulties
|
||||
numberCache *lru.Cache // Cache for the most recent block numbers
|
||||
|
||||
procInterrupt func() bool |
||||
|
||||
rand *mrand.Rand |
||||
engine consensus.Engine |
||||
} |
||||
|
||||
// NewHeaderChain creates a new HeaderChain structure.
|
||||
// getValidator should return the parent's validator
|
||||
// procInterrupt points to the parent's interrupt semaphore
|
||||
// wg points to the parent's shutdown wait group
|
||||
func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) { |
||||
headerCache, _ := lru.New(headerCacheLimit) |
||||
tdCache, _ := lru.New(tdCacheLimit) |
||||
numberCache, _ := lru.New(numberCacheLimit) |
||||
|
||||
// Seed a fast but crypto originating random generator
|
||||
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
hc := &HeaderChain{ |
||||
config: config, |
||||
chainDb: chainDb, |
||||
headerCache: headerCache, |
||||
tdCache: tdCache, |
||||
numberCache: numberCache, |
||||
procInterrupt: procInterrupt, |
||||
rand: mrand.New(mrand.NewSource(seed.Int64())), |
||||
engine: engine, |
||||
} |
||||
|
||||
hc.genesisHeader = hc.GetHeaderByNumber(0) |
||||
if hc.genesisHeader == nil { |
||||
return nil, ErrNoGenesis |
||||
} |
||||
|
||||
hc.currentHeader.Store(hc.genesisHeader) |
||||
if head := rawdb.ReadHeadBlockHash(chainDb); head != (common.Hash{}) { |
||||
if chead := hc.GetHeaderByHash(head); chead != nil { |
||||
hc.currentHeader.Store(chead) |
||||
} |
||||
} |
||||
hc.currentHeaderHash = hc.CurrentHeader().Hash() |
||||
|
||||
return hc, nil |
||||
} |
||||
|
||||
// GetBlockNumber retrieves the block number belonging to the given hash
|
||||
// from the cache or database
|
||||
func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 { |
||||
if cached, ok := hc.numberCache.Get(hash); ok { |
||||
number := cached.(uint64) |
||||
return &number |
||||
} |
||||
number := rawdb.ReadHeaderNumber(hc.chainDb, hash) |
||||
if number != nil { |
||||
hc.numberCache.Add(hash, *number) |
||||
} |
||||
return number |
||||
} |
||||
|
||||
// WriteHeader writes a header into the local chain, given that its parent is
|
||||
// already known. If the total difficulty of the newly inserted header becomes
|
||||
// greater than the current known TD, the canonical chain is re-routed.
|
||||
//
|
||||
// Note: This method is not concurrent-safe with inserting blocks simultaneously
|
||||
// into the chain, as side effects caused by reorganisations cannot be emulated
|
||||
// without the real blocks. Hence, writing headers directly should only be done
|
||||
// in two scenarios: pure-header mode of operation (light clients), or properly
|
||||
// separated header/block phases (non-archive clients).
|
||||
func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, err error) { |
||||
// Cache some values to prevent constant recalculation
|
||||
var ( |
||||
hash = header.Hash() |
||||
number = header.Number.Uint64() |
||||
) |
||||
// Calculate the total difficulty of the header
|
||||
ptd := hc.GetTd(header.ParentHash, number-1) |
||||
if ptd == nil { |
||||
return NonStatTy, consensus.ErrUnknownAncestor |
||||
} |
||||
localTd := hc.GetTd(hc.currentHeaderHash, hc.CurrentHeader().Number.Uint64()) |
||||
externTd := new(big.Int).Add(header.Difficulty, ptd) |
||||
|
||||
// Irrelevant of the canonical status, write the td and header to the database
|
||||
if err := hc.WriteTd(hash, number, externTd); err != nil { |
||||
log.Crit("Failed to write header total difficulty", "err", err) |
||||
} |
||||
rawdb.WriteHeader(hc.chainDb, header) |
||||
|
||||
// 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.
|
||||
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
||||
if externTd.Cmp(localTd) > 0 || (externTd.Cmp(localTd) == 0 && mrand.Float64() < 0.5) { |
||||
// Delete any canonical number assignments above the new head
|
||||
batch := hc.chainDb.NewBatch() |
||||
for i := number + 1; ; i++ { |
||||
hash := rawdb.ReadCanonicalHash(hc.chainDb, i) |
||||
if hash == (common.Hash{}) { |
||||
break |
||||
} |
||||
rawdb.DeleteCanonicalHash(batch, i) |
||||
} |
||||
batch.Write() |
||||
|
||||
// Overwrite any stale canonical number assignments
|
||||
var ( |
||||
headHash = header.ParentHash |
||||
headNumber = header.Number.Uint64() - 1 |
||||
headHeader = hc.GetHeader(headHash, headNumber) |
||||
) |
||||
for rawdb.ReadCanonicalHash(hc.chainDb, headNumber) != headHash { |
||||
rawdb.WriteCanonicalHash(hc.chainDb, headHash, headNumber) |
||||
|
||||
headHash = headHeader.ParentHash |
||||
headNumber = headHeader.Number.Uint64() - 1 |
||||
headHeader = hc.GetHeader(headHash, headNumber) |
||||
} |
||||
// Extend the canonical chain with the new header
|
||||
rawdb.WriteCanonicalHash(hc.chainDb, hash, number) |
||||
rawdb.WriteHeadHeaderHash(hc.chainDb, hash) |
||||
|
||||
hc.currentHeaderHash = hash |
||||
hc.currentHeader.Store(types.CopyHeader(header)) |
||||
|
||||
status = CanonStatTy |
||||
} else { |
||||
status = SideStatTy |
||||
} |
||||
|
||||
hc.headerCache.Add(hash, header) |
||||
hc.numberCache.Add(hash, number) |
||||
|
||||
return |
||||
} |
||||
|
||||
// WhCallback is a callback function for inserting individual headers.
|
||||
// A callback is used for two reasons: first, in a LightChain, status should be
|
||||
// processed and light chain events sent, while in a BlockChain this is not
|
||||
// necessary since chain events are sent after inserting blocks. Second, the
|
||||
// header writes should be protected by the parent chain mutex individually.
|
||||
type WhCallback func(*types.Header) error |
||||
|
||||
func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int) (int, error) { |
||||
// Do a sanity check that the provided chain is actually ordered and linked
|
||||
for i := 1; i < len(chain); i++ { |
||||
if chain[i].Number.Uint64() != chain[i-1].Number.Uint64()+1 || chain[i].ParentHash != chain[i-1].Hash() { |
||||
// Chain broke ancestry, log a message (programming error) and skip insertion
|
||||
log.Error("Non contiguous header insert", "number", chain[i].Number, "hash", chain[i].Hash(), |
||||
"parent", chain[i].ParentHash, "prevnumber", chain[i-1].Number, "prevhash", chain[i-1].Hash()) |
||||
|
||||
return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, chain[i-1].Number, |
||||
chain[i-1].Hash().Bytes()[:4], i, chain[i].Number, chain[i].Hash().Bytes()[:4], chain[i].ParentHash[:4]) |
||||
} |
||||
} |
||||
|
||||
// Generate the list of seal verification requests, and start the parallel verifier
|
||||
seals := make([]bool, len(chain)) |
||||
for i := 0; i < len(seals)/checkFreq; i++ { |
||||
index := i*checkFreq + hc.rand.Intn(checkFreq) |
||||
if index >= len(seals) { |
||||
index = len(seals) - 1 |
||||
} |
||||
seals[index] = true |
||||
} |
||||
seals[len(seals)-1] = true // Last should always be verified to avoid junk
|
||||
|
||||
abort, results := hc.engine.VerifyHeaders(hc, chain, seals) |
||||
defer close(abort) |
||||
|
||||
// Iterate over the headers and ensure they all check out
|
||||
for i, _ := range chain { |
||||
// If the chain is terminating, stop processing blocks
|
||||
if hc.procInterrupt() { |
||||
log.Debug("Premature abort during headers verification") |
||||
return 0, errors.New("aborted") |
||||
} |
||||
|
||||
// Otherwise wait for headers checks and ensure they pass
|
||||
if err := <-results; err != nil { |
||||
return i, err |
||||
} |
||||
} |
||||
|
||||
return 0, nil |
||||
} |
||||
|
||||
// InsertHeaderChain attempts to insert the given header chain in to the local
|
||||
// chain, possibly creating a reorg. If an error is returned, it will return the
|
||||
// index number of the failing header as well an error describing what went wrong.
|
||||
//
|
||||
// The verify parameter can be used to fine tune whether nonce verification
|
||||
// should be done or not. The reason behind the optional check is because some
|
||||
// of the header retrieval mechanisms already need to verfy nonces, as well as
|
||||
// because nonces can be verified sparsely, not needing to check each.
|
||||
func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCallback, start time.Time) (int, error) { |
||||
// Collect some import statistics to report on
|
||||
stats := struct{ processed, ignored int }{} |
||||
// All headers passed verification, import them into the database
|
||||
for i, header := range chain { |
||||
// Short circuit insertion if shutting down
|
||||
if hc.procInterrupt() { |
||||
log.Debug("Premature abort during headers import") |
||||
return i, errors.New("aborted") |
||||
} |
||||
// If the header's already known, skip it, otherwise store
|
||||
if hc.HasHeader(header.Hash(), header.Number.Uint64()) { |
||||
stats.ignored++ |
||||
continue |
||||
} |
||||
if err := writeHeader(header); err != nil { |
||||
return i, err |
||||
} |
||||
stats.processed++ |
||||
} |
||||
// Report some public statistics so the user has a clue what's going on
|
||||
last := chain[len(chain)-1] |
||||
|
||||
context := []interface{}{ |
||||
"count", stats.processed, "elapsed", common.PrettyDuration(time.Since(start)), |
||||
"number", last.Number, "hash", last.Hash(), |
||||
} |
||||
if timestamp := time.Unix(last.Time.Int64(), 0); time.Since(timestamp) > time.Minute { |
||||
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) |
||||
} |
||||
if stats.ignored > 0 { |
||||
context = append(context, []interface{}{"ignored", stats.ignored}...) |
||||
} |
||||
log.Info("Imported new block headers", context...) |
||||
|
||||
return 0, nil |
||||
} |
||||
|
||||
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
|
||||
// hash, fetching towards the genesis block.
|
||||
func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash { |
||||
// Get the origin header from which to fetch
|
||||
header := hc.GetHeaderByHash(hash) |
||||
if header == nil { |
||||
return nil |
||||
} |
||||
// Iterate the headers until enough is collected or the genesis reached
|
||||
chain := make([]common.Hash, 0, max) |
||||
for i := uint64(0); i < max; i++ { |
||||
next := header.ParentHash |
||||
if header = hc.GetHeader(next, header.Number.Uint64()-1); header == nil { |
||||
break |
||||
} |
||||
chain = append(chain, next) |
||||
if header.Number.Sign() == 0 { |
||||
break |
||||
} |
||||
} |
||||
return chain |
||||
} |
||||
|
||||
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
|
||||
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
|
||||
// number of blocks to be individually checked before we reach the canonical chain.
|
||||
//
|
||||
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
|
||||
func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) { |
||||
if ancestor > number { |
||||
return common.Hash{}, 0 |
||||
} |
||||
if ancestor == 1 { |
||||
// in this case it is cheaper to just read the header
|
||||
if header := hc.GetHeader(hash, number); header != nil { |
||||
return header.ParentHash, number - 1 |
||||
} else { |
||||
return common.Hash{}, 0 |
||||
} |
||||
} |
||||
for ancestor != 0 { |
||||
if rawdb.ReadCanonicalHash(hc.chainDb, number) == hash { |
||||
number -= ancestor |
||||
return rawdb.ReadCanonicalHash(hc.chainDb, number), number |
||||
} |
||||
if *maxNonCanonical == 0 { |
||||
return common.Hash{}, 0 |
||||
} |
||||
*maxNonCanonical-- |
||||
ancestor-- |
||||
header := hc.GetHeader(hash, number) |
||||
if header == nil { |
||||
return common.Hash{}, 0 |
||||
} |
||||
hash = header.ParentHash |
||||
number-- |
||||
} |
||||
return hash, number |
||||
} |
||||
|
||||
// GetTd retrieves a block's total difficulty in the canonical chain from the
|
||||
// database by hash and number, caching it if found.
|
||||
func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { |
||||
// Short circuit if the td's already in the cache, retrieve otherwise
|
||||
if cached, ok := hc.tdCache.Get(hash); ok { |
||||
return cached.(*big.Int) |
||||
} |
||||
td := rawdb.ReadTd(hc.chainDb, hash, number) |
||||
if td == nil { |
||||
return nil |
||||
} |
||||
// Cache the found body for next time and return
|
||||
hc.tdCache.Add(hash, td) |
||||
return td |
||||
} |
||||
|
||||
// GetTdByHash retrieves a block's total difficulty in the canonical chain from the
|
||||
// database by hash, caching it if found.
|
||||
func (hc *HeaderChain) GetTdByHash(hash common.Hash) *big.Int { |
||||
number := hc.GetBlockNumber(hash) |
||||
if number == nil { |
||||
return nil |
||||
} |
||||
return hc.GetTd(hash, *number) |
||||
} |
||||
|
||||
// WriteTd stores a block's total difficulty into the database, also caching it
|
||||
// along the way.
|
||||
func (hc *HeaderChain) WriteTd(hash common.Hash, number uint64, td *big.Int) error { |
||||
rawdb.WriteTd(hc.chainDb, hash, number, td) |
||||
hc.tdCache.Add(hash, new(big.Int).Set(td)) |
||||
return nil |
||||
} |
||||
|
||||
// GetHeader retrieves a block header from the database by hash and number,
|
||||
// caching it if found.
|
||||
func (hc *HeaderChain) GetHeader(hash common.Hash, number uint64) *types.Header { |
||||
// Short circuit if the header's already in the cache, retrieve otherwise
|
||||
if header, ok := hc.headerCache.Get(hash); ok { |
||||
return header.(*types.Header) |
||||
} |
||||
header := rawdb.ReadHeader(hc.chainDb, hash, number) |
||||
if header == nil { |
||||
return nil |
||||
} |
||||
// Cache the found header for next time and return
|
||||
hc.headerCache.Add(hash, header) |
||||
return header |
||||
} |
||||
|
||||
// GetHeaderByHash retrieves a block header from the database by hash, caching it if
|
||||
// found.
|
||||
func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header { |
||||
number := hc.GetBlockNumber(hash) |
||||
if number == nil { |
||||
return nil |
||||
} |
||||
return hc.GetHeader(hash, *number) |
||||
} |
||||
|
||||
// HasHeader checks if a block header is present in the database or not.
|
||||
func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool { |
||||
if hc.numberCache.Contains(hash) || hc.headerCache.Contains(hash) { |
||||
return true |
||||
} |
||||
return rawdb.HasHeader(hc.chainDb, hash, number) |
||||
} |
||||
|
||||
// GetHeaderByNumber retrieves a block header from the database by number,
|
||||
// caching it (associated with its hash) if found.
|
||||
func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { |
||||
hash := rawdb.ReadCanonicalHash(hc.chainDb, number) |
||||
if hash == (common.Hash{}) { |
||||
return nil |
||||
} |
||||
return hc.GetHeader(hash, number) |
||||
} |
||||
|
||||
// CurrentHeader retrieves the current head header of the canonical chain. The
|
||||
// header is retrieved from the HeaderChain's internal cache.
|
||||
func (hc *HeaderChain) CurrentHeader() *types.Header { |
||||
return hc.currentHeader.Load().(*types.Header) |
||||
} |
||||
|
||||
// SetCurrentHeader sets the current head header of the canonical chain.
|
||||
func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { |
||||
rawdb.WriteHeadHeaderHash(hc.chainDb, head.Hash()) |
||||
|
||||
hc.currentHeader.Store(head) |
||||
hc.currentHeaderHash = head.Hash() |
||||
} |
||||
|
||||
// DeleteCallback is a callback function that is called by SetHead before
|
||||
// each header is deleted.
|
||||
type DeleteCallback func(rawdb.DatabaseDeleter, common.Hash, uint64) |
||||
|
||||
// SetHead rewinds the local chain to a new head. Everything above the new head
|
||||
// will be deleted and the new one set.
|
||||
func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) { |
||||
height := uint64(0) |
||||
|
||||
if hdr := hc.CurrentHeader(); hdr != nil { |
||||
height = hdr.Number.Uint64() |
||||
} |
||||
batch := hc.chainDb.NewBatch() |
||||
for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() { |
||||
hash := hdr.Hash() |
||||
num := hdr.Number.Uint64() |
||||
if delFn != nil { |
||||
delFn(batch, hash, num) |
||||
} |
||||
rawdb.DeleteHeader(batch, hash, num) |
||||
rawdb.DeleteTd(batch, hash, num) |
||||
|
||||
hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash, hdr.Number.Uint64()-1)) |
||||
} |
||||
// Roll back the canonical chain numbering
|
||||
for i := height; i > head; i-- { |
||||
rawdb.DeleteCanonicalHash(batch, i) |
||||
} |
||||
batch.Write() |
||||
|
||||
// Clear out any stale content from the caches
|
||||
hc.headerCache.Purge() |
||||
hc.tdCache.Purge() |
||||
hc.numberCache.Purge() |
||||
|
||||
if hc.CurrentHeader() == nil { |
||||
hc.currentHeader.Store(hc.genesisHeader) |
||||
} |
||||
hc.currentHeaderHash = hc.CurrentHeader().Hash() |
||||
|
||||
rawdb.WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash) |
||||
} |
||||
|
||||
// SetGenesis sets a new genesis block header for the chain
|
||||
func (hc *HeaderChain) SetGenesis(head *types.Header) { |
||||
hc.genesisHeader = head |
||||
} |
||||
|
||||
// Config retrieves the header chain's chain configuration.
|
||||
func (hc *HeaderChain) Config() *params.ChainConfig { return hc.config } |
||||
|
||||
// Engine retrieves the header chain's consensus engine.
|
||||
func (hc *HeaderChain) Engine() consensus.Engine { return hc.engine } |
||||
|
||||
// GetBlock implements consensus.ChainReader, and returns nil for every input as
|
||||
// a header chain does not have blocks available for retrieval.
|
||||
func (hc *HeaderChain) GetBlock(hash common.Hash, number uint64) *types.Block { |
||||
return nil |
||||
} |
@ -0,0 +1,126 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core |
||||
|
||||
import ( |
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/consensus" |
||||
"github.com/ethereum/go-ethereum/consensus/misc" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/core/vm" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
"github.com/ethereum/go-ethereum/params" |
||||
) |
||||
|
||||
// StateProcessor is a basic Processor, which takes care of transitioning
|
||||
// state from one point to another.
|
||||
//
|
||||
// StateProcessor implements Processor.
|
||||
type StateProcessor struct { |
||||
config *params.ChainConfig // Chain configuration options
|
||||
bc *BlockChain // Canonical block chain
|
||||
engine consensus.Engine // Consensus engine used for block rewards
|
||||
} |
||||
|
||||
// NewStateProcessor initialises a new StateProcessor.
|
||||
func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { |
||||
return &StateProcessor{ |
||||
config: config, |
||||
bc: bc, |
||||
engine: engine, |
||||
} |
||||
} |
||||
|
||||
// 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, []*types.Log, uint64, error) { |
||||
var ( |
||||
receipts types.Receipts |
||||
usedGas = new(uint64) |
||||
header = block.Header() |
||||
allLogs []*types.Log |
||||
gp = new(GasPool).AddGas(block.GasLimit()) |
||||
) |
||||
// Mutate 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 { |
||||
misc.ApplyDAOHardFork(statedb) |
||||
} |
||||
// Iterate over and process the individual transactions
|
||||
for i, tx := range block.Transactions() { |
||||
statedb.Prepare(tx.Hash(), block.Hash(), i) |
||||
receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) |
||||
if err != nil { |
||||
return nil, nil, 0, err |
||||
} |
||||
receipts = append(receipts, receipt) |
||||
allLogs = append(allLogs, receipt.Logs...) |
||||
} |
||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts) |
||||
|
||||
return receipts, allLogs, *usedGas, nil |
||||
} |
||||
|
||||
// ApplyTransaction attempts to apply a transaction to the given state database
|
||||
// and uses the input parameters for its environment. It returns the receipt
|
||||
// for the transaction, gas used and an error if the transaction failed,
|
||||
// indicating the block was invalid.
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { |
||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) |
||||
if err != nil { |
||||
return nil, 0, err |
||||
} |
||||
// Create a new context to be used in the EVM environment
|
||||
context := NewEVMContext(msg, header, bc, author) |
||||
// Create a new environment which holds all relevant information
|
||||
// about the transaction and calling mechanisms.
|
||||
vmenv := vm.NewEVM(context, statedb, config, cfg) |
||||
// Apply the transaction to the current state (included in the env)
|
||||
_, gas, failed, err := ApplyMessage(vmenv, msg, gp) |
||||
if err != nil { |
||||
return nil, 0, err |
||||
} |
||||
// Update the state with pending changes
|
||||
var root []byte |
||||
if config.IsByzantium(header.Number) { |
||||
statedb.Finalise(true) |
||||
} else { |
||||
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() |
||||
} |
||||
*usedGas += gas |
||||
|
||||
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
|
||||
// based on the eip phase, we're passing whether the root touch-delete accounts.
|
||||
receipt := types.NewReceipt(root, failed, *usedGas) |
||||
receipt.TxHash = tx.Hash() |
||||
receipt.GasUsed = gas |
||||
// if the transaction created a contract, store the creation address in the receipt.
|
||||
if msg.To() == nil { |
||||
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) |
||||
} |
||||
// Set the receipt logs and create a bloom for filtering
|
||||
receipt.Logs = statedb.GetLogs(tx.Hash()) |
||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) |
||||
|
||||
return receipt, gas, err |
||||
} |
@ -0,0 +1,46 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core |
||||
|
||||
import ( |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/core/vm" |
||||
) |
||||
|
||||
// Validator is an interface which defines the standard for block validation. It
|
||||
// is only responsible for validating block contents, as the header validation is
|
||||
// done by the specific consensus engines.
|
||||
//
|
||||
type Validator interface { |
||||
// ValidateBody validates the given block's content.
|
||||
ValidateBody(block *types.Block) error |
||||
|
||||
// ValidateState validates the given statedb and optionally the receipts and
|
||||
// gas used.
|
||||
ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error |
||||
} |
||||
|
||||
// Processor is an interface for processing blocks using a given initial state.
|
||||
//
|
||||
// Process takes the block to be processed and the statedb upon which the
|
||||
// initial state is based. It should return the receipts generated, amount
|
||||
// of gas used in the process and return an error if any of the internal rules
|
||||
// failed.
|
||||
type Processor interface { |
||||
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) |
||||
} |
Loading…
Reference in new issue