forked from cerc-io/plugeth
Merge pull request #15028 from karalabe/metropolis-iceage
consensus, core, tests: implement Metropolis EIP 649
This commit is contained in:
commit
27a5622e99
@ -36,7 +36,8 @@ import (
|
|||||||
|
|
||||||
// Ethash proof-of-work protocol constants.
|
// Ethash proof-of-work protocol constants.
|
||||||
var (
|
var (
|
||||||
blockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
|
frontierBlockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
|
||||||
|
metropolisBlockReward *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Metropolis
|
||||||
maxUncles = 2 // Maximum number of uncles allowed in a single block
|
maxUncles = 2 // Maximum number of uncles allowed in a single block
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -306,6 +307,7 @@ var (
|
|||||||
big9 = big.NewInt(9)
|
big9 = big.NewInt(9)
|
||||||
big10 = big.NewInt(10)
|
big10 = big.NewInt(10)
|
||||||
bigMinus99 = big.NewInt(-99)
|
bigMinus99 = big.NewInt(-99)
|
||||||
|
big2999999 = big.NewInt(2999999)
|
||||||
)
|
)
|
||||||
|
|
||||||
// calcDifficultyMetropolis is the difficulty adjustment algorithm. It returns
|
// calcDifficultyMetropolis is the difficulty adjustment algorithm. It returns
|
||||||
@ -346,8 +348,15 @@ func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int {
|
|||||||
if x.Cmp(params.MinimumDifficulty) < 0 {
|
if x.Cmp(params.MinimumDifficulty) < 0 {
|
||||||
x.Set(params.MinimumDifficulty)
|
x.Set(params.MinimumDifficulty)
|
||||||
}
|
}
|
||||||
|
// calculate a fake block numer for the ice-age delay:
|
||||||
|
// https://github.com/ethereum/EIPs/pull/669
|
||||||
|
// fake_block_number = min(0, block.number - 3_000_000
|
||||||
|
fakeBlockNumber := new(big.Int)
|
||||||
|
if parent.Number.Cmp(big2999999) >= 0 {
|
||||||
|
fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, big2999999) // Note, parent is 1 less than the actual block number
|
||||||
|
}
|
||||||
// for the exponential factor
|
// for the exponential factor
|
||||||
periodCount := new(big.Int).Add(parent.Number, big1)
|
periodCount := fakeBlockNumber
|
||||||
periodCount.Div(periodCount, expDiffPeriod)
|
periodCount.Div(periodCount, expDiffPeriod)
|
||||||
|
|
||||||
// the exponential factor, commonly referred to as "the bomb"
|
// the exponential factor, commonly referred to as "the bomb"
|
||||||
@ -501,7 +510,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header)
|
|||||||
// setting the final state and assembling the block.
|
// setting the final state and assembling the block.
|
||||||
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) {
|
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
|
// Accumulate any block and uncle rewards and commit the final state root
|
||||||
AccumulateRewards(state, header, uncles)
|
AccumulateRewards(chain.Config(), state, header, uncles)
|
||||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||||
|
|
||||||
// Header seems complete, assemble into a block and return
|
// Header seems complete, assemble into a block and return
|
||||||
@ -518,7 +527,13 @@ var (
|
|||||||
// reward. The total reward consists of the static block reward and rewards for
|
// reward. The total reward consists of the static block reward and rewards for
|
||||||
// included uncles. The coinbase of each uncle block is also rewarded.
|
// included uncles. The coinbase of each uncle block is also rewarded.
|
||||||
// TODO (karalabe): Move the chain maker into this package and make this private!
|
// TODO (karalabe): Move the chain maker into this package and make this private!
|
||||||
func AccumulateRewards(state *state.StateDB, header *types.Header, uncles []*types.Header) {
|
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.IsMetropolis(header.Number) {
|
||||||
|
blockReward = metropolisBlockReward
|
||||||
|
}
|
||||||
|
// Accumulate the rewards for the miner and any included uncles
|
||||||
reward := new(big.Int).Set(blockReward)
|
reward := new(big.Int).Set(blockReward)
|
||||||
r := new(big.Int)
|
r := new(big.Int)
|
||||||
for _, uncle := range uncles {
|
for _, uncle := range uncles {
|
||||||
|
@ -179,7 +179,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Dat
|
|||||||
if gen != nil {
|
if gen != nil {
|
||||||
gen(i, b)
|
gen(i, b)
|
||||||
}
|
}
|
||||||
ethash.AccumulateRewards(statedb, h, b.uncles)
|
ethash.AccumulateRewards(config, statedb, h, b.uncles)
|
||||||
root, err := statedb.CommitTo(db, config.IsEIP158(h.Number))
|
root, err := statedb.CommitTo(db, config.IsEIP158(h.Number))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("state write error: %v", err))
|
panic(fmt.Sprintf("state write error: %v", err))
|
||||||
|
@ -128,18 +128,14 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
// capture SSTORE opcodes and determine the changed value and store
|
// capture SSTORE opcodes and determine the changed value and store
|
||||||
// it in the local storage container. NOTE: we do not need to do any
|
// it in the local storage container.
|
||||||
// range checks here because that's already handler prior to calling
|
if op == SSTORE && stack.len() >= 2 {
|
||||||
// this function.
|
|
||||||
switch op {
|
|
||||||
case SSTORE:
|
|
||||||
var (
|
var (
|
||||||
value = common.BigToHash(stack.data[stack.len()-2])
|
value = common.BigToHash(stack.data[stack.len()-2])
|
||||||
address = common.BigToHash(stack.data[stack.len()-1])
|
address = common.BigToHash(stack.data[stack.len()-1])
|
||||||
)
|
)
|
||||||
l.changedValues[contract.Address()][address] = value
|
l.changedValues[contract.Address()][address] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy a snapstot of the current memory state to a new buffer
|
// copy a snapstot of the current memory state to a new buffer
|
||||||
var mem []byte
|
var mem []byte
|
||||||
if !l.cfg.DisableMemory {
|
if !l.cfg.DisableMemory {
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
|
||||||
|
|
||||||
package tests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = (*stLogMarshaling)(nil)
|
|
||||||
|
|
||||||
func (s stLog) MarshalJSON() ([]byte, error) {
|
|
||||||
type stLog struct {
|
|
||||||
Address common.UnprefixedAddress `json:"address"`
|
|
||||||
Data hexutil.Bytes `json:"data"`
|
|
||||||
Topics []common.UnprefixedHash `json:"topics"`
|
|
||||||
Bloom string `json:"bloom"`
|
|
||||||
}
|
|
||||||
var enc stLog
|
|
||||||
enc.Address = common.UnprefixedAddress(s.Address)
|
|
||||||
enc.Data = s.Data
|
|
||||||
if s.Topics != nil {
|
|
||||||
enc.Topics = make([]common.UnprefixedHash, len(s.Topics))
|
|
||||||
for k, v := range s.Topics {
|
|
||||||
enc.Topics[k] = common.UnprefixedHash(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.Bloom = s.Bloom
|
|
||||||
return json.Marshal(&enc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stLog) UnmarshalJSON(input []byte) error {
|
|
||||||
type stLog struct {
|
|
||||||
Address *common.UnprefixedAddress `json:"address"`
|
|
||||||
Data hexutil.Bytes `json:"data"`
|
|
||||||
Topics []common.UnprefixedHash `json:"topics"`
|
|
||||||
Bloom *string `json:"bloom"`
|
|
||||||
}
|
|
||||||
var dec stLog
|
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if dec.Address != nil {
|
|
||||||
s.Address = common.Address(*dec.Address)
|
|
||||||
}
|
|
||||||
if dec.Data != nil {
|
|
||||||
s.Data = dec.Data
|
|
||||||
}
|
|
||||||
if dec.Topics != nil {
|
|
||||||
s.Topics = make([]common.Hash, len(dec.Topics))
|
|
||||||
for k, v := range dec.Topics {
|
|
||||||
s.Topics[k] = common.Hash(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dec.Bloom != nil {
|
|
||||||
s.Bloom = *dec.Bloom
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -17,12 +17,10 @@
|
|||||||
package tests
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -33,8 +31,10 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StateTest checks transaction processing without block context.
|
// StateTest checks transaction processing without block context.
|
||||||
@ -63,7 +63,7 @@ type stJSON struct {
|
|||||||
|
|
||||||
type stPostState struct {
|
type stPostState struct {
|
||||||
Root common.UnprefixedHash `json:"hash"`
|
Root common.UnprefixedHash `json:"hash"`
|
||||||
Logs *[]stLog `json:"logs"`
|
Logs common.UnprefixedHash `json:"logs"`
|
||||||
Indexes struct {
|
Indexes struct {
|
||||||
Data int `json:"data"`
|
Data int `json:"data"`
|
||||||
Gas int `json:"gas"`
|
Gas int `json:"gas"`
|
||||||
@ -108,21 +108,6 @@ type stTransactionMarshaling struct {
|
|||||||
PrivateKey hexutil.Bytes
|
PrivateKey hexutil.Bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate gencodec -type stLog -field-override stLogMarshaling -out gen_stlog.go
|
|
||||||
|
|
||||||
type stLog struct {
|
|
||||||
Address common.Address `json:"address"`
|
|
||||||
Data []byte `json:"data"`
|
|
||||||
Topics []common.Hash `json:"topics"`
|
|
||||||
Bloom string `json:"bloom"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type stLogMarshaling struct {
|
|
||||||
Address common.UnprefixedAddress
|
|
||||||
Data hexutil.Bytes
|
|
||||||
Topics []common.UnprefixedHash
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtests returns all valid subtests of the test.
|
// Subtests returns all valid subtests of the test.
|
||||||
func (t *StateTest) Subtests() []StateSubtest {
|
func (t *StateTest) Subtests() []StateSubtest {
|
||||||
var sub []StateSubtest
|
var sub []StateSubtest
|
||||||
@ -159,10 +144,8 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) error {
|
|||||||
if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
|
if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
if post.Logs != nil {
|
if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) {
|
||||||
if err := checkLogs(statedb.Logs(), *post.Logs); err != nil {
|
return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs)
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
root, _ := statedb.CommitTo(db, config.IsEIP158(block.Number()))
|
root, _ := statedb.CommitTo(db, config.IsEIP158(block.Number()))
|
||||||
if root != common.Hash(post.Root) {
|
if root != common.Hash(post.Root) {
|
||||||
@ -254,28 +237,9 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) {
|
|||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkLogs(have []*types.Log, want []stLog) error {
|
func rlpHash(x interface{}) (h common.Hash) {
|
||||||
if len(have) != len(want) {
|
hw := sha3.NewKeccak256()
|
||||||
return fmt.Errorf("logs length mismatch: got %d, want %d", len(have), len(want))
|
rlp.Encode(hw, x)
|
||||||
}
|
hw.Sum(h[:0])
|
||||||
for i := range have {
|
return h
|
||||||
if have[i].Address != want[i].Address {
|
|
||||||
return fmt.Errorf("log address %d: got %x, want %x", i, have[i].Address, want[i].Address)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(have[i].Data, want[i].Data) {
|
|
||||||
return fmt.Errorf("log data %d: got %x, want %x", i, have[i].Data, want[i].Data)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(have[i].Topics, want[i].Topics) {
|
|
||||||
return fmt.Errorf("log topics %d:\ngot %x\nwant %x", i, have[i].Topics, want[i].Topics)
|
|
||||||
}
|
|
||||||
genBloom := math.PaddedBigBytes(types.LogsBloom([]*types.Log{have[i]}), 256)
|
|
||||||
var wantBloom types.Bloom
|
|
||||||
if err := hexutil.UnmarshalFixedUnprefixedText("Bloom", []byte(want[i].Bloom), wantBloom[:]); err != nil {
|
|
||||||
return fmt.Errorf("test log %d has invalid bloom: %v", i, err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(genBloom, wantBloom[:]) {
|
|
||||||
return fmt.Errorf("bloom mismatch")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 70e5862eb267226ca89fb9f395c97be1fdf6923a
|
Subproject commit cd2c3f1b3acb98c0d1501b06a4a54629d8794d79
|
@ -26,6 +26,10 @@ func TestVM(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
vmt := new(testMatcher)
|
vmt := new(testMatcher)
|
||||||
vmt.fails("^vmSystemOperationsTest.json/createNameRegistrator$", "fails without parallel execution")
|
vmt.fails("^vmSystemOperationsTest.json/createNameRegistrator$", "fails without parallel execution")
|
||||||
|
|
||||||
|
vmt.skipLoad(`^vmPerformanceTest.json`) // log format broken
|
||||||
|
vmt.skipLoad(`^vmInputLimits(Light)?.json`) // log format broken
|
||||||
|
|
||||||
vmt.skipShortMode("^vmPerformanceTest.json")
|
vmt.skipShortMode("^vmPerformanceTest.json")
|
||||||
vmt.skipShortMode("^vmInputLimits(Light)?.json")
|
vmt.skipShortMode("^vmInputLimits(Light)?.json")
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ func (t *VMTest) UnmarshalJSON(data []byte) error {
|
|||||||
type vmJSON struct {
|
type vmJSON struct {
|
||||||
Env stEnv `json:"env"`
|
Env stEnv `json:"env"`
|
||||||
Exec vmExec `json:"exec"`
|
Exec vmExec `json:"exec"`
|
||||||
Logs []stLog `json:"logs"`
|
Logs common.UnprefixedHash `json:"logs"`
|
||||||
GasRemaining *math.HexOrDecimal64 `json:"gas"`
|
GasRemaining *math.HexOrDecimal64 `json:"gas"`
|
||||||
Out hexutil.Bytes `json:"out"`
|
Out hexutil.Bytes `json:"out"`
|
||||||
Pre core.GenesisAlloc `json:"pre"`
|
Pre core.GenesisAlloc `json:"pre"`
|
||||||
@ -109,7 +109,10 @@ func (t *VMTest) Run(vmconfig vm.Config) error {
|
|||||||
// if root := statedb.IntermediateRoot(false); root != t.json.PostStateRoot {
|
// if root := statedb.IntermediateRoot(false); root != t.json.PostStateRoot {
|
||||||
// return fmt.Errorf("post state root mismatch, got %x, want %x", root, t.json.PostStateRoot)
|
// return fmt.Errorf("post state root mismatch, got %x, want %x", root, t.json.PostStateRoot)
|
||||||
// }
|
// }
|
||||||
return checkLogs(statedb.Logs(), t.json.Logs)
|
if logs := rlpHash(statedb.Logs()); logs != common.Hash(t.json.Logs) {
|
||||||
|
return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, t.json.Logs)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) {
|
func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user