mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
cmd,consensus,core,eth,params,tests: articulate EIP features
Refactors chain configuration and respective feature implementations to use EIP definitions and methods, instead of HardFork names, whenever possible. Doing so attempts to address ambiguity and complexity in chain configuration and feature implementation. Signed-off-by: Isaac Ardis (isaac.ardis@gmail.com)
This commit is contained in:
parent
56a3f6c03c
commit
717df21245
19 changed files with 923 additions and 233 deletions
|
|
@ -421,7 +421,7 @@ func (spec *parityChainSpec) setPrecompile(address byte, data *parityChainSpecBu
|
|||
}
|
||||
|
||||
func (spec *parityChainSpec) setByzantium(num *big.Int) {
|
||||
spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.ByzantiumBlockReward)
|
||||
spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.EIP649FBlockReward)
|
||||
spec.Engine.Ethash.Params.DifficultyBombDelays[hexutil.EncodeBig(num)] = hexutil.EncodeUint64(3000000)
|
||||
n := hexutil.Uint64(num.Uint64())
|
||||
spec.Engine.Ethash.Params.EIP100bTransition = n
|
||||
|
|
@ -432,7 +432,7 @@ func (spec *parityChainSpec) setByzantium(num *big.Int) {
|
|||
}
|
||||
|
||||
func (spec *parityChainSpec) setConstantinople(num *big.Int) {
|
||||
spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.ConstantinopleBlockReward)
|
||||
spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.EIP1234FBlockReward)
|
||||
spec.Engine.Ethash.Params.DifficultyBombDelays[hexutil.EncodeBig(num)] = hexutil.EncodeUint64(2000000)
|
||||
n := hexutil.Uint64(num.Uint64())
|
||||
spec.Params.EIP145Transition = n
|
||||
|
|
|
|||
|
|
@ -581,7 +581,7 @@ func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) erro
|
|||
// rewards given, and returns the final block.
|
||||
func (c *Clique) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
||||
// No block rewards in PoA, so the state remains as is and uncles are dropped
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP161F(header.Number))
|
||||
header.UncleHash = types.CalcUncleHash(nil)
|
||||
|
||||
// Assemble and return the final block for sealing
|
||||
|
|
|
|||
|
|
@ -39,22 +39,24 @@ import (
|
|||
// Ethash proof-of-work protocol constants.
|
||||
var (
|
||||
FrontierBlockReward = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
|
||||
ByzantiumBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
|
||||
ConstantinopleBlockReward = big.NewInt(2e+18) // Block reward in wei for successfully mining a block upward from Constantinople
|
||||
EIP649FBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
|
||||
EIP1234FBlockReward = big.NewInt(2e+18) // Block reward in wei for successfully mining a block upward from Constantinople
|
||||
maxUncles = 2 // Maximum number of uncles allowed in a single block
|
||||
allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks
|
||||
|
||||
// calcDifficultyConstantinople is the difficulty adjustment algorithm for Constantinople.
|
||||
// calcDifficultyEIP1234 is the difficulty adjustment algorithm for Constantinople.
|
||||
// It returns the difficulty that a new block should have when created at time given the
|
||||
// parent block's time and difficulty. The calculation uses the Byzantium rules, but with
|
||||
// bomb offset 5M.
|
||||
// Specification EIP-1234: https://eips.ethereum.org/EIPS/eip-1234
|
||||
calcDifficultyConstantinople = makeDifficultyCalculator(big.NewInt(5000000))
|
||||
calcDifficultyEIP1234 = makeDifficultyCalculator(big.NewInt(5000000))
|
||||
|
||||
// calcDifficultyByzantium is the difficulty adjustment algorithm. It returns
|
||||
// calcDifficultyByzantium is the difficulty adjustment algorithm for Byzantium. It returns
|
||||
// the difficulty that a new block should have when created at time given the
|
||||
// parent block's time and difficulty. The calculation uses the Byzantium rules.
|
||||
// Specification EIP-649: https://eips.ethereum.org/EIPS/eip-649
|
||||
// Related meta-ish EIP-669: https://github.com/ethereum/EIPs/pull/669
|
||||
// Note that this calculator also includes the change from EIP100.
|
||||
calcDifficultyByzantium = makeDifficultyCalculator(big.NewInt(3000000))
|
||||
)
|
||||
|
||||
|
|
@ -313,10 +315,16 @@ func (ethash *Ethash) CalcDifficulty(chain consensus.ChainReader, time uint64, p
|
|||
func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
|
||||
next := new(big.Int).Add(parent.Number, big1)
|
||||
switch {
|
||||
case config.IsConstantinople(next):
|
||||
return calcDifficultyConstantinople(time, parent)
|
||||
case config.IsByzantium(next):
|
||||
case config.IsEIP1234F(next):
|
||||
return calcDifficultyEIP1234(time, parent)
|
||||
case config.IsByzantium(next) || (config.IsEIP649F(next) && config.IsEIP100F(next)):
|
||||
return calcDifficultyByzantium(time, parent)
|
||||
case config.IsEIP649F(next):
|
||||
// TODO: calculator for only EIP649:difficulty bomb delay (without EIP100:mean time adjustment)
|
||||
panic("not implemented")
|
||||
case config.IsEIP100F(next):
|
||||
// TODO: calculator for only EIP100:mean time adjustment (without EIP649:difficulty bomb delay)
|
||||
panic("not implemented")
|
||||
case config.IsHomestead(next):
|
||||
return calcDifficultyHomestead(time, parent)
|
||||
default:
|
||||
|
|
@ -567,7 +575,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header)
|
|||
func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
||||
// Accumulate any block and uncle rewards and commit the final state root
|
||||
accumulateRewards(chain.Config(), state, header, uncles)
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP161F(header.Number))
|
||||
|
||||
// Header seems complete, assemble into a block and return
|
||||
return types.NewBlock(header, txs, uncles, receipts), nil
|
||||
|
|
@ -608,11 +616,11 @@ var (
|
|||
func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
|
||||
// Select the correct block reward based on chain progression
|
||||
blockReward := FrontierBlockReward
|
||||
if config.IsByzantium(header.Number) {
|
||||
blockReward = ByzantiumBlockReward
|
||||
if config.IsEIP649F(header.Number) {
|
||||
blockReward = EIP649FBlockReward
|
||||
}
|
||||
if config.IsConstantinople(header.Number) {
|
||||
blockReward = ConstantinopleBlockReward
|
||||
if config.IsEIP1234F(header.Number) {
|
||||
blockReward = EIP1234FBlockReward
|
||||
}
|
||||
// Accumulate the rewards for the miner and any included uncles
|
||||
reward := new(big.Int).Set(blockReward)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
|
|||
}
|
||||
// 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 {
|
||||
if root := statedb.IntermediateRoot(v.config.IsEIP161F(header.Number)); header.Root != root {
|
||||
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -946,7 +946,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
|
|||
}
|
||||
rawdb.WriteBlock(bc.db, block)
|
||||
|
||||
root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number()))
|
||||
root, err := state.Commit(bc.chainConfig.IsEIP161F(block.Number()))
|
||||
if err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
block, _ := b.engine.Finalize(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts)
|
||||
|
||||
// Write state changes to db
|
||||
root, err := statedb.Commit(config.IsEIP158(b.header.Number))
|
||||
root, err := statedb.Commit(config.IsEIP161F(b.header.Number))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("state write error: %v", err))
|
||||
}
|
||||
|
|
@ -233,7 +233,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
|
|||
}
|
||||
|
||||
return &types.Header{
|
||||
Root: state.IntermediateRoot(chain.Config().IsEIP158(parent.Number())),
|
||||
Root: state.IntermediateRoot(chain.Config().IsEIP161F(parent.Number())),
|
||||
ParentHash: parent.Hash(),
|
||||
Coinbase: parent.Coinbase(),
|
||||
Difficulty: engine.CalcDifficulty(chain, time.Uint64(), &types.Header{
|
||||
|
|
|
|||
|
|
@ -102,10 +102,10 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
|||
}
|
||||
// Update the state with pending changes
|
||||
var root []byte
|
||||
if config.IsByzantium(header.Number) {
|
||||
if config.IsEIP658F(header.Number) {
|
||||
statedb.Finalise(true)
|
||||
} else {
|
||||
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
|
||||
root = statedb.IntermediateRoot(config.IsEIP161F(header.Number)).Bytes()
|
||||
}
|
||||
*usedGas += gas
|
||||
|
||||
|
|
|
|||
|
|
@ -37,18 +37,8 @@ type PrecompiledContract interface {
|
|||
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
|
||||
}
|
||||
|
||||
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
|
||||
// contracts used in the Frontier and Homestead releases.
|
||||
var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
|
||||
common.BytesToAddress([]byte{1}): &ecrecover{},
|
||||
common.BytesToAddress([]byte{2}): &sha256hash{},
|
||||
common.BytesToAddress([]byte{3}): &ripemd160hash{},
|
||||
common.BytesToAddress([]byte{4}): &dataCopy{},
|
||||
}
|
||||
|
||||
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
|
||||
// contracts used in the Byzantium release.
|
||||
var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
|
||||
// AllPrecompiledContracts returns all possible precompiled contracts.
|
||||
var AllPrecompiledContracts = map[common.Address]PrecompiledContract{
|
||||
common.BytesToAddress([]byte{1}): &ecrecover{},
|
||||
common.BytesToAddress([]byte{2}): &sha256hash{},
|
||||
common.BytesToAddress([]byte{3}): &ripemd160hash{},
|
||||
|
|
@ -59,6 +49,27 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
|
|||
common.BytesToAddress([]byte{8}): &bn256Pairing{},
|
||||
}
|
||||
|
||||
// IsPrecompiledContractEnabled checks whether a given precompiled contract is enabled for a chain config at a given block.
|
||||
func IsPrecompiledContractEnabled(config *params.ChainConfig, num *big.Int, codeAddr common.Address) bool {
|
||||
switch codeAddr {
|
||||
case common.BytesToAddress([]byte{1}),
|
||||
common.BytesToAddress([]byte{2}),
|
||||
common.BytesToAddress([]byte{3}),
|
||||
common.BytesToAddress([]byte{4}):
|
||||
return true
|
||||
case common.BytesToAddress([]byte{5}):
|
||||
return config.IsEIP198F(num)
|
||||
case common.BytesToAddress([]byte{6}):
|
||||
return config.IsEIP213F(num)
|
||||
case common.BytesToAddress([]byte{7}):
|
||||
return config.IsEIP213F(num)
|
||||
case common.BytesToAddress([]byte{8}):
|
||||
return config.IsEIP212F(num)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
|
||||
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
|
||||
gas := p.RequiredGas(input)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import (
|
|||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
|
|
@ -337,9 +339,10 @@ var bn256PairingTests = []precompiledTest{
|
|||
}
|
||||
|
||||
func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
|
||||
p := PrecompiledContractsByzantium[common.HexToAddress(addr)]
|
||||
p := AllPrecompiledContracts[common.HexToAddress(addr)]
|
||||
in := common.Hex2Bytes(test.input)
|
||||
contract := NewContract(AccountRef(common.HexToAddress("1337")),
|
||||
|
||||
nil, new(big.Int), p.RequiredGas(in))
|
||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
|
||||
if res, err := RunPrecompiledContract(p, in, contract); err != nil {
|
||||
|
|
@ -350,11 +353,100 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestIsPrecompiledContractEnabled(t *testing.T) {
|
||||
var homeCts = []common.Address{
|
||||
common.BytesToAddress([]byte{1}),
|
||||
common.BytesToAddress([]byte{2}),
|
||||
common.BytesToAddress([]byte{3}),
|
||||
common.BytesToAddress([]byte{4}),
|
||||
}
|
||||
var byzUniqCts = []common.Address{
|
||||
common.BytesToAddress([]byte{5}),
|
||||
common.BytesToAddress([]byte{6}),
|
||||
common.BytesToAddress([]byte{7}),
|
||||
common.BytesToAddress([]byte{8}),
|
||||
}
|
||||
var byzCts = append(homeCts, byzUniqCts...)
|
||||
var nonCts = []common.Address{
|
||||
common.Address{},
|
||||
common.BytesToAddress([]byte{42}),
|
||||
common.HexToAddress("0xdeadbeef"),
|
||||
}
|
||||
type c struct {
|
||||
addr common.Address
|
||||
config *params.ChainConfig
|
||||
blockNum *big.Int
|
||||
want bool
|
||||
}
|
||||
cases := []c{}
|
||||
addCaseWhere := func(config *params.ChainConfig, addr common.Address, bn *big.Int, want bool) {
|
||||
cases = append(cases, c{
|
||||
addr: addr,
|
||||
config: config,
|
||||
blockNum: bn,
|
||||
want: want,
|
||||
})
|
||||
}
|
||||
for _, a := range homeCts {
|
||||
addCaseWhere(params.AllEthashProtocolChanges, a, big.NewInt(0), true)
|
||||
addCaseWhere(params.MainnetChainConfig, a, big.NewInt(0), true)
|
||||
addCaseWhere(params.MainnetChainConfig, a, new(big.Int).Sub(params.MainnetChainConfig.ByzantiumBlock, common.Big1), true)
|
||||
addCaseWhere(params.MainnetChainConfig, a, params.MainnetChainConfig.ByzantiumBlock, true)
|
||||
addCaseWhere(params.MainnetChainConfig, a, new(big.Int).Add(params.MainnetChainConfig.ByzantiumBlock, common.Big1), true)
|
||||
}
|
||||
for _, a := range byzUniqCts {
|
||||
addCaseWhere(params.MainnetChainConfig, a, new(big.Int).Sub(params.MainnetChainConfig.ByzantiumBlock, common.Big1), false)
|
||||
addCaseWhere(params.MainnetChainConfig, a, params.MainnetChainConfig.ByzantiumBlock, true)
|
||||
addCaseWhere(params.MainnetChainConfig, a, new(big.Int).Add(params.MainnetChainConfig.ByzantiumBlock, common.Big1), true)
|
||||
}
|
||||
for _, a := range byzCts {
|
||||
addCaseWhere(params.AllEthashProtocolChanges, a, big.NewInt(0), true)
|
||||
addCaseWhere(params.MainnetChainConfig, a, new(big.Int).Add(params.MainnetChainConfig.ByzantiumBlock, common.Big1), true)
|
||||
}
|
||||
for _, a := range nonCts {
|
||||
addCaseWhere(params.AllEthashProtocolChanges, a, big.NewInt(0), false)
|
||||
addCaseWhere(params.MainnetChainConfig, a, new(big.Int).Sub(params.MainnetChainConfig.ByzantiumBlock, common.Big1), false)
|
||||
addCaseWhere(params.MainnetChainConfig, a, new(big.Int).Add(params.MainnetChainConfig.ByzantiumBlock, common.Big1), false)
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
got := IsPrecompiledContractEnabled(c.config, c.blockNum, c.addr)
|
||||
if c.want != got {
|
||||
t.Errorf("test: %d, address: %x, want: %v, got: %v", i, c.addr, c.want, got)
|
||||
}
|
||||
|
||||
// test 1:1 with pre-existing hard-fork implementation style in *evm#Call
|
||||
precomps := map[common.Address]PrecompiledContract{
|
||||
common.BytesToAddress([]byte{1}): &ecrecover{},
|
||||
common.BytesToAddress([]byte{2}): &sha256hash{},
|
||||
common.BytesToAddress([]byte{3}): &ripemd160hash{},
|
||||
common.BytesToAddress([]byte{4}): &dataCopy{},
|
||||
}
|
||||
if c.config.IsByzantium(c.blockNum) {
|
||||
precomps = map[common.Address]PrecompiledContract{
|
||||
common.BytesToAddress([]byte{1}): &ecrecover{},
|
||||
common.BytesToAddress([]byte{2}): &sha256hash{},
|
||||
common.BytesToAddress([]byte{3}): &ripemd160hash{},
|
||||
common.BytesToAddress([]byte{4}): &dataCopy{},
|
||||
common.BytesToAddress([]byte{5}): &bigModExp{},
|
||||
common.BytesToAddress([]byte{6}): &bn256Add{},
|
||||
common.BytesToAddress([]byte{7}): &bn256ScalarMul{},
|
||||
common.BytesToAddress([]byte{8}): &bn256Pairing{},
|
||||
}
|
||||
}
|
||||
expect := precomps[c.addr] == nil
|
||||
got = !IsPrecompiledContractEnabled(c.config, c.blockNum, c.addr)
|
||||
if got != expect {
|
||||
t.Errorf("addr: %x, bn: %v, want: %v, got: %v", c.addr, c.blockNum, c.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
|
||||
if test.noBenchmark {
|
||||
return
|
||||
}
|
||||
p := PrecompiledContractsByzantium[common.HexToAddress(addr)]
|
||||
p := AllPrecompiledContracts[common.HexToAddress(addr)]
|
||||
in := common.Hex2Bytes(test.input)
|
||||
reqGas := p.RequiredGas(in)
|
||||
contract := NewContract(AccountRef(common.HexToAddress("1337")),
|
||||
|
|
|
|||
|
|
@ -43,12 +43,8 @@ type (
|
|||
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
|
||||
func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
|
||||
if contract.CodeAddr != nil {
|
||||
precompiles := PrecompiledContractsHomestead
|
||||
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
|
||||
precompiles = PrecompiledContractsByzantium
|
||||
}
|
||||
if p := precompiles[*contract.CodeAddr]; p != nil {
|
||||
return RunPrecompiledContract(p, input, contract)
|
||||
if IsPrecompiledContractEnabled(evm.ChainConfig(), evm.BlockNumber, *contract.CodeAddr) {
|
||||
return RunPrecompiledContract(AllPrecompiledContracts[*contract.CodeAddr], input, contract)
|
||||
}
|
||||
}
|
||||
for _, interpreter := range evm.interpreters {
|
||||
|
|
@ -197,11 +193,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
snapshot = evm.StateDB.Snapshot()
|
||||
)
|
||||
if !evm.StateDB.Exist(addr) {
|
||||
precompiles := PrecompiledContractsHomestead
|
||||
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
|
||||
precompiles = PrecompiledContractsByzantium
|
||||
}
|
||||
if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
|
||||
if !IsPrecompiledContractEnabled(evm.ChainConfig(), evm.BlockNumber, addr) && evm.ChainConfig().IsEIP161F(evm.BlockNumber) && value.Sign() == 0 {
|
||||
// Calling a non existing account, don't do anything, but ping the tracer
|
||||
if evm.vmConfig.Debug && evm.depth == 0 {
|
||||
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
|
||||
|
|
@ -391,7 +383,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
// Create a new account on the state
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
evm.StateDB.CreateAccount(address)
|
||||
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
||||
if evm.ChainConfig().IsEIP161F(evm.BlockNumber) {
|
||||
evm.StateDB.SetNonce(address, 1)
|
||||
}
|
||||
evm.Transfer(evm.StateDB, caller.Address(), address, value)
|
||||
|
|
@ -414,7 +406,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
|||
ret, err := run(evm, contract, nil, false)
|
||||
|
||||
// check whether the max code size has been exceeded
|
||||
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
|
||||
maxCodeSizeExceeded := evm.ChainConfig().IsEIP170F(evm.BlockNumber) && len(ret) > params.MaxCodeSize
|
||||
// if the contract creation ran successfully and no errors were returned
|
||||
// calculate the gas required to store the code. If the code could not
|
||||
// be stored due to not enough gas set an error and let it be handled
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
|
|||
current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
||||
)
|
||||
// The legacy gas metering only takes into consideration the current state
|
||||
if !evm.chainRules.IsConstantinople {
|
||||
if !evm.chainRules.IsEIP1283F {
|
||||
// This checks for 3 scenario's and calculates gas accordingly:
|
||||
//
|
||||
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
||||
|
|
@ -391,7 +391,7 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem
|
|||
gas = gt.Calls
|
||||
transfersValue = stack.Back(2).Sign() != 0
|
||||
address = common.BigToAddress(stack.Back(1))
|
||||
eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
|
||||
eip158 = evm.ChainConfig().IsEIP161F(evm.BlockNumber)
|
||||
)
|
||||
if eip158 {
|
||||
if transfersValue && evm.StateDB.Empty(address) {
|
||||
|
|
@ -461,7 +461,7 @@ func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack,
|
|||
gas = gt.Suicide
|
||||
var (
|
||||
address = common.BigToAddress(stack.Back(0))
|
||||
eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
|
||||
eip158 = evm.ChainConfig().IsEIP161F(evm.BlockNumber)
|
||||
)
|
||||
|
||||
if eip158 {
|
||||
|
|
|
|||
|
|
@ -99,16 +99,7 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
|
|||
// the jump table was initialised. If it was not
|
||||
// we'll set the default jump table.
|
||||
if !cfg.JumpTable[STOP].valid {
|
||||
switch {
|
||||
case evm.ChainConfig().IsConstantinople(evm.BlockNumber):
|
||||
cfg.JumpTable = constantinopleInstructionSet
|
||||
case evm.ChainConfig().IsByzantium(evm.BlockNumber):
|
||||
cfg.JumpTable = byzantiumInstructionSet
|
||||
case evm.ChainConfig().IsHomestead(evm.BlockNumber):
|
||||
cfg.JumpTable = homesteadInstructionSet
|
||||
default:
|
||||
cfg.JumpTable = frontierInstructionSet
|
||||
}
|
||||
cfg.JumpTable = baseInstructionSet
|
||||
}
|
||||
|
||||
return &EVMInterpreter{
|
||||
|
|
@ -119,7 +110,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
|
|||
}
|
||||
|
||||
func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
|
||||
if in.evm.chainRules.IsByzantium {
|
||||
// STATICCALL
|
||||
if in.evm.chainRules.IsEIP214F {
|
||||
if in.readOnly {
|
||||
// If the interpreter is operating in readonly mode, make sure no
|
||||
// state-modifying operation is performed. The 3rd stack item
|
||||
|
|
@ -131,6 +123,36 @@ func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, st
|
|||
}
|
||||
}
|
||||
}
|
||||
switch op {
|
||||
case DELEGATECALL:
|
||||
if !in.evm.chainRules.IsEIP7F {
|
||||
return fmt.Errorf("invalid opcode 0x%x", int(op))
|
||||
}
|
||||
case REVERT:
|
||||
if !in.evm.chainRules.IsEIP140F {
|
||||
return fmt.Errorf("invalid opcode 0x%x", int(op))
|
||||
}
|
||||
case STATICCALL:
|
||||
if !in.evm.chainRules.IsEIP214F {
|
||||
return fmt.Errorf("invalid opcode 0x%x", int(op))
|
||||
}
|
||||
case RETURNDATACOPY, RETURNDATASIZE:
|
||||
if !in.evm.chainRules.IsEIP211F {
|
||||
return fmt.Errorf("invalid opcode 0x%x", int(op))
|
||||
}
|
||||
case SHL, SHR, SAR:
|
||||
if !in.evm.chainRules.IsEIP145F {
|
||||
return fmt.Errorf("invalid opcode 0x%x", int(op))
|
||||
}
|
||||
case CREATE2:
|
||||
if !in.evm.chainRules.IsEIP1014F {
|
||||
return fmt.Errorf("invalid opcode 0x%x", int(op))
|
||||
}
|
||||
case EXTCODEHASH:
|
||||
if !in.evm.chainRules.IsEIP1052F {
|
||||
return fmt.Errorf("invalid opcode 0x%x", int(op))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -216,13 +238,13 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
if !operation.valid {
|
||||
return nil, fmt.Errorf("invalid opcode 0x%x", int(op))
|
||||
}
|
||||
if err := operation.validateStack(stack); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// If the operation is valid, enforce and write restrictions
|
||||
if err := in.enforceRestrictions(op, operation, stack); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := operation.validateStack(stack); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var memorySize uint64
|
||||
// calculate the new memory size and expand the memory to fit
|
||||
|
|
|
|||
|
|
@ -48,112 +48,13 @@ type operation struct {
|
|||
valid bool // indication whether the retrieved operation is valid and known
|
||||
reverts bool // determines whether the operation reverts state (implicitly halts)
|
||||
returns bool // determines whether the operations sets the return data content
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
frontierInstructionSet = newFrontierInstructionSet()
|
||||
homesteadInstructionSet = newHomesteadInstructionSet()
|
||||
byzantiumInstructionSet = newByzantiumInstructionSet()
|
||||
constantinopleInstructionSet = newConstantinopleInstructionSet()
|
||||
)
|
||||
var baseInstructionSet = newInstructionSet()
|
||||
|
||||
// NewConstantinopleInstructionSet returns the frontier, homestead
|
||||
// byzantium and contantinople instructions.
|
||||
func newConstantinopleInstructionSet() [256]operation {
|
||||
// instructions that can be executed during the byzantium phase.
|
||||
instructionSet := newByzantiumInstructionSet()
|
||||
instructionSet[SHL] = operation{
|
||||
execute: opSHL,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
}
|
||||
instructionSet[SHR] = operation{
|
||||
execute: opSHR,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
}
|
||||
instructionSet[SAR] = operation{
|
||||
execute: opSAR,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
}
|
||||
instructionSet[EXTCODEHASH] = operation{
|
||||
execute: opExtCodeHash,
|
||||
gasCost: gasExtCodeHash,
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
valid: true,
|
||||
}
|
||||
instructionSet[CREATE2] = operation{
|
||||
execute: opCreate2,
|
||||
gasCost: gasCreate2,
|
||||
validateStack: makeStackFunc(4, 1),
|
||||
memorySize: memoryCreate2,
|
||||
valid: true,
|
||||
writes: true,
|
||||
returns: true,
|
||||
}
|
||||
return instructionSet
|
||||
}
|
||||
|
||||
// NewByzantiumInstructionSet returns the frontier, homestead and
|
||||
// byzantium instructions.
|
||||
func newByzantiumInstructionSet() [256]operation {
|
||||
// instructions that can be executed during the homestead phase.
|
||||
instructionSet := newHomesteadInstructionSet()
|
||||
instructionSet[STATICCALL] = operation{
|
||||
execute: opStaticCall,
|
||||
gasCost: gasStaticCall,
|
||||
validateStack: makeStackFunc(6, 1),
|
||||
memorySize: memoryStaticCall,
|
||||
valid: true,
|
||||
returns: true,
|
||||
}
|
||||
instructionSet[RETURNDATASIZE] = operation{
|
||||
execute: opReturnDataSize,
|
||||
gasCost: constGasFunc(GasQuickStep),
|
||||
validateStack: makeStackFunc(0, 1),
|
||||
valid: true,
|
||||
}
|
||||
instructionSet[RETURNDATACOPY] = operation{
|
||||
execute: opReturnDataCopy,
|
||||
gasCost: gasReturnDataCopy,
|
||||
validateStack: makeStackFunc(3, 0),
|
||||
memorySize: memoryReturnDataCopy,
|
||||
valid: true,
|
||||
}
|
||||
instructionSet[REVERT] = operation{
|
||||
execute: opRevert,
|
||||
gasCost: gasRevert,
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
memorySize: memoryRevert,
|
||||
valid: true,
|
||||
reverts: true,
|
||||
returns: true,
|
||||
}
|
||||
return instructionSet
|
||||
}
|
||||
|
||||
// NewHomesteadInstructionSet returns the frontier and homestead
|
||||
// instructions that can be executed during the homestead phase.
|
||||
func newHomesteadInstructionSet() [256]operation {
|
||||
instructionSet := newFrontierInstructionSet()
|
||||
instructionSet[DELEGATECALL] = operation{
|
||||
execute: opDelegateCall,
|
||||
gasCost: gasDelegateCall,
|
||||
validateStack: makeStackFunc(6, 1),
|
||||
memorySize: memoryDelegateCall,
|
||||
valid: true,
|
||||
returns: true,
|
||||
}
|
||||
return instructionSet
|
||||
}
|
||||
|
||||
// NewFrontierInstructionSet returns the frontier instructions
|
||||
// that can be executed during the frontier phase.
|
||||
func newFrontierInstructionSet() [256]operation {
|
||||
// newInstructionSet returns all available instructions.
|
||||
func newInstructionSet() [256]operation {
|
||||
return [256]operation{
|
||||
STOP: {
|
||||
execute: opStop,
|
||||
|
|
@ -962,5 +863,92 @@ func newFrontierInstructionSet() [256]operation {
|
|||
valid: true,
|
||||
writes: true,
|
||||
},
|
||||
|
||||
// Homestead
|
||||
// EIP7
|
||||
DELEGATECALL: {
|
||||
execute: opDelegateCall,
|
||||
gasCost: gasDelegateCall,
|
||||
validateStack: makeStackFunc(6, 1),
|
||||
memorySize: memoryDelegateCall,
|
||||
valid: true,
|
||||
returns: true,
|
||||
},
|
||||
|
||||
// Byzantium
|
||||
// EIP140
|
||||
REVERT: {
|
||||
execute: opRevert,
|
||||
gasCost: gasRevert,
|
||||
validateStack: makeStackFunc(2, 0),
|
||||
memorySize: memoryRevert,
|
||||
valid: true,
|
||||
reverts: true,
|
||||
returns: true,
|
||||
},
|
||||
// EIP214
|
||||
STATICCALL: {
|
||||
execute: opStaticCall,
|
||||
gasCost: gasStaticCall,
|
||||
validateStack: makeStackFunc(6, 1),
|
||||
memorySize: memoryStaticCall,
|
||||
valid: true,
|
||||
returns: true,
|
||||
},
|
||||
// EIP211
|
||||
RETURNDATASIZE: {
|
||||
execute: opReturnDataSize,
|
||||
gasCost: constGasFunc(GasQuickStep),
|
||||
validateStack: makeStackFunc(0, 1),
|
||||
valid: true,
|
||||
},
|
||||
// EIP211
|
||||
RETURNDATACOPY: {
|
||||
execute: opReturnDataCopy,
|
||||
gasCost: gasReturnDataCopy,
|
||||
validateStack: makeStackFunc(3, 0),
|
||||
memorySize: memoryReturnDataCopy,
|
||||
valid: true,
|
||||
},
|
||||
|
||||
// Constantinople
|
||||
// EIP145
|
||||
SHL: {
|
||||
execute: opSHL,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
// EIP145
|
||||
SHR: {
|
||||
execute: opSHR,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
// EIP145
|
||||
SAR: {
|
||||
execute: opSAR,
|
||||
gasCost: constGasFunc(GasFastestStep),
|
||||
validateStack: makeStackFunc(2, 1),
|
||||
valid: true,
|
||||
},
|
||||
// EIP1014
|
||||
CREATE2: {
|
||||
execute: opCreate2,
|
||||
gasCost: gasCreate2,
|
||||
validateStack: makeStackFunc(4, 1),
|
||||
memorySize: memoryCreate2,
|
||||
valid: true,
|
||||
writes: true,
|
||||
returns: true,
|
||||
},
|
||||
// EIP1052
|
||||
EXTCODEHASH: {
|
||||
execute: opExtCodeHash,
|
||||
gasCost: gasExtCodeHash,
|
||||
validateStack: makeStackFunc(1, 1),
|
||||
valid: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -669,7 +669,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
|
|||
return nil, fmt.Errorf("processing block %d failed: %v", block.NumberU64(), err)
|
||||
}
|
||||
// Finalize the state so any modifications are written to the trie
|
||||
root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP158(block.Number()))
|
||||
root, err := statedb.Commit(api.eth.blockchain.Config().IsEIP161F(block.Number()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,7 +390,7 @@ func New(code string) (*Tracer, error) {
|
|||
return 1
|
||||
})
|
||||
tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int {
|
||||
_, ok := vm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))]
|
||||
_, ok := vm.AllPrecompiledContracts[common.BytesToAddress(popSlice(ctx))]
|
||||
ctx.PushBoolean(ok)
|
||||
return 1
|
||||
})
|
||||
|
|
|
|||
479
params/config.go
479
params/config.go
|
|
@ -111,16 +111,136 @@ var (
|
|||
//
|
||||
// This configuration is intentionally not using keyed fields to force anyone
|
||||
// adding flags to the config to also have to set these fields.
|
||||
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil}
|
||||
AllEthashProtocolChanges = &ChainConfig{
|
||||
big.NewInt(1337), // ChainID
|
||||
|
||||
big.NewInt(0), // HomesteadBlock
|
||||
nil, // EIP7FBlock
|
||||
|
||||
nil, // DAOForkBlock
|
||||
false, // DAOForkSupport
|
||||
|
||||
big.NewInt(0), // EIP150Block
|
||||
common.Hash{}, // EIP150Hash
|
||||
big.NewInt(0), // EIP155Block
|
||||
big.NewInt(0), // EIP158Block
|
||||
nil, // EIP160FBlock
|
||||
nil, // EIP161FBlock
|
||||
nil, // EIP170FBlock
|
||||
|
||||
big.NewInt(0), // ByzantiumBlock
|
||||
nil, // EIP100FBlock
|
||||
nil, // EIP140FBlock
|
||||
nil, // EIP198FBlock
|
||||
nil, // EIP211FBlock
|
||||
nil, // EIP212FBlock
|
||||
nil, // EIP213FBlock
|
||||
nil, // EIP214FBlock
|
||||
nil, // EIP649FBlock
|
||||
nil, // EIP658FBlock
|
||||
|
||||
big.NewInt(0), // ConstantinopleBlock
|
||||
nil, // EIP145FBlock
|
||||
nil, // EIP1014FBlock
|
||||
nil, // EIP1052FBlock
|
||||
nil, // EIP1234FBlock
|
||||
nil, // EIP1283FBlock
|
||||
|
||||
nil, // EWASMBlock
|
||||
new(EthashConfig), // Ethash
|
||||
nil, // Clique
|
||||
}
|
||||
|
||||
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
||||
// and accepted by the Ethereum core developers into the Clique consensus.
|
||||
//
|
||||
// This configuration is intentionally not using keyed fields to force anyone
|
||||
// adding flags to the config to also have to set these fields.
|
||||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
|
||||
AllCliqueProtocolChanges = &ChainConfig{
|
||||
big.NewInt(1337), // ChainID
|
||||
|
||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil}
|
||||
big.NewInt(0), // HomesteadBlock
|
||||
nil, // EIP7FBlock
|
||||
|
||||
nil, // DAOForkBlock
|
||||
false, // DAOForkSupport
|
||||
|
||||
big.NewInt(0), // EIP150Block
|
||||
common.Hash{}, // EIP150Hash
|
||||
big.NewInt(0), // EIP155Block
|
||||
big.NewInt(0), // EIP158Block
|
||||
nil, // EIP160FBlock
|
||||
nil, // EIP161FBlock
|
||||
nil, // EIP170FBlock
|
||||
|
||||
big.NewInt(0), // ByzantiumBlock
|
||||
nil, // EIP100FBlock
|
||||
nil, // EIP140FBlock
|
||||
nil, // EIP198FBlock
|
||||
nil, // EIP211FBlock
|
||||
nil, // EIP212FBlock
|
||||
nil, // EIP213FBlock
|
||||
nil, // EIP214FBlock
|
||||
nil, // EIP649FBlock
|
||||
nil, // EIP658FBlock
|
||||
|
||||
big.NewInt(0), // ConstantinopleBlock
|
||||
nil, // EIP145FBlock
|
||||
nil, // EIP1014FBlock
|
||||
nil, // EIP1052FBlock
|
||||
nil, // EIP1234FBlock
|
||||
nil, // EIP1283FBlock
|
||||
|
||||
nil, // EWASMBlock
|
||||
nil, // Ethash
|
||||
&CliqueConfig{
|
||||
Period: 0,
|
||||
Epoch: 30000,
|
||||
},
|
||||
}
|
||||
|
||||
// TestChainConfig is used for tests.
|
||||
TestChainConfig = &ChainConfig{
|
||||
big.NewInt(1), // ChainID
|
||||
|
||||
big.NewInt(0), // HomesteadBlock
|
||||
nil, // EIP7FBlock
|
||||
|
||||
nil, // DAOForkBlock
|
||||
false, // DAOForkSupport
|
||||
|
||||
big.NewInt(0), // EIP150Block
|
||||
common.Hash{}, // EIP150Hash
|
||||
big.NewInt(0), // EIP155Block
|
||||
big.NewInt(0), // EIP158Block
|
||||
nil, // EIP160FBlock
|
||||
nil, // EIP161FBlock
|
||||
nil, // EIP170FBlock
|
||||
|
||||
big.NewInt(0), // ByzantiumBlock
|
||||
nil, // EIP100FBlock
|
||||
nil, // EIP140FBlock
|
||||
nil, // EIP198FBlock
|
||||
nil, // EIP211FBlock
|
||||
nil, // EIP212FBlock
|
||||
nil, // EIP213FBlock
|
||||
nil, // EIP214FBlock
|
||||
nil, // EIP649FBlock
|
||||
nil, // EIP658FBlock
|
||||
|
||||
big.NewInt(0), // ConstantinopleBlock
|
||||
nil, // EIP145FBlock
|
||||
nil, // EIP1014FBlock
|
||||
nil, // EIP1052FBlock
|
||||
nil, // EIP1234FBlock
|
||||
nil, // EIP1283FBlock
|
||||
|
||||
nil, // EWASMBlock
|
||||
new(EthashConfig), // Ethash
|
||||
nil, // Clique
|
||||
}
|
||||
|
||||
// TestRules are all rules from TestChainConfig initialized at 0.
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
)
|
||||
|
||||
|
|
@ -144,20 +264,92 @@ type TrustedCheckpoint struct {
|
|||
type ChainConfig struct {
|
||||
ChainID *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection
|
||||
|
||||
// HF: Homestead
|
||||
HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead)
|
||||
// Note: EIPs 2 and 8 were also included in this fork, but have not been distinguished individually in the code.
|
||||
//
|
||||
// DELEGATECALL
|
||||
// https://eips.ethereum.org/EIPS/eip-7
|
||||
EIP7FBlock *big.Int `json:"eip7FBlock,omitempy"`
|
||||
|
||||
// HF: DAO
|
||||
DAOForkBlock *big.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork)
|
||||
DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork
|
||||
|
||||
// HF: Tangerine Whistle
|
||||
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
|
||||
EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork)
|
||||
EIP150Hash common.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed)
|
||||
|
||||
// HF: Spurious Dragon
|
||||
EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block
|
||||
EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block
|
||||
EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block, includes implementations of 158/161, 160, and 170
|
||||
//
|
||||
// EXP cost increase
|
||||
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-160.md
|
||||
EIP160FBlock *big.Int `json:"eip160FBlock,omitempty"`
|
||||
// State trie clearing (== EIP158 proper)
|
||||
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md
|
||||
EIP161FBlock *big.Int `json:"eip161FBlock,omitempty"`
|
||||
// Contract code size limit
|
||||
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-170.md
|
||||
EIP170FBlock *big.Int `json:"eip170FBlock,omitempty"`
|
||||
|
||||
// HF: Byzantium
|
||||
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
|
||||
//
|
||||
// Difficulty adjustment to target mean block time including uncles
|
||||
// https://github.com/ethereum/EIPs/issues/100
|
||||
EIP100FBlock *big.Int `json:"eip100FBlock,omitempty"`
|
||||
// Opcode REVERT
|
||||
// https://eips.ethereum.org/EIPS/eip-140
|
||||
EIP140FBlock *big.Int `json:"eip140FBlock,omitempty"`
|
||||
// Precompiled contract for bigint_modexp
|
||||
// https://github.com/ethereum/EIPs/issues/198
|
||||
EIP198FBlock *big.Int `json:"eip198FBlock,omitempty"`
|
||||
// Opcodes RETURNDATACOPY, RETURNDATASIZE
|
||||
// https://github.com/ethereum/EIPs/issues/211
|
||||
EIP211FBlock *big.Int `json:"eip211FBlock,omitempty"`
|
||||
// Precompiled contract for pairing check
|
||||
// https://github.com/ethereum/EIPs/issues/212
|
||||
EIP212FBlock *big.Int `json:"eip212FBlock,omitempty"`
|
||||
// Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128
|
||||
// https://github.com/ethereum/EIPs/issues/213
|
||||
EIP213FBlock *big.Int `json:"eip213FBlock,omitempty"`
|
||||
// Opcode STATICCALL
|
||||
// https://github.com/ethereum/EIPs/issues/214
|
||||
EIP214FBlock *big.Int `json:"eip214FBlock,omitempty"`
|
||||
// Metropolis diff bomb delay and reducing block reward
|
||||
// https://github.com/ethereum/EIPs/issues/649
|
||||
// note that this is closely related to EIP100.
|
||||
// In fact, EIP100 is bundled in
|
||||
EIP649FBlock *big.Int `json:"eip649FBlock,omitempty"`
|
||||
// Transaction receipt status
|
||||
// https://github.com/ethereum/EIPs/issues/658
|
||||
EIP658FBlock *big.Int `json:"eip658FBlock,omitempty"`
|
||||
// NOT CONFIGURABLE: prevent overwriting contracts
|
||||
// https://github.com/ethereum/EIPs/issues/684
|
||||
// EIP684FBlock *big.Int `json:"eip684BFlock,omitempty"`
|
||||
|
||||
// HF: Constantinople
|
||||
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
|
||||
//
|
||||
// Opcodes SHR, SHL, SAR
|
||||
// https://eips.ethereum.org/EIPS/eip-145
|
||||
EIP145FBlock *big.Int `json:"eip145FBlock,omitempty"`
|
||||
// Opcode CREATE2
|
||||
// https://eips.ethereum.org/EIPS/eip-1014
|
||||
EIP1014FBlock *big.Int `json:"eip1014FBlock,omitempty"`
|
||||
// Opcode EXTCODEHASH
|
||||
// https://eips.ethereum.org/EIPS/eip-1052
|
||||
EIP1052FBlock *big.Int `json:"eip1052FBlock,omitempty"`
|
||||
// Constantinople difficulty bomb delay and block reward adjustment
|
||||
// https://eips.ethereum.org/EIPS/eip-1234
|
||||
EIP1234FBlock *big.Int `json:"eip1234FBlock,omitempty"`
|
||||
// Net gas metering
|
||||
// https://eips.ethereum.org/EIPS/eip-1283
|
||||
EIP1283FBlock *big.Int `json:"eip1283FBlock,omitempty"`
|
||||
|
||||
EWASMBlock *big.Int `json:"ewasmBlock,omitempty"` // EWASM switch block (nil = no fork, 0 = already activated)
|
||||
|
||||
// Various consensus engines
|
||||
|
|
@ -214,6 +406,11 @@ func (c *ChainConfig) IsHomestead(num *big.Int) bool {
|
|||
return isForked(c.HomesteadBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP7F returns whether num is equal to or greater than the Homestead or EIP7 block.
|
||||
func (c *ChainConfig) IsEIP7F(num *big.Int) bool {
|
||||
return c.IsHomestead(num) || isForked(c.EIP7FBlock, num)
|
||||
}
|
||||
|
||||
// IsDAOFork returns whether num is either equal to the DAO fork block or greater.
|
||||
func (c *ChainConfig) IsDAOFork(num *big.Int) bool {
|
||||
return isForked(c.DAOForkBlock, num)
|
||||
|
|
@ -229,19 +426,167 @@ func (c *ChainConfig) IsEIP155(num *big.Int) bool {
|
|||
return isForked(c.EIP155Block, num)
|
||||
}
|
||||
|
||||
// IsEIP158 returns whether num is either equal to the EIP158 fork block or greater.
|
||||
func (c *ChainConfig) IsEIP158(num *big.Int) bool {
|
||||
return isForked(c.EIP158Block, num)
|
||||
// EIP158HFFBlocks returns the canonical EIP blocks configured for the implemented EIP158HF fork,
|
||||
// a subset of features introduced at the Spurious Dragon fork.
|
||||
func (c *ChainConfig) EIP158HFFBlocks() []*big.Int {
|
||||
return []*big.Int{
|
||||
c.EIP160FBlock,
|
||||
c.EIP161FBlock,
|
||||
c.EIP170FBlock,
|
||||
}
|
||||
}
|
||||
|
||||
// IsByzantium returns whether num is either equal to the Byzantium fork block or greater.
|
||||
// IsEIP158HF returns whether num is either equal to the "EIP158 Hardfork"
|
||||
// (an implemented-in-code subset of the Spurious Dragon hard-fork) block or greater.
|
||||
func (c *ChainConfig) IsEIP158HF(num *big.Int) bool {
|
||||
return isForked(c.EIP158Block, num) || func(n *big.Int) bool {
|
||||
blocks := c.EIP158HFFBlocks()
|
||||
for i := range blocks {
|
||||
if !isForked(blocks[i], n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}(num)
|
||||
}
|
||||
|
||||
// IsEIP160F returns whether num is either equal to or greater than the "EIP158HF" Block or EIP160 block.
|
||||
func (c *ChainConfig) IsEIP160F(num *big.Int) bool {
|
||||
return c.IsEIP158HF(num) || isForked(c.EIP160FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP161F returns whether num is either equal to or greater than the "EIP158HF" Block or EIP161 block.
|
||||
func (c *ChainConfig) IsEIP161F(num *big.Int) bool {
|
||||
return c.IsEIP158HF(num) || isForked(c.EIP161FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP170F returns whether num is either equal to or greater than the "EIP158HF" Block or EIP170 block.
|
||||
func (c *ChainConfig) IsEIP170F(num *big.Int) bool {
|
||||
return c.IsEIP158HF(num) || isForked(c.EIP170FBlock, num)
|
||||
}
|
||||
|
||||
//ByzantiumEIPFBlocks returns the canonical EIP blocks configured for the Byzantium Fork.
|
||||
func (c *ChainConfig) ByzantiumEIPFBlocks() []*big.Int {
|
||||
return []*big.Int{
|
||||
c.EIP100FBlock,
|
||||
c.EIP140FBlock,
|
||||
c.EIP198FBlock,
|
||||
c.EIP211FBlock,
|
||||
c.EIP212FBlock,
|
||||
c.EIP213FBlock,
|
||||
c.EIP214FBlock,
|
||||
c.EIP649FBlock,
|
||||
c.EIP658FBlock,
|
||||
}
|
||||
}
|
||||
|
||||
// IsByzantium returns whether num is either equal to the Byzantium fork block or greater,
|
||||
// or whether the configured params satisfy all requirements fulfilling the Byzantium fork.
|
||||
func (c *ChainConfig) IsByzantium(num *big.Int) bool {
|
||||
return isForked(c.ByzantiumBlock, num)
|
||||
return isForked(c.ByzantiumBlock, num) || func(n *big.Int) bool {
|
||||
blocks := c.ByzantiumEIPFBlocks()
|
||||
for i := range blocks {
|
||||
if !isForked(blocks[i], n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}(num)
|
||||
}
|
||||
|
||||
// IsConstantinople returns whether num is either equal to the Constantinople fork block or greater.
|
||||
// IsEIP100F returns whether num is equal to or greater than the Byzantium or EIP100 block.
|
||||
func (c *ChainConfig) IsEIP100F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP100FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP140F returns whether num is equal to or greater than the Byzantium or EIP140 block.
|
||||
func (c *ChainConfig) IsEIP140F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP140FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP198F returns whether num is equal to or greater than the Byzantium or EIP198 block.
|
||||
func (c *ChainConfig) IsEIP198F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP198FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP211F returns whether num is equal to or greater than the Byzantium or EIP211 block.
|
||||
func (c *ChainConfig) IsEIP211F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP211FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP212F returns whether num is equal to or greater than the Byzantium or EIP212 block.
|
||||
func (c *ChainConfig) IsEIP212F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP212FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP213F returns whether num is equal to or greater than the Byzantium or EIP213 block.
|
||||
func (c *ChainConfig) IsEIP213F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP213FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP214F returns whether num is equal to or greater than the Byzantium or EIP214 block.
|
||||
func (c *ChainConfig) IsEIP214F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP214FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP649F returns whether num is equal to or greater than the Byzantium or EIP649 block.
|
||||
func (c *ChainConfig) IsEIP649F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP649FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP658F returns whether num is equal to or greater than the Byzantium or EIP658 block.
|
||||
func (c *ChainConfig) IsEIP658F(num *big.Int) bool {
|
||||
return c.IsByzantium(num) || isForked(c.EIP658FBlock, num)
|
||||
}
|
||||
|
||||
// ConstantinopleEIPFBlocks returns the canonical blocks configured for the Constantinople Fork.
|
||||
func (c *ChainConfig) ConstantinopleEIPFBlocks() []*big.Int {
|
||||
return []*big.Int{
|
||||
c.EIP145FBlock,
|
||||
c.EIP1014FBlock,
|
||||
c.EIP1052FBlock,
|
||||
c.EIP1234FBlock,
|
||||
c.EIP1283FBlock,
|
||||
}
|
||||
}
|
||||
|
||||
// IsConstantinople returns whether num is either equal to the Constantinople fork block or greater,
|
||||
// or whether configured params satisfy all requirements fulfilling the Constantinople fork.
|
||||
func (c *ChainConfig) IsConstantinople(num *big.Int) bool {
|
||||
return isForked(c.ConstantinopleBlock, num)
|
||||
return isForked(c.ConstantinopleBlock, num) || func(n *big.Int) bool {
|
||||
blocks := c.ConstantinopleEIPFBlocks()
|
||||
for i := range blocks {
|
||||
if !isForked(blocks[i], n) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}(num)
|
||||
}
|
||||
|
||||
// IsEIP145F returns whether num is equal to or greater than the Constantinople or EIP145 block.
|
||||
func (c *ChainConfig) IsEIP145F(num *big.Int) bool {
|
||||
return c.IsConstantinople(num) || isForked(c.EIP145FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP1014F returns whether num is equal to or greater than the Constantinople or EIP1014 block.
|
||||
func (c *ChainConfig) IsEIP1014F(num *big.Int) bool {
|
||||
return c.IsConstantinople(num) || isForked(c.EIP1014FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP1052F returns whether num is equal to or greater than the Constantinople or EIP1052 block.
|
||||
func (c *ChainConfig) IsEIP1052F(num *big.Int) bool {
|
||||
return c.IsConstantinople(num) || isForked(c.EIP1052FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP1234F returns whether num is equal to or greater than the Constantinople or EIP1234 block.
|
||||
func (c *ChainConfig) IsEIP1234F(num *big.Int) bool {
|
||||
return c.IsConstantinople(num) || isForked(c.EIP1234FBlock, num)
|
||||
}
|
||||
|
||||
// IsEIP1283F returns whether num is equal to or greater than the Constantinople or EIP1283 block.
|
||||
func (c *ChainConfig) IsEIP1283F(num *big.Int) bool {
|
||||
return c.IsConstantinople(num) || isForked(c.EIP1283FBlock, num)
|
||||
}
|
||||
|
||||
// IsEWASM returns whether num represents a block number after the EWASM fork
|
||||
|
|
@ -249,7 +594,7 @@ func (c *ChainConfig) IsEWASM(num *big.Int) bool {
|
|||
return isForked(c.EWASMBlock, num)
|
||||
}
|
||||
|
||||
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
|
||||
// GasTable returns the gas table corresponding to the current phase.
|
||||
//
|
||||
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
|
||||
func (c *ChainConfig) GasTable(num *big.Int) GasTable {
|
||||
|
|
@ -257,10 +602,10 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable {
|
|||
return GasTableHomestead
|
||||
}
|
||||
switch {
|
||||
case c.IsConstantinople(num):
|
||||
return GasTableConstantinople
|
||||
case c.IsEIP158(num):
|
||||
return GasTableEIP158
|
||||
case c.IsEIP1052F(num):
|
||||
return GasTableEIP1052
|
||||
case c.IsEIP160F(num):
|
||||
return GasTableEIP160
|
||||
case c.IsEIP150(num):
|
||||
return GasTableEIP150
|
||||
default:
|
||||
|
|
@ -287,36 +632,66 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *Confi
|
|||
}
|
||||
|
||||
func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
|
||||
if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
|
||||
return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
|
||||
for _, ch := range []struct {
|
||||
name string
|
||||
c1, c2 *big.Int
|
||||
}{
|
||||
{"Homestead", c.HomesteadBlock, newcfg.HomesteadBlock},
|
||||
{"EIP7F", c.EIP7FBlock, newcfg.EIP7FBlock},
|
||||
{"DAO", c.DAOForkBlock, newcfg.DAOForkBlock},
|
||||
{"EIP150", c.EIP150Block, newcfg.EIP150Block},
|
||||
{"EIP155", c.EIP155Block, newcfg.EIP155Block},
|
||||
{"EIP158", c.EIP158Block, newcfg.EIP158Block},
|
||||
{"EIP160F", c.EIP160FBlock, newcfg.EIP160FBlock},
|
||||
{"EIP161F", c.EIP161FBlock, newcfg.EIP161FBlock},
|
||||
{"EIP170F", c.EIP170FBlock, newcfg.EIP170FBlock},
|
||||
{"Byzantium", c.ByzantiumBlock, newcfg.ByzantiumBlock},
|
||||
{"EIP100F", c.EIP100FBlock, newcfg.EIP100FBlock},
|
||||
{"EIP140F", c.EIP140FBlock, newcfg.EIP140FBlock},
|
||||
{"EIP198F", c.EIP198FBlock, newcfg.EIP198FBlock},
|
||||
{"EIP211F", c.EIP211FBlock, newcfg.EIP211FBlock},
|
||||
{"EIP212F", c.EIP212FBlock, newcfg.EIP212FBlock},
|
||||
{"EIP213F", c.EIP213FBlock, newcfg.EIP213FBlock},
|
||||
{"EIP214F", c.EIP214FBlock, newcfg.EIP214FBlock},
|
||||
{"EIP649F", c.EIP649FBlock, newcfg.EIP649FBlock},
|
||||
{"EIP658F", c.EIP658FBlock, newcfg.EIP658FBlock},
|
||||
{"Constantinople", c.ConstantinopleBlock, newcfg.ConstantinopleBlock},
|
||||
{"EIP145F", c.EIP145FBlock, newcfg.EIP145FBlock},
|
||||
{"EIP1014F", c.EIP1014FBlock, newcfg.EIP1014FBlock},
|
||||
{"EIP1052F", c.EIP1052FBlock, newcfg.EIP1052FBlock},
|
||||
{"EIP1234F", c.EIP1234FBlock, newcfg.EIP1234FBlock},
|
||||
{"EIP1283F", c.EIP1283FBlock, newcfg.EIP1283FBlock},
|
||||
{"EWASM", c.EWASMBlock, newcfg.EWASMBlock},
|
||||
} {
|
||||
if err := func(c1, c2, head *big.Int) *ConfigCompatError {
|
||||
if isForkIncompatible(ch.c1, ch.c2, head) {
|
||||
return newCompatError(ch.name+" fork block", ch.c1, ch.c2)
|
||||
}
|
||||
if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) {
|
||||
return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock)
|
||||
return nil
|
||||
}(ch.c1, ch.c2, head); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c.IsDAOFork(head) && c.DAOForkSupport != newcfg.DAOForkSupport {
|
||||
return newCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock)
|
||||
}
|
||||
if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) {
|
||||
return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block)
|
||||
if c.IsEIP155(head) && !configNumEqual(c.ChainID, newcfg.ChainID) {
|
||||
return newCompatError("EIP155 chain ID", c.EIP155Block, newcfg.EIP155Block)
|
||||
}
|
||||
if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
|
||||
return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block)
|
||||
// Either Byzantium block must be set OR EIP100 and EIP649 must be equivalent
|
||||
if newcfg.ByzantiumBlock == nil {
|
||||
if !configNumEqual(newcfg.EIP100FBlock, newcfg.EIP649FBlock) {
|
||||
return newCompatError("EIP100F/EIP649F not equal", newcfg.EIP100FBlock, newcfg.EIP649FBlock)
|
||||
}
|
||||
if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) {
|
||||
return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block)
|
||||
if isForkIncompatible(c.EIP100FBlock, newcfg.EIP649FBlock, head) {
|
||||
return newCompatError("EIP100F/EIP649F fork block", c.EIP100FBlock, newcfg.EIP649FBlock)
|
||||
}
|
||||
if c.IsEIP158(head) && !configNumEqual(c.ChainID, newcfg.ChainID) {
|
||||
return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block)
|
||||
if isForkIncompatible(c.EIP649FBlock, newcfg.EIP100FBlock, head) {
|
||||
return newCompatError("EIP649F/EIP100F fork block", c.EIP649FBlock, newcfg.EIP100FBlock)
|
||||
}
|
||||
if isForkIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) {
|
||||
return newCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock)
|
||||
}
|
||||
if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
|
||||
return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
|
||||
}
|
||||
if isForkIncompatible(c.EWASMBlock, newcfg.EWASMBlock, head) {
|
||||
return newCompatError("ewasm fork block", c.EWASMBlock, newcfg.EWASMBlock)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -382,8 +757,12 @@ func (err *ConfigCompatError) Error() string {
|
|||
// phases.
|
||||
type Rules struct {
|
||||
ChainID *big.Int
|
||||
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
|
||||
IsByzantium, IsConstantinople bool
|
||||
IsHomestead, IsEIP7F bool
|
||||
IsEIP150 bool
|
||||
IsEIP155 bool
|
||||
IsEIP158HF, IsEIP160F, IsEIP161F, IsEIP170F bool
|
||||
IsByzantium, IsEIP100F, IsEIP140F, IsEIP198F, IsEIP211F, IsEIP212F, IsEIP213F, IsEIP214F, IsEIP649F, IsEIP658F bool
|
||||
IsConstantinople, IsEIP145F, IsEIP1014F, IsEIP1052F, IsEIP1283F, IsEIP1234F bool
|
||||
}
|
||||
|
||||
// Rules ensures c's ChainID is not nil.
|
||||
|
|
@ -394,11 +773,33 @@ func (c *ChainConfig) Rules(num *big.Int) Rules {
|
|||
}
|
||||
return Rules{
|
||||
ChainID: new(big.Int).Set(chainID),
|
||||
|
||||
IsHomestead: c.IsHomestead(num),
|
||||
IsEIP7F: c.IsEIP7F(num),
|
||||
|
||||
IsEIP150: c.IsEIP150(num),
|
||||
IsEIP155: c.IsEIP155(num),
|
||||
IsEIP158: c.IsEIP158(num),
|
||||
IsEIP158HF: c.IsEIP158HF(num),
|
||||
IsEIP160F: c.IsEIP160F(num),
|
||||
IsEIP161F: c.IsEIP161F(num),
|
||||
IsEIP170F: c.IsEIP170F(num),
|
||||
|
||||
IsByzantium: c.IsByzantium(num),
|
||||
IsEIP100F: c.IsEIP100F(num),
|
||||
IsEIP140F: c.IsEIP140F(num),
|
||||
IsEIP198F: c.IsEIP198F(num),
|
||||
IsEIP211F: c.IsEIP211F(num),
|
||||
IsEIP212F: c.IsEIP212F(num),
|
||||
IsEIP213F: c.IsEIP213F(num),
|
||||
IsEIP214F: c.IsEIP214F(num),
|
||||
IsEIP649F: c.IsEIP649F(num),
|
||||
IsEIP658F: c.IsEIP658F(num),
|
||||
|
||||
IsConstantinople: c.IsConstantinople(num),
|
||||
IsEIP145F: c.IsEIP145F(num),
|
||||
IsEIP1014F: c.IsEIP1014F(num),
|
||||
IsEIP1052F: c.IsEIP1052F(num),
|
||||
IsEIP1234F: c.IsEIP1234F(num),
|
||||
IsEIP1283F: c.IsEIP1283F(num),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,107 @@ import (
|
|||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// Test HF::EIPs boolean logic
|
||||
func TestIsByzantiumAndAssociatedEIPFFns(t *testing.T) {
|
||||
blocksWantsAroundFork := func(forkBlock *big.Int) (blocks []*big.Int, wants []bool) {
|
||||
blocks, wants = append(blocks, forkBlock), append(wants, forkBlock != nil)
|
||||
if forkBlock == nil {
|
||||
blocks, wants = append(blocks, big.NewInt(0)), append(wants, false)
|
||||
blocks, wants = append(blocks, big.NewInt(42)), append(wants, false)
|
||||
return
|
||||
}
|
||||
blocks, wants = append(blocks, new(big.Int).Sub(forkBlock, common.Big1)), append(wants, false)
|
||||
blocks, wants = append(blocks, new(big.Int).Add(forkBlock, common.Big1)), append(wants, true)
|
||||
return
|
||||
}
|
||||
|
||||
c := &ChainConfig{}
|
||||
*c = *MainnetChainConfig
|
||||
blocks, wants := blocksWantsAroundFork(c.ByzantiumBlock)
|
||||
for i, b := range blocks {
|
||||
if c.IsByzantium(b) != wants[i] {
|
||||
t.Errorf("i: %d, b: %v, got: %v, want: %v", i, b, c.IsByzantium(b), wants[i])
|
||||
}
|
||||
// Show that Byzantium's EIP<N>F block methods imply Byzantium block presence
|
||||
for j, fn := range []func(*big.Int) bool{
|
||||
c.IsEIP100F,
|
||||
c.IsEIP140F,
|
||||
c.IsEIP198F,
|
||||
c.IsEIP211F,
|
||||
c.IsEIP212F,
|
||||
c.IsEIP213F,
|
||||
c.IsEIP214F,
|
||||
c.IsEIP649F,
|
||||
c.IsEIP658F,
|
||||
} {
|
||||
if fn(b) != c.IsByzantium(b) {
|
||||
t.Errorf("j: %d, b: %v, got: %v, want: %v", j, b, fn(b), c.IsByzantium(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show that presence of all Byzantium's EIP<N>F blocks alone satisfy IsByzantium fn
|
||||
c.EIP100FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.EIP140FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.EIP198FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.EIP211FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.EIP212FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.EIP213FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.EIP214FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.EIP649FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.EIP658FBlock = new(big.Int).Set(c.ByzantiumBlock)
|
||||
c.ByzantiumBlock = nil
|
||||
for i, b := range blocks {
|
||||
if c.IsByzantium(b) != wants[i] {
|
||||
t.Errorf("i: %d, b: %v, got: %v, want: %v", i, b, c.IsByzantium(b), wants[i])
|
||||
}
|
||||
for j, fn := range []func(*big.Int) bool{
|
||||
c.IsEIP100F,
|
||||
c.IsEIP140F,
|
||||
c.IsEIP198F,
|
||||
c.IsEIP211F,
|
||||
c.IsEIP212F,
|
||||
c.IsEIP213F,
|
||||
c.IsEIP214F,
|
||||
c.IsEIP649F,
|
||||
c.IsEIP658F,
|
||||
} {
|
||||
if fn(b) != c.IsByzantium(b) {
|
||||
t.Errorf("j: %d, b: %v, got: %v, want: %v", j, b, fn(b), c.IsByzantium(b))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show that ALL EIP<N>F blocks must be set in order to be sufficiently "Byzantium"
|
||||
c.EIP658FBlock = nil
|
||||
for i, b := range blocks {
|
||||
if c.IsByzantium(b) {
|
||||
t.Errorf("i: %d, b: %v, got: %v, want: %v", i, b, c.IsByzantium(b), wants[i])
|
||||
}
|
||||
for j, fn := range []func(*big.Int) bool{
|
||||
c.IsEIP100F,
|
||||
c.IsEIP140F,
|
||||
c.IsEIP198F,
|
||||
c.IsEIP211F,
|
||||
c.IsEIP212F,
|
||||
c.IsEIP213F,
|
||||
c.IsEIP214F,
|
||||
c.IsEIP649F,
|
||||
} {
|
||||
if fn(b) != wants[i] {
|
||||
t.Errorf("j: %d, b: %v, got: %v, want: %v", j, b, fn(b), wants[i])
|
||||
}
|
||||
}
|
||||
if c.IsEIP658F(b) {
|
||||
t.Errorf("got: %v, want: %v", c.IsEIP658F(b), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckCompatible(t *testing.T) {
|
||||
type test struct {
|
||||
stored, new *ChainConfig
|
||||
|
|
@ -70,6 +169,83 @@ func TestCheckCompatible(t *testing.T) {
|
|||
RewindTo: 9,
|
||||
},
|
||||
},
|
||||
{
|
||||
stored: &ChainConfig{EIP100FBlock: big.NewInt(30), EIP649FBlock: big.NewInt(31)},
|
||||
new: &ChainConfig{EIP100FBlock: big.NewInt(30), EIP649FBlock: big.NewInt(31)},
|
||||
head: 25,
|
||||
wantErr: &ConfigCompatError{
|
||||
What: "EIP100F/EIP649F not equal",
|
||||
StoredConfig: big.NewInt(30),
|
||||
NewConfig: big.NewInt(31),
|
||||
RewindTo: 29,
|
||||
},
|
||||
},
|
||||
{
|
||||
stored: &ChainConfig{EIP100FBlock: big.NewInt(30), EIP649FBlock: big.NewInt(30)},
|
||||
new: &ChainConfig{EIP100FBlock: big.NewInt(24), EIP649FBlock: big.NewInt(24)},
|
||||
head: 25,
|
||||
wantErr: &ConfigCompatError{
|
||||
What: "EIP100F fork block",
|
||||
StoredConfig: big.NewInt(30),
|
||||
NewConfig: big.NewInt(24),
|
||||
RewindTo: 23,
|
||||
},
|
||||
},
|
||||
{
|
||||
stored: &ChainConfig{ByzantiumBlock: big.NewInt(30)},
|
||||
new: &ChainConfig{EIP211FBlock: big.NewInt(26)},
|
||||
head: 25,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
stored: &ChainConfig{ByzantiumBlock: big.NewInt(30)},
|
||||
new: &ChainConfig{EIP100FBlock: big.NewInt(26)}, // err: EIP649 must also be set
|
||||
head: 25,
|
||||
wantErr: &ConfigCompatError{
|
||||
What: "EIP100F/EIP649F not equal",
|
||||
StoredConfig: big.NewInt(26), // this yields a weird-looking error (correctly, though), b/c ConfigCompatError not set up for these kinds of strange cases
|
||||
NewConfig: nil,
|
||||
RewindTo: 25,
|
||||
},
|
||||
},
|
||||
{
|
||||
stored: &ChainConfig{ByzantiumBlock: big.NewInt(30)},
|
||||
new: &ChainConfig{EIP100FBlock: big.NewInt(26), EIP649FBlock: big.NewInt(26)},
|
||||
head: 25,
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
stored: MainnetChainConfig,
|
||||
new: func() *ChainConfig {
|
||||
c := &ChainConfig{}
|
||||
*c = *MainnetChainConfig
|
||||
c.DAOForkSupport = !MainnetChainConfig.DAOForkSupport
|
||||
return c
|
||||
}(),
|
||||
head: MainnetChainConfig.DAOForkBlock.Uint64(),
|
||||
wantErr: &ConfigCompatError{
|
||||
What: "DAO fork support flag",
|
||||
StoredConfig: MainnetChainConfig.DAOForkBlock,
|
||||
NewConfig: MainnetChainConfig.DAOForkBlock,
|
||||
RewindTo: new(big.Int).Sub(MainnetChainConfig.DAOForkBlock, common.Big1).Uint64(),
|
||||
},
|
||||
},
|
||||
{
|
||||
stored: MainnetChainConfig,
|
||||
new: func() *ChainConfig {
|
||||
c := &ChainConfig{}
|
||||
*c = *MainnetChainConfig
|
||||
c.ChainID = new(big.Int).Sub(MainnetChainConfig.EIP155Block, common.Big1)
|
||||
return c
|
||||
}(),
|
||||
head: MainnetChainConfig.EIP158Block.Uint64(),
|
||||
wantErr: &ConfigCompatError{
|
||||
What: "EIP155 chain ID",
|
||||
StoredConfig: MainnetChainConfig.EIP155Block,
|
||||
NewConfig: MainnetChainConfig.EIP155Block,
|
||||
RewindTo: new(big.Int).Sub(MainnetChainConfig.EIP158Block, common.Big1).Uint64(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ var (
|
|||
|
||||
CreateBySuicide: 25000,
|
||||
}
|
||||
// GasTableEIP158 contain the gas re-prices for
|
||||
// GasTableEIP160 contain the gas re-prices for
|
||||
// the EIP155/EIP158 phase.
|
||||
GasTableEIP158 = GasTable{
|
||||
GasTableEIP160 = GasTable{
|
||||
ExtcodeSize: 700,
|
||||
ExtcodeCopy: 700,
|
||||
Balance: 400,
|
||||
|
|
@ -76,9 +76,9 @@ var (
|
|||
|
||||
CreateBySuicide: 25000,
|
||||
}
|
||||
// GasTableConstantinople contain the gas re-prices for
|
||||
// GasTableEIP1052 contain the gas re-prices for
|
||||
// the constantinople phase.
|
||||
GasTableConstantinople = GasTable{
|
||||
GasTableEIP1052 = GasTable{
|
||||
ExtcodeSize: 700,
|
||||
ExtcodeCopy: 700,
|
||||
ExtcodeHash: 400,
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD
|
|||
statedb.RevertToSnapshot(snapshot)
|
||||
}
|
||||
// Commit block
|
||||
statedb.Commit(config.IsEIP158(block.Number()))
|
||||
statedb.Commit(config.IsEIP161F(block.Number()))
|
||||
// Add 0-value mining reward. This only makes a difference in the cases
|
||||
// where
|
||||
// - the coinbase suicided, or
|
||||
|
|
@ -152,7 +152,7 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD
|
|||
// the coinbase gets no txfee, so isn't created, and thus needs to be touched
|
||||
statedb.AddBalance(block.Coinbase(), new(big.Int))
|
||||
// And _now_ get the state root
|
||||
root := statedb.IntermediateRoot(config.IsEIP158(block.Number()))
|
||||
root := statedb.IntermediateRoot(config.IsEIP161F(block.Number()))
|
||||
// N.B: We need to do this in a two-step process, because the first Commit takes care
|
||||
// of suicides, and we need to touch the coinbase _after_ it has potentially suicided.
|
||||
if root != common.Hash(post.Root) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue