From 97a8454af21a148a511a87b68908ece0c6e3e543 Mon Sep 17 00:00:00 2001 From: Goran Rojovic Date: Fri, 9 Feb 2024 16:15:37 +0100 Subject: [PATCH] Tests fixes --- state/executor.go | 46 +++++++++++++++++++++++++------ state/runtime/precompiled/base.go | 6 +++- state/runtime/runtime.go | 5 ++-- state/txn.go | 19 +++++++++++-- tests/state_test_util.go | 29 +++++++++++-------- 5 files changed, 79 insertions(+), 26 deletions(-) diff --git a/state/executor.go b/state/executor.go index 4e05967281..a7beb114af 100644 --- a/state/executor.go +++ b/state/executor.go @@ -466,10 +466,17 @@ func (t *Transition) subGasLimitPrice(msg *types.Transaction) error { } func (t *Transition) nonceCheck(msg *types.Transaction) error { - nonce := t.state.GetNonce(msg.From()) + currentNonce := t.state.GetNonce(msg.From()) - if nonce != msg.Nonce() { - return ErrNonceIncorrect + if msgNonce := msg.Nonce(); currentNonce < msgNonce { + return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh, + msg.From(), msgNonce, currentNonce) + } else if currentNonce > msgNonce { + return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow, + msg.From(), msgNonce, currentNonce) + } else if currentNonce+1 < currentNonce { + return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax, + msg.From(), currentNonce) } return nil @@ -517,7 +524,9 @@ func (t *Transition) checkDynamicFees(msg *types.Transaction) error { // surfacing of these errors reject the transaction thus not including it in the block var ( - ErrNonceIncorrect = errors.New("incorrect nonce") + ErrNonceTooLow = errors.New("nonce too low") + ErrNonceTooHigh = errors.New("nonce too high") + ErrNonceMax = errors.New("nonce has max value") ErrNotEnoughFundsForGas = errors.New("not enough funds to cover gas costs") ErrBlockLimitReached = errors.New("gas limit reached in the pool") ErrIntrinsicGasOverflow = errors.New("overflow in intrinsic gas calculation") @@ -631,8 +640,13 @@ func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, er result = t.Call2(msg.From(), *(msg.To()), msg.Input(), value, gasLeft, initialAccessList) } + refundQuotient := LegacyRefundQuotient + if t.config.London { + refundQuotient = LondonRefundQuotient + } + refund := t.state.GetRefund() - result.UpdateGasUsed(msg.Gas(), refund) + result.UpdateGasUsed(msg.Gas(), refund, refundQuotient) if t.ctx.Tracer != nil { t.ctx.Tracer.TxEnd(result.GasLeft) @@ -660,10 +674,10 @@ func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, er // Burn some amount if the london hardfork is applied. // Basically, burn amount is just transferred to the current burn contract. - if t.config.London && msg.Type() != types.StateTx { - burnAmount := new(big.Int).Mul(new(big.Int).SetUint64(result.GasUsed), t.ctx.BaseFee) - t.state.AddBalance(t.ctx.BurnContract, burnAmount) - } + // if t.config.London && msg.Type() != types.StateTx { + // burnAmount := new(big.Int).Mul(new(big.Int).SetUint64(result.GasUsed), t.ctx.BaseFee) + // t.state.AddBalance(t.ctx.BurnContract, burnAmount) + // } // return gas to the pool t.addGasPool(result.GasLeft) @@ -948,6 +962,20 @@ func (t *Transition) applyCreate(c *runtime.Contract, host runtime.Host) *runtim } } + // Reject code starting with 0xEF if EIP-3541 is enabled. + if result.Err == nil && len(result.ReturnValue) >= 1 && result.ReturnValue[0] == 0xEF && t.config.London { + if err := t.state.RevertToSnapshot(snapshot); err != nil { + return &runtime.ExecutionResult{ + Err: err, + } + } + + return &runtime.ExecutionResult{ + GasLeft: 0, + Err: runtime.ErrInvalidCode, + } + } + gasCost := uint64(len(result.ReturnValue)) * 200 if result.GasLeft < gasCost { diff --git a/state/runtime/precompiled/base.go b/state/runtime/precompiled/base.go index 06f1e76429..9997d4ebdc 100644 --- a/state/runtime/precompiled/base.go +++ b/state/runtime/precompiled/base.go @@ -39,7 +39,11 @@ func (e *ecrecover) run(input []byte, caller types.Address, _ runtime.Host) ([]b return nil, nil } - pubKey, err := crypto.Ecrecover(input[:32], append(input[64:128], v)) + sig := make([]byte, 65) + copy(sig, input[64:128]) + sig[64] = v + + pubKey, err := crypto.Ecrecover(input[:32], sig) if err != nil { return nil, nil } diff --git a/state/runtime/runtime.go b/state/runtime/runtime.go index cfe865b2b9..fa4ecddbe2 100644 --- a/state/runtime/runtime.go +++ b/state/runtime/runtime.go @@ -119,11 +119,11 @@ func (r *ExecutionResult) Succeeded() bool { return r.Err == nil } func (r *ExecutionResult) Failed() bool { return r.Err != nil } func (r *ExecutionResult) Reverted() bool { return errors.Is(r.Err, ErrExecutionReverted) } -func (r *ExecutionResult) UpdateGasUsed(gasLimit uint64, refund uint64) { +func (r *ExecutionResult) UpdateGasUsed(gasLimit uint64, refund, refundQuotient uint64) { r.GasUsed = gasLimit - r.GasLeft // Refund can go up to half the gas used - if maxRefund := r.GasUsed / 2; refund > maxRefund { + if maxRefund := r.GasUsed / refundQuotient; refund > maxRefund { refund = maxRefund } @@ -143,6 +143,7 @@ var ( ErrUnauthorizedCaller = errors.New("unauthorized caller") ErrInvalidInputData = errors.New("invalid input data") ErrNotAuth = errors.New("not in allow list") + ErrInvalidCode = errors.New("invalid code: must not begin with 0xef") ) // StackUnderflowError wraps an evm error when the items on the stack less diff --git a/state/txn.go b/state/txn.go index c4578ae333..0eeb618ff7 100644 --- a/state/txn.go +++ b/state/txn.go @@ -16,6 +16,14 @@ import ( var emptyStateHash = types.StringToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") +const ( + BerlinClearingRefund = uint64(15000) + LondonClearingRefund = uint64(4800) + + LegacyRefundQuotient = uint64(2) + LondonRefundQuotient = uint64(5) +) + type readSnapshot interface { GetStorage(addr types.Address, root types.Hash, key types.Hash) types.Hash GetAccount(addr types.Address) (*Account, error) @@ -247,13 +255,18 @@ func (txn *Txn) SetStorage( return runtime.StorageModified } + clearingRefund := BerlinClearingRefund + if config.London { + clearingRefund = LondonClearingRefund + } + if original == current { if original == types.ZeroHash { // create slot (2.1.1) return runtime.StorageAdded } if value == types.ZeroHash { // delete slot (2.1.2b) - txn.AddRefund(15000) + txn.AddRefund(clearingRefund) return runtime.StorageDeleted } @@ -263,9 +276,9 @@ func (txn *Txn) SetStorage( if original != types.ZeroHash { // Storage slot was populated before this transaction started if current == types.ZeroHash { // recreate slot (2.2.1.1) - txn.SubRefund(15000) + txn.SubRefund(clearingRefund) } else if value == types.ZeroHash { // delete slot (2.2.1.2) - txn.AddRefund(15000) + txn.AddRefund(clearingRefund) } } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 322447d31f..01a3cb0dd7 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -347,7 +347,13 @@ func (t *stTransaction) At(i indexes, baseFee *big.Int) (*types.Transaction, err }), nil } + txType := types.LegacyTx + if isDynamicTransaction { + txType = types.DynamicFeeTx + } + return types.NewTx(&types.MixedTxn{ + Type: txType, From: t.From, To: t.To, Nonce: t.Nonce, @@ -561,17 +567,18 @@ var Forks = map[string]*chain.Forks{ chain.Berlin: chain.NewFork(0), chain.London: chain.NewFork(5), }, - // "London": { - // chain.Homestead: chain.NewFork(0), - // chain.EIP150: chain.NewFork(0), - // chain.EIP155: chain.NewFork(0), - // chain.EIP158: chain.NewFork(0), - // chain.Byzantium: chain.NewFork(0), - // chain.Constantinople: chain.NewFork(0), - // chain.Petersburg: chain.NewFork(0), - // chain.Istanbul: chain.NewFork(0), - // chain.London: chain.NewFork(0), - // }, + "London": { + chain.Homestead: chain.NewFork(0), + chain.EIP150: chain.NewFork(0), + chain.EIP155: chain.NewFork(0), + chain.EIP158: chain.NewFork(0), + chain.Byzantium: chain.NewFork(0), + chain.Constantinople: chain.NewFork(0), + chain.Petersburg: chain.NewFork(0), + chain.Istanbul: chain.NewFork(0), + chain.Berlin: chain.NewFork(0), + chain.London: chain.NewFork(0), + }, } func contains(l []string, name string) bool {