Skip to content

Commit

Permalink
Merge pull request ethereum#15028 from karalabe/metropolis-iceage
Browse files Browse the repository at this point in the history
consensus, core, tests: implement Metropolis EIP 649
  • Loading branch information
karalabe authored Aug 25, 2017
2 parents 8596fc5 + b872961 commit 27a5622
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 129 deletions.
25 changes: 20 additions & 5 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ import (

// Ethash proof-of-work protocol constants.
var (
blockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
maxUncles = 2 // Maximum number of uncles allowed in a single 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
)

// Various error messages to mark blocks invalid. These should be private to
Expand Down Expand Up @@ -306,6 +307,7 @@ var (
big9 = big.NewInt(9)
big10 = big.NewInt(10)
bigMinus99 = big.NewInt(-99)
big2999999 = big.NewInt(2999999)
)

// calcDifficultyMetropolis is the difficulty adjustment algorithm. It returns
Expand Down Expand Up @@ -346,8 +348,15 @@ func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int {
if x.Cmp(params.MinimumDifficulty) < 0 {
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
periodCount := new(big.Int).Add(parent.Number, big1)
periodCount := fakeBlockNumber
periodCount.Div(periodCount, expDiffPeriod)

// the exponential factor, commonly referred to as "the bomb"
Expand Down Expand Up @@ -501,7 +510,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header)
// 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) {
// 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 seems complete, assemble into a block and return
Expand All @@ -518,7 +527,13 @@ var (
// reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded.
// 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)
r := new(big.Int)
for _, uncle := range uncles {
Expand Down
2 changes: 1 addition & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Dat
if gen != nil {
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))
if err != nil {
panic(fmt.Sprintf("state write error: %v", err))
Expand Down
8 changes: 2 additions & 6 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
// it in the local storage container. NOTE: we do not need to do any
// range checks here because that's already handler prior to calling
// this function.
switch op {
case SSTORE:
// it in the local storage container.
if op == SSTORE && stack.len() >= 2 {
var (
value = common.BigToHash(stack.data[stack.len()-2])
address = common.BigToHash(stack.data[stack.len()-1])
)
l.changedValues[contract.Address()][address] = value
}

// copy a snapstot of the current memory state to a new buffer
var mem []byte
if !l.cfg.DisableMemory {
Expand Down
61 changes: 0 additions & 61 deletions tests/gen_stlog.go

This file was deleted.

56 changes: 10 additions & 46 deletions tests/state_test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
package tests

import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"reflect"
"strings"

"github.com/ethereum/go-ethereum/common"
Expand All @@ -33,8 +31,10 @@ import (
"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/crypto/sha3"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)

// StateTest checks transaction processing without block context.
Expand Down Expand Up @@ -63,7 +63,7 @@ type stJSON struct {

type stPostState struct {
Root common.UnprefixedHash `json:"hash"`
Logs *[]stLog `json:"logs"`
Logs common.UnprefixedHash `json:"logs"`
Indexes struct {
Data int `json:"data"`
Gas int `json:"gas"`
Expand Down Expand Up @@ -108,21 +108,6 @@ type stTransactionMarshaling struct {
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.
func (t *StateTest) Subtests() []StateSubtest {
var sub []StateSubtest
Expand Down Expand Up @@ -159,10 +144,8 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) error {
if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
statedb.RevertToSnapshot(snapshot)
}
if post.Logs != nil {
if err := checkLogs(statedb.Logs(), *post.Logs); err != nil {
return err
}
if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) {
return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs)
}
root, _ := statedb.CommitTo(db, config.IsEIP158(block.Number()))
if root != common.Hash(post.Root) {
Expand Down Expand Up @@ -254,28 +237,9 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) {
return msg, nil
}

func checkLogs(have []*types.Log, want []stLog) error {
if len(have) != len(want) {
return fmt.Errorf("logs length mismatch: got %d, want %d", len(have), len(want))
}
for i := range have {
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
func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256()
rlp.Encode(hw, x)
hw.Sum(h[:0])
return h
}
2 changes: 1 addition & 1 deletion tests/testdata
Submodule testdata updated 3016 files
4 changes: 4 additions & 0 deletions tests/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ func TestVM(t *testing.T) {
t.Parallel()
vmt := new(testMatcher)
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("^vmInputLimits(Light)?.json")

Expand Down
21 changes: 12 additions & 9 deletions tests/vm_test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ func (t *VMTest) UnmarshalJSON(data []byte) error {
}

type vmJSON struct {
Env stEnv `json:"env"`
Exec vmExec `json:"exec"`
Logs []stLog `json:"logs"`
GasRemaining *math.HexOrDecimal64 `json:"gas"`
Out hexutil.Bytes `json:"out"`
Pre core.GenesisAlloc `json:"pre"`
Post core.GenesisAlloc `json:"post"`
PostStateRoot common.Hash `json:"postStateRoot"`
Env stEnv `json:"env"`
Exec vmExec `json:"exec"`
Logs common.UnprefixedHash `json:"logs"`
GasRemaining *math.HexOrDecimal64 `json:"gas"`
Out hexutil.Bytes `json:"out"`
Pre core.GenesisAlloc `json:"pre"`
Post core.GenesisAlloc `json:"post"`
PostStateRoot common.Hash `json:"postStateRoot"`
}

//go:generate gencodec -type vmExec -field-override vmExecMarshaling -out gen_vmexec.go
Expand Down Expand Up @@ -109,7 +109,10 @@ func (t *VMTest) Run(vmconfig vm.Config) error {
// 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 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) {
Expand Down

0 comments on commit 27a5622

Please sign in to comment.