core, light, params: implement eip2028 (#19931)

* core, light, params: implement eip2028

* core, light: address comments

* core: address comments

* tests: disable Istanbul tx tests (until updated)

* core: address comment
This commit is contained in:
gary rong 2019-08-14 20:53:21 +08:00 committed by Péter Szilágyi
parent 44c8b9ad37
commit c2c4c9f1e5
6 changed files with 53 additions and 34 deletions

View File

@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) { return func(i int, gen *BlockGen) {
toaddr := common.Address{} toaddr := common.Address{}
data := make([]byte, nbytes) 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) tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
gen.AddTx(tx) gen.AddTx(tx)
} }

View File

@ -76,10 +76,10 @@ type Message interface {
} }
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. // 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, isEIP155 bool, isEIP2028 bool) (uint64, error) {
// Set the starting gas for the raw transaction // Set the starting gas for the raw transaction
var gas uint64 var gas uint64
if contractCreation && homestead { if contractCreation && isEIP155 {
gas = params.TxGasContractCreation gas = params.TxGasContractCreation
} else { } else {
gas = params.TxGas gas = params.TxGas
@ -94,10 +94,14 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error)
} }
} }
// Make sure we don't exceed uint64 for all data combinations // Make sure we don't exceed uint64 for all data combinations
if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz { nonZeroGas := params.TxDataNonZeroGasFrontier
if isEIP2028 {
nonZeroGas = params.TxDataNonZeroGasEIP2028
}
if (math.MaxUint64-gas)/nonZeroGas < nz {
return 0, vm.ErrOutOfGas return 0, vm.ErrOutOfGas
} }
gas += nz * params.TxDataNonZeroGas gas += nz * nonZeroGas
z := uint64(len(data)) - nz z := uint64(len(data)) - nz
if (math.MaxUint64-gas)/params.TxDataZeroGas < z { if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
@ -187,10 +191,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
msg := st.msg msg := st.msg
sender := vm.AccountRef(msg.From()) sender := vm.AccountRef(msg.From())
homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.BlockNumber)
contractCreation := msg.To() == nil contractCreation := msg.To() == nil
// Pay intrinsic gas // Pay intrinsic gas
gas, err := IntrinsicGas(st.data, contractCreation, homestead) gas, err := IntrinsicGas(st.data, contractCreation, homestead, istanbul)
if err != nil { if err != nil {
return nil, 0, false, err return nil, 0, false, err
} }

View File

@ -217,6 +217,8 @@ type TxPool struct {
signer types.Signer signer types.Signer
mu sync.RWMutex mu sync.RWMutex
istanbul bool // Fork indicator whether we are in the istanbul stage.
currentState *state.StateDB // Current state in the blockchain head currentState *state.StateDB // Current state in the blockchain head
pendingNonces *txNoncer // Pending state tracking virtual nonces pendingNonces *txNoncer // Pending state tracking virtual nonces
currentMaxGas uint64 // Current gas limit for transaction caps currentMaxGas uint64 // Current gas limit for transaction caps
@ -540,7 +542,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
return ErrInsufficientFunds return ErrInsufficientFunds
} }
// Ensure the transaction has more gas than the basic tx fee. // 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, true, pool.istanbul)
if err != nil { if err != nil {
return err return err
} }
@ -1118,6 +1120,10 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
log.Debug("Reinjecting stale transactions", "count", len(reinject)) log.Debug("Reinjecting stale transactions", "count", len(reinject))
senderCacher.recover(pool.signer, reinject) senderCacher.recover(pool.signer, reinject)
pool.addTxsLocked(reinject, false) pool.addTxsLocked(reinject, false)
// 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)
} }
// promoteExecutables moves transactions that have become processable from the // promoteExecutables moves transactions that have become processable from the

View File

@ -19,6 +19,7 @@ package light
import ( import (
"context" "context"
"fmt" "fmt"
"math/big"
"sync" "sync"
"time" "time"
@ -67,7 +68,7 @@ type TxPool struct {
mined map[common.Hash][]*types.Transaction // mined transactions by block hash mined map[common.Hash][]*types.Transaction // mined transactions by block hash
clearIdx uint64 // earliest block nr that can contain mined tx info clearIdx uint64 // earliest block nr that can contain mined tx info
homestead bool istanbul bool // Fork indicator whether we are in the istanbul stage.
} }
// TxRelayBackend provides an interface to the mechanism that forwards transacions // TxRelayBackend provides an interface to the mechanism that forwards transacions
@ -309,8 +310,10 @@ func (pool *TxPool) setNewHead(head *types.Header) {
txc, _ := pool.reorgOnNewHead(ctx, head) txc, _ := pool.reorgOnNewHead(ctx, head)
m, r := txc.getLists() m, r := txc.getLists()
pool.relay.NewHead(pool.head, m, r) pool.relay.NewHead(pool.head, m, r)
pool.homestead = pool.config.IsHomestead(head.Number)
pool.signer = types.MakeSigner(pool.config, head.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)
} }
// Stop stops the light transaction pool // Stop stops the light transaction pool
@ -378,7 +381,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
} }
// Should supply enough intrinsic gas // 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, true, pool.istanbul)
if err != nil { if err != nil {
return err return err
} }

View File

@ -55,19 +55,20 @@ const (
JumpdestGas uint64 = 1 // Once per JUMPDEST operation. JumpdestGas uint64 = 1 // Once per JUMPDEST operation.
EpochDuration uint64 = 30000 // Duration between proof-of-work epochs. EpochDuration uint64 = 30000 // Duration between proof-of-work epochs.
CreateDataGas uint64 = 200 // CreateDataGas uint64 = 200 //
CallCreateDepth uint64 = 1024 // Maximum depth of call/create stack. CallCreateDepth uint64 = 1024 // Maximum depth of call/create stack.
ExpGas uint64 = 10 // Once per EXP instruction ExpGas uint64 = 10 // Once per EXP instruction
LogGas uint64 = 375 // Per LOG* operation. LogGas uint64 = 375 // Per LOG* operation.
CopyGas uint64 = 3 // CopyGas uint64 = 3 //
StackLimit uint64 = 1024 // Maximum size of VM stack allowed. StackLimit uint64 = 1024 // Maximum size of VM stack allowed.
TierStepGas uint64 = 0 // Once per operation, for a selection of them. 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. 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. CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
Create2Gas uint64 = 32000 // Once per CREATE2 operation Create2Gas uint64 = 32000 // Once per CREATE2 operation
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct 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. 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. 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 // These have been changed during the course of the chain
CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction. CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction.

View File

@ -32,6 +32,7 @@ type TransactionTest struct {
RLP hexutil.Bytes `json:"rlp"` RLP hexutil.Bytes `json:"rlp"`
Byzantium ttFork Byzantium ttFork
Constantinople ttFork Constantinople ttFork
Istanbul ttFork
EIP150 ttFork EIP150 ttFork
EIP158 ttFork EIP158 ttFork
Frontier ttFork Frontier ttFork
@ -45,7 +46,7 @@ type ttFork struct {
func (tt *TransactionTest) Run(config *params.ChainConfig) error { 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) tx := new(types.Transaction)
if err := rlp.DecodeBytes(rlpData, tx); err != nil { if err := rlp.DecodeBytes(rlpData, tx); err != nil {
return nil, nil, err return nil, nil, err
@ -55,7 +56,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error {
return nil, nil, err return nil, nil, err
} }
// Intrinsic gas // 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 { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -71,19 +72,22 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error {
signer types.Signer signer types.Signer
fork ttFork fork ttFork
isHomestead bool isHomestead bool
isIstanbul bool
}{ }{
{"Frontier", types.FrontierSigner{}, tt.Frontier, false}, {"Frontier", types.FrontierSigner{}, tt.Frontier, false, false},
{"Homestead", types.HomesteadSigner{}, tt.Homestead, true}, {"Homestead", types.HomesteadSigner{}, tt.Homestead, true, false},
{"EIP150", types.HomesteadSigner{}, tt.EIP150, true}, {"EIP150", types.HomesteadSigner{}, tt.EIP150, true, false},
{"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true}, {"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true, false},
{"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true}, {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true, false},
{"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true}, {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true, false},
//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) sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead, testcase.isIstanbul)
if testcase.fork.Sender == (common.UnprefixedAddress{}) { if testcase.fork.Sender == (common.UnprefixedAddress{}) {
if err == nil { 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 continue
} }