Skip to content

Commit

Permalink
impl EIP4488 for pisa (ethereum#74)
Browse files Browse the repository at this point in the history
* impl EIP4488 for pisa

* fix review; mod IntrinsicGas

Co-authored-by: blockchaindevsh <blockchaindevsh@google.com>
  • Loading branch information
blockchaindevsh and blockchaindevsh authored May 15, 2022
1 parent 6ea6a30 commit d1dd0e1
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 43 deletions.
2 changes: 1 addition & 1 deletion cmd/evm/internal/t8ntool/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func Transaction(ctx *cli.Context) error {
}
// Check intrinsic gas
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil,
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int))); err != nil {
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsPisa(new(big.Int))); err != nil {
r.Error = err
results = append(results, r)
continue
Expand Down
2 changes: 1 addition & 1 deletion core/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, nil, false, false, false)
gas, _ := IntrinsicGas(data, nil, false, false, false, false)
signer := types.MakeSigner(gen.config, big.NewInt(int64(i)))
gasPrice := big.NewInt(0)
if gen.header.BaseFee != nil {
Expand Down
14 changes: 14 additions & 0 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,23 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
}
return consensus.ErrPrunedAncestor
}
if v.config.IsPisa(block.Number()) {
totalCalldata := 0
for _, tx := range block.Transactions() {
totalCalldata += len(tx.Data())
}

if totalCalldata > MaxCalldataEIP4488(len(block.Transactions())) {
return fmt.Errorf("transaction totalCalldata exceeded for EIP4488")
}
}
return nil
}

func MaxCalldataEIP4488(txCount int) int {
return params.BaseMaxCalldataPerBlockEIP4488 + params.CalldataPerTxStipendEIP4488*(txCount)
}

// ValidateState validates the various changes that happen after a state
// transition, such as amount of used gas, the receipt roots and the state root
// itself. ValidateState returns a database batch if the validation was a success
Expand Down
49 changes: 28 additions & 21 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (result *ExecutionResult) Revert() []byte {
}

// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) {
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028, isPisa bool) (uint64, error) {
// Set the starting gas for the raw transaction
var gas uint64
if isContractCreation && isHomestead {
Expand All @@ -125,28 +125,34 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b
}
// Bump the required gas by the amount of transactional data
if len(data) > 0 {
// Zero and non-zero bytes are priced differently
var nz uint64
for _, byt := range data {
if byt != 0 {
nz++
switch {
case isPisa:
gas += uint64(len(data)) * params.CalldataGasCostEIP4488
default:
// Zero and non-zero bytes are priced differently
var nz uint64
for _, byt := range data {
if byt != 0 {
nz++
}
}
}
// Make sure we don't exceed uint64 for all data combinations
nonZeroGas := params.TxDataNonZeroGasFrontier
if isEIP2028 {
nonZeroGas = params.TxDataNonZeroGasEIP2028
}
if (math.MaxUint64-gas)/nonZeroGas < nz {
return 0, ErrGasUintOverflow
}
gas += nz * nonZeroGas
// Make sure we don't exceed uint64 for all data combinations
nonZeroGas := params.TxDataNonZeroGasFrontier
if isEIP2028 {
nonZeroGas = params.TxDataNonZeroGasEIP2028
}
if (math.MaxUint64-gas)/nonZeroGas < nz {
return 0, ErrGasUintOverflow
}
gas += nz * nonZeroGas

z := uint64(len(data)) - nz
if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
return 0, ErrGasUintOverflow
z := uint64(len(data)) - nz
if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
return 0, ErrGasUintOverflow
}
gas += z * params.TxDataZeroGas
}
gas += z * params.TxDataZeroGas

}
if accessList != nil {
gas += uint64(len(accessList)) * params.TxAccessListAddressGas
Expand Down Expand Up @@ -292,10 +298,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber)
istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber)
london := st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber)
pisa := st.evm.ChainConfig().IsPisa(st.evm.Context.BlockNumber)
contractCreation := msg.To() == nil

// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul)
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul, pisa)
if err != nil {
return nil, err
}
Expand Down
4 changes: 3 additions & 1 deletion core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ type TxPool struct {
signer types.Signer
mu sync.RWMutex

pisa bool // Fork indicator whether we are in the pisa stage.
istanbul bool // Fork indicator whether we are in the istanbul stage.
eip2718 bool // Fork indicator whether we are using EIP-2718 type transactions.
eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions.
Expand Down Expand Up @@ -635,7 +636,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.AccessList(), tx.To() == nil, true, pool.istanbul)
intrGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.pisa)
if err != nil {
return err
}
Expand Down Expand Up @@ -1302,6 +1303,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
// 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)
pool.pisa = pool.chainconfig.IsPisa(next)
pool.eip2718 = pool.chainconfig.IsBerlin(next)
pool.eip1559 = pool.chainconfig.IsLondon(next)
}
Expand Down
3 changes: 2 additions & 1 deletion eth/tracers/js/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,8 @@ func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Ad
// Compute intrinsic gas
isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber)
isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber)
intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul)
isPisa := env.ChainConfig().IsPisa(env.Context.BlockNumber)
intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul, isPisa)
if err != nil {
return
}
Expand Down
3 changes: 2 additions & 1 deletion eth/tracers/native/prestate.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo
// Compute intrinsic gas
isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber)
isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber)
intrinsicGas, err := core.IntrinsicGas(input, nil, create, isHomestead, isIstanbul)
isPisa := env.ChainConfig().IsPisa(env.Context.BlockNumber)
intrinsicGas, err := core.IntrinsicGas(input, nil, create, isHomestead, isIstanbul, isPisa)
if err != nil {
return
}
Expand Down
4 changes: 3 additions & 1 deletion light/txpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type TxPool struct {
clearIdx uint64 // earliest block nr that can contain mined tx info

istanbul bool // Fork indicator whether we are in the istanbul stage.
pisa bool // Fork indicator whether we are in the Pisa stage.
eip2718 bool // Fork indicator whether we are in the eip2718 stage.
}

Expand Down Expand Up @@ -314,6 +315,7 @@ func (pool *TxPool) setNewHead(head *types.Header) {
// Update fork indicator by next pending block number
next := new(big.Int).Add(head.Number, big.NewInt(1))
pool.istanbul = pool.config.IsIstanbul(next)
pool.pisa = pool.config.IsPisa(next)
pool.eip2718 = pool.config.IsBerlin(next)
}

Expand Down Expand Up @@ -382,7 +384,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
}

// Should supply enough intrinsic gas
gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul)
gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.pisa)
if err != nil {
return err
}
Expand Down
42 changes: 27 additions & 15 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,13 @@ const (
type environment struct {
signer types.Signer

state *state.StateDB // apply state changes here
ancestors mapset.Set // ancestor set (used for checking uncle parent validity)
family mapset.Set // family set (used for checking uncle invalidity)
tcount int // tx count in cycle
gasPool *core.GasPool // available gas used to pack transactions
coinbase common.Address
state *state.StateDB // apply state changes here
ancestors mapset.Set // ancestor set (used for checking uncle parent validity)
family mapset.Set // family set (used for checking uncle invalidity)
tcount int // tx count in cycle
totalCalldata int // total calldata in cycle
gasPool *core.GasPool // available gas used to pack transactions
coinbase common.Address

header *types.Header
txs []*types.Transaction
Expand All @@ -99,14 +100,15 @@ type environment struct {
// copy creates a deep copy of environment.
func (env *environment) copy() *environment {
cpy := &environment{
signer: env.signer,
state: env.state.Copy(),
ancestors: env.ancestors.Clone(),
family: env.family.Clone(),
tcount: env.tcount,
coinbase: env.coinbase,
header: types.CopyHeader(env.header),
receipts: copyReceipts(env.receipts),
signer: env.signer,
state: env.state.Copy(),
ancestors: env.ancestors.Clone(),
family: env.family.Clone(),
tcount: env.tcount,
totalCalldata: env.totalCalldata,
coinbase: env.coinbase,
header: types.CopyHeader(env.header),
receipts: copyReceipts(env.receipts),
}
if env.gasPool != nil {
gasPool := *env.gasPool
Expand Down Expand Up @@ -800,6 +802,7 @@ func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase com
}
// Keep track of transactions which return errors so they can be removed
env.tcount = 0
env.totalCalldata = 0
return env, nil
}

Expand Down Expand Up @@ -888,11 +891,19 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
break
}

// Retrieve the next transaction and abort if all done
tx := txs.Peek()
if tx == nil {
break
}

if w.chainConfig.IsPisa(env.header.Number) && env.totalCalldata+len(tx.Data()) > core.MaxCalldataEIP4488(env.tcount+1) {
log.Trace("Total transaction calldata exceeded, ignoring transaction", "hash", tx.Hash(), "eip4488", w.chainConfig.PisaBlock)

break
}

// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
//
Expand Down Expand Up @@ -930,6 +941,7 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP
// Everything ok, collect the logs and shift in the next transaction from the same account
coalescedLogs = append(coalescedLogs, logs...)
env.tcount++
env.totalCalldata += len(tx.Data())
txs.Shift()

case errors.Is(err, core.ErrTxTypeNotSupported):
Expand Down Expand Up @@ -1162,7 +1174,7 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti
case w.taskCh <- &task{receipts: env.receipts, state: env.state, block: block, createdAt: time.Now()}:
w.unconfirmed.Shift(block.NumberU64() - 1)
log.Info("Commit new sealing work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()),
"uncles", len(env.uncles), "txs", env.tcount,
"uncles", len(env.uncles), "txs", env.tcount, "totalCalldata", env.totalCalldata,
"gas", block.GasUsed(), "fees", totalFees(block, env.receipts),
"elapsed", common.PrettyDuration(time.Since(start)))

Expand Down
4 changes: 4 additions & 0 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ const (
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
RefundQuotient uint64 = 2
RefundQuotientEIP3529 uint64 = 5

CalldataGasCostEIP4488 = 3 // NEW_CALLDATA_GAS_COST in EIP-4488
BaseMaxCalldataPerBlockEIP4488 = 1048576 // BASE_MAX_CALLDATA_PER_BLOCK in EIP-4488
CalldataPerTxStipendEIP4488 = 300 // CALLDATA_PER_TX_STIPEND in EIP-4488
)

// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
Expand Down
2 changes: 1 addition & 1 deletion tests/transaction_test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error {
return nil, nil, err
}
// Intrinsic gas
requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, isHomestead, isIstanbul)
requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, isHomestead, isIstanbul, false)
if err != nil {
return nil, nil, err
}
Expand Down

0 comments on commit d1dd0e1

Please sign in to comment.