From acad1475e6f3372bbad675ea42cd222c77d54f84 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 9 Aug 2019 10:28:23 +0800 Subject: [PATCH 1/5] core, light, params: implement eip2028 --- core/bench_test.go | 2 +- core/state_transition.go | 13 +++++++++---- core/tx_pool.go | 14 +++++++++++++- light/txpool.go | 17 +++++++++++++---- params/protocol_params.go | 27 ++++++++++++++------------- tests/transaction_test_util.go | 21 ++++++++++++--------- 6 files changed, 62 insertions(+), 32 deletions(-) diff --git a/core/bench_test.go b/core/bench_test.go index 79c369d5fcfb..d7a5e11c2f15 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { return func(i int, gen *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) - gas, _ := IntrinsicGas(data, false, false) + gas, _ := IntrinsicGas(data, false, false, false) tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey) gen.AddTx(tx) } diff --git a/core/state_transition.go b/core/state_transition.go index fda081b7d113..58023bb3623c 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -76,7 +76,7 @@ type Message interface { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) { +func IntrinsicGas(data []byte, contractCreation, homestead bool, istanbul bool) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 if contractCreation && homestead { @@ -94,10 +94,14 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) } } // Make sure we don't exceed uint64 for all data combinations - if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz { + nonZeroGas := params.TxDataNonZeroGasFrontier + if istanbul { + nonZeroGas = params.TxDataNonZeroGasEIP2028 + } + if (math.MaxUint64-gas)/nonZeroGas < nz { return 0, vm.ErrOutOfGas } - gas += nz * params.TxDataNonZeroGas + gas += nz * nonZeroGas z := uint64(len(data)) - nz if (math.MaxUint64-gas)/params.TxDataZeroGas < z { @@ -187,10 +191,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo msg := st.msg sender := vm.AccountRef(msg.From()) homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) + istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber) contractCreation := msg.To() == nil // Pay intrinsic gas - gas, err := IntrinsicGas(st.data, contractCreation, homestead) + gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul) if err != nil { return nil, 0, false, err } diff --git a/core/tx_pool.go b/core/tx_pool.go index 0c422dd99d92..a205e0a0082e 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -217,6 +217,9 @@ type TxPool struct { signer types.Signer mu sync.RWMutex + homestead bool // Fork indicator whether we are in the homestead stage. + istanbul bool // Fork indicator whether we are in the istanbul stage. + currentState *state.StateDB // Current state in the blockchain head pendingNonces *txNoncer // Pending state tracking virtual nonces currentMaxGas uint64 // Current gas limit for transaction caps @@ -540,7 +543,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrInsufficientFunds } // Ensure the transaction has more gas than the basic tx fee. - intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true) + intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, pool.istanbul) if err != nil { return err } @@ -1118,6 +1121,15 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { log.Debug("Reinjecting stale transactions", "count", len(reinject)) senderCacher.recover(pool.signer, reinject) pool.addTxsLocked(reinject, false) + + // Update all fork indicators by next pending block number. + next := new(big.Int).Add(newHead.Number, big.NewInt(1)) + pool.istanbul = pool.chainconfig.IsIstanbul(next) + if pool.istanbul { + pool.homestead = true + } else { + pool.homestead = pool.chainconfig.IsHomestead(next) + } } // promoteExecutables moves transactions that have become processable from the diff --git a/light/txpool.go b/light/txpool.go index e945ef2ec178..d1c0634afa03 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -19,6 +19,7 @@ package light import ( "context" "fmt" + "math/big" "sync" "time" @@ -67,7 +68,8 @@ type TxPool struct { mined map[common.Hash][]*types.Transaction // mined transactions by block hash clearIdx uint64 // earliest block nr that can contain mined tx info - homestead bool + homestead bool // Fork indicator whether we are in the homestead stage. + istanbul bool // Fork indicator whether we are in the istanbul stage. } // TxRelayBackend provides an interface to the mechanism that forwards transacions @@ -309,8 +311,15 @@ func (pool *TxPool) setNewHead(head *types.Header) { txc, _ := pool.reorgOnNewHead(ctx, head) m, r := txc.getLists() pool.relay.NewHead(pool.head, m, r) - pool.homestead = pool.config.IsHomestead(head.Number) - pool.signer = types.MakeSigner(pool.config, head.Number) + + // Update fork indicators by next pending block number + next := new(big.Int).Add(head.Number, big.NewInt(1)) + pool.istanbul = pool.config.IsIstanbul(next) + if pool.istanbul { + pool.homestead = true + } else { + pool.homestead = pool.config.IsHomestead(next) + } } // Stop stops the light transaction pool @@ -378,7 +387,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error } // Should supply enough intrinsic gas - gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) + gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, pool.istanbul) if err != nil { return err } diff --git a/params/protocol_params.go b/params/protocol_params.go index 943788be8cf2..3022b700df9a 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -55,19 +55,20 @@ const ( JumpdestGas uint64 = 1 // Once per JUMPDEST operation. EpochDuration uint64 = 30000 // Duration between proof-of-work epochs. - CreateDataGas uint64 = 200 // - CallCreateDepth uint64 = 1024 // Maximum depth of call/create stack. - ExpGas uint64 = 10 // Once per EXP instruction - LogGas uint64 = 375 // Per LOG* operation. - CopyGas uint64 = 3 // - StackLimit uint64 = 1024 // Maximum size of VM stack allowed. - TierStepGas uint64 = 0 // Once per operation, for a selection of them. - LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. - CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction. - Create2Gas uint64 = 32000 // Once per CREATE2 operation - SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation. - MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. - TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. + CreateDataGas uint64 = 200 // + CallCreateDepth uint64 = 1024 // Maximum depth of call/create stack. + ExpGas uint64 = 10 // Once per EXP instruction + LogGas uint64 = 375 // Per LOG* operation. + CopyGas uint64 = 3 // + StackLimit uint64 = 1024 // Maximum size of VM stack allowed. + TierStepGas uint64 = 0 // Once per operation, for a selection of them. + LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. + CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction. + Create2Gas uint64 = 32000 // Once per CREATE2 operation + SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation. + MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. + TxDataNonZeroGasFrontier uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. + TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul) // These have been changed during the course of the chain CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction. diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 12444720cc7a..cd0079823a63 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -32,6 +32,7 @@ type TransactionTest struct { RLP hexutil.Bytes `json:"rlp"` Byzantium ttFork Constantinople ttFork + Istanbul ttFork EIP150 ttFork EIP158 ttFork Frontier ttFork @@ -45,7 +46,7 @@ type ttFork struct { func (tt *TransactionTest) Run(config *params.ChainConfig) error { - validateTx := func(rlpData hexutil.Bytes, signer types.Signer, isHomestead bool) (*common.Address, *common.Hash, error) { + validateTx := func(rlpData hexutil.Bytes, signer types.Signer, isHomestead bool, isIstanbul bool) (*common.Address, *common.Hash, error) { tx := new(types.Transaction) if err := rlp.DecodeBytes(rlpData, tx); err != nil { return nil, nil, err @@ -55,7 +56,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { return nil, nil, err } // Intrinsic gas - requiredGas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, isHomestead) + requiredGas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, isHomestead, isIstanbul) if err != nil { return nil, nil, err } @@ -71,15 +72,17 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { signer types.Signer fork ttFork isHomestead bool + isIstanbul bool }{ - {"Frontier", types.FrontierSigner{}, tt.Frontier, false}, - {"Homestead", types.HomesteadSigner{}, tt.Homestead, true}, - {"EIP150", types.HomesteadSigner{}, tt.EIP150, true}, - {"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true}, - {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true}, - {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true}, + {"Frontier", types.FrontierSigner{}, tt.Frontier, false, false}, + {"Homestead", types.HomesteadSigner{}, tt.Homestead, true, false}, + {"EIP150", types.HomesteadSigner{}, tt.EIP150, true, false}, + {"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true, false}, + {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true, false}, + {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true, false}, + {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Istanbul, true, true}, } { - sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead) + sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead, testcase.isIstanbul) if testcase.fork.Sender == (common.UnprefixedAddress{}) { if err == nil { From 80bb52c244cf15beff0318334eedba53efe459db Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 9 Aug 2019 22:34:47 +0800 Subject: [PATCH 2/5] core, light: address comments --- core/tx_pool.go | 12 +++--------- light/txpool.go | 12 +++--------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index a205e0a0082e..a49b42261421 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -217,8 +217,7 @@ type TxPool struct { signer types.Signer mu sync.RWMutex - homestead bool // Fork indicator whether we are in the homestead stage. - istanbul bool // Fork indicator whether we are in the istanbul stage. + istanbul bool // Fork indicator whether we are in the istanbul stage. currentState *state.StateDB // Current state in the blockchain head pendingNonces *txNoncer // Pending state tracking virtual nonces @@ -543,7 +542,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrInsufficientFunds } // Ensure the transaction has more gas than the basic tx fee. - intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, pool.istanbul) + intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul) if err != nil { return err } @@ -1122,14 +1121,9 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { senderCacher.recover(pool.signer, reinject) pool.addTxsLocked(reinject, false) - // Update all fork indicators by next pending block number. + // Update all fork indicator by next pending block number. next := new(big.Int).Add(newHead.Number, big.NewInt(1)) pool.istanbul = pool.chainconfig.IsIstanbul(next) - if pool.istanbul { - pool.homestead = true - } else { - pool.homestead = pool.chainconfig.IsHomestead(next) - } } // promoteExecutables moves transactions that have become processable from the diff --git a/light/txpool.go b/light/txpool.go index d1c0634afa03..11a0e76ae01e 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -68,8 +68,7 @@ type TxPool struct { mined map[common.Hash][]*types.Transaction // mined transactions by block hash clearIdx uint64 // earliest block nr that can contain mined tx info - homestead bool // Fork indicator whether we are in the homestead stage. - istanbul bool // Fork indicator whether we are in the istanbul stage. + istanbul bool // Fork indicator whether we are in the istanbul stage. } // TxRelayBackend provides an interface to the mechanism that forwards transacions @@ -312,14 +311,9 @@ func (pool *TxPool) setNewHead(head *types.Header) { m, r := txc.getLists() pool.relay.NewHead(pool.head, m, r) - // Update fork indicators by next pending block number + // Update fork indicator by next pending block number next := new(big.Int).Add(head.Number, big.NewInt(1)) pool.istanbul = pool.config.IsIstanbul(next) - if pool.istanbul { - pool.homestead = true - } else { - pool.homestead = pool.config.IsHomestead(next) - } } // Stop stops the light transaction pool @@ -387,7 +381,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error } // Should supply enough intrinsic gas - gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, pool.istanbul) + gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul) if err != nil { return err } From 1b34f35b141539dd9e5da62cbb1de74a7a7bf3cf Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 13 Aug 2019 16:45:56 +0800 Subject: [PATCH 3/5] core: address comments --- core/state_transition.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 58023bb3623c..eb9dd08c9d2b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -76,10 +76,10 @@ type Message interface { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, contractCreation, homestead bool, istanbul bool) (uint64, error) { +func IntrinsicGas(data []byte, contractCreation, eip155Active bool, eip2028Active bool) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 - if contractCreation && homestead { + if contractCreation && eip155Active { gas = params.TxGasContractCreation } else { gas = params.TxGas @@ -95,7 +95,7 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool, istanbul bool) } // Make sure we don't exceed uint64 for all data combinations nonZeroGas := params.TxDataNonZeroGasFrontier - if istanbul { + if eip2028Active { nonZeroGas = params.TxDataNonZeroGasEIP2028 } if (math.MaxUint64-gas)/nonZeroGas < nz { From 4c7d37399100212d4111a1b1291f9eac217336f1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 14 Aug 2019 09:17:08 +0200 Subject: [PATCH 4/5] tests: disable Istanbul tx tests (until updated) --- tests/transaction_test_util.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index cd0079823a63..85bf1fb0bd0d 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -80,13 +80,14 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { {"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true, false}, {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true, false}, {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true, false}, - {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Istanbul, true, true}, + //TODO! @holiman or @rjl493456442 : enable this after tests have been updated for Istanbul + //{"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Istanbul, true, true}, } { sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead, testcase.isIstanbul) if testcase.fork.Sender == (common.UnprefixedAddress{}) { if err == nil { - return fmt.Errorf("Expected error, got none (address %v)", sender.String()) + return fmt.Errorf("Expected error, got none (address %v)[%v]", sender.String(), testcase.name) } continue } From d94d5dd3dd2284b69fb6051f69743f9d5539346d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 14 Aug 2019 16:10:55 +0800 Subject: [PATCH 5/5] core: address comment --- core/state_transition.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index eb9dd08c9d2b..bef6e9b0eb2f 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -76,10 +76,10 @@ type Message interface { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, contractCreation, eip155Active bool, eip2028Active bool) (uint64, error) { +func IntrinsicGas(data []byte, contractCreation, isEIP155 bool, isEIP2028 bool) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 - if contractCreation && eip155Active { + if contractCreation && isEIP155 { gas = params.TxGasContractCreation } else { gas = params.TxGas @@ -95,7 +95,7 @@ func IntrinsicGas(data []byte, contractCreation, eip155Active bool, eip2028Activ } // Make sure we don't exceed uint64 for all data combinations nonZeroGas := params.TxDataNonZeroGasFrontier - if eip2028Active { + if isEIP2028 { nonZeroGas = params.TxDataNonZeroGasEIP2028 } if (math.MaxUint64-gas)/nonZeroGas < nz {