Jelajahi Sumber

consensus, core, tests: implement Metropolis EIP 649

Péter Szilágyi 8 tahun lalu
induk
melakukan
b872961ec8

+ 20 - 5
consensus/ethash/consensus.go

@@ -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
@@ -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
@@ -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"
@@ -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
@@ -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 {

+ 1 - 1
core/chain_makers.go

@@ -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))

+ 2 - 6
core/vm/logger.go

@@ -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 {

+ 0 - 61
tests/gen_stlog.go

@@ -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
-}

+ 10 - 46
tests/state_test_util.go

@@ -17,12 +17,10 @@
 package tests
 
 import (
-	"bytes"
 	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"math/big"
-	"reflect"
 	"strings"
 
 	"github.com/ethereum/go-ethereum/common"
@@ -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.
@@ -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"`
@@ -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
@@ -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) {
@@ -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
 }

+ 1 - 1
tests/testdata

@@ -1 +1 @@
-Subproject commit 70e5862eb267226ca89fb9f395c97be1fdf6923a
+Subproject commit cd2c3f1b3acb98c0d1501b06a4a54629d8794d79

+ 4 - 0
tests/vm_test.go

@@ -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")
 

+ 12 - 9
tests/vm_test_util.go

@@ -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
@@ -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) {