From 66ef4cf198aa2a9a60ba485dc3287537a544d697 Mon Sep 17 00:00:00 2001 From: cby3149 Date: Fri, 20 Jan 2023 13:54:59 -0800 Subject: [PATCH] Add gascap and check input on hybrid compute and add unit tests (cherry picked from commit 61b1e85adeb41388ca7d5eeb38a2987660a8179b) --- l2geth/boba/boba_turing_call_test.go | 104 +++++++++++++++++++++++++++ l2geth/core/vm/errors.go | 1 + l2geth/core/vm/evm.go | 5 ++ ops/scripts/geth.sh | 1 + 4 files changed, 111 insertions(+) create mode 100644 l2geth/boba/boba_turing_call_test.go diff --git a/l2geth/boba/boba_turing_call_test.go b/l2geth/boba/boba_turing_call_test.go new file mode 100644 index 0000000000..72ee01b9c7 --- /dev/null +++ b/l2geth/boba/boba_turing_call_test.go @@ -0,0 +1,104 @@ +package boba + +import ( + "errors" + "math/big" + "testing" + + "github.com/ethereum-optimism/optimism/l2geth/common" + "github.com/ethereum-optimism/optimism/l2geth/common/hexutil" + "github.com/ethereum-optimism/optimism/l2geth/core" + "github.com/ethereum-optimism/optimism/l2geth/core/rawdb" + "github.com/ethereum-optimism/optimism/l2geth/core/state" + "github.com/ethereum-optimism/optimism/l2geth/core/vm" + "github.com/ethereum-optimism/optimism/l2geth/crypto" + "github.com/ethereum-optimism/optimism/l2geth/params" + "github.com/ethereum-optimism/optimism/l2geth/tests" +) + +var ( + ErrTuringInputTooShort = errors.New("turing input too short") + ErrTuringEmpty = errors.New("turing replay data not found") + contractAddr = common.HexToAddress("0x00000000000000000000000000000000deadbeef") + EOAAddr = common.HexToAddress("0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266") +) + +type ContractRef struct{} + +func (ContractRef) Address() common.Address { return contractAddr } + +func vmTestBlockHash(n uint64) common.Hash { + return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) +} + +func newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM { + initialCall := true + canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool { + if initialCall { + initialCall = false + return true + } + return core.CanTransfer(db, address, amount) + } + transfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {} + context := vm.Context{ + CanTransfer: canTransfer, + Transfer: transfer, + GetHash: vmTestBlockHash, + Origin: EOAAddr, + Coinbase: EOAAddr, + BlockNumber: new(big.Int).SetUint64(0), + Time: new(big.Int).SetUint64(0), + GasLimit: 0, + Difficulty: common.Big1, + GasPrice: common.Big1, + } + vmconfig.NoRecursion = true + return vm.NewEVM(context, statedb, params.MainnetChainConfig, vmconfig) +} + +func createStateDB() *state.StateDB { + alloc := core.GenesisAlloc{} + alloc[contractAddr] = core.GenesisAccount{ + Nonce: 1, + Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"), + Balance: big.NewInt(1), + } + statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc) + return statedb +} + +func TestHybridComputeShortInput(t *testing.T) { + errTuringInput := []byte{125, 147, 97, 108} + TuringInput := append(errTuringInput[:], make([]byte, 32)...) + statedb := createStateDB() + evm := newEVM(statedb, vm.Config{}) + if _, _, err := evm.Call(ContractRef{}, EOAAddr, errTuringInput, 0, common.Big0); err == ErrTuringInputTooShort { + t.Fatalf("should return 'turing input too short', but got err %v", err) + } + if _, _, err := evm.Call(ContractRef{}, EOAAddr, TuringInput, 0, common.Big0); err == ErrTuringEmpty { + t.Fatalf("should return 'turing replay data not found', but got err %v", err) + } +} + +func TestHybridComputeGetRandomShortInput(t *testing.T) { + errGetRandInput := []byte{73, 61, 87, 214} + getRandInputInput := append(errGetRandInput[:], make([]byte, 32)...) + statedb := createStateDB() + evm := newEVM(statedb, vm.Config{}) + if _, _, err := evm.Call(ContractRef{}, EOAAddr, errGetRandInput, 0, common.Big0); err == ErrTuringInputTooShort { + t.Fatalf("should return 'turing input too short', but got err %v", err) + } + if _, _, err := evm.Call(ContractRef{}, EOAAddr, getRandInputInput, 0, common.Big0); err == ErrTuringEmpty { + t.Fatalf("should return 'turing replay data not found', but got err %v", err) + } +} + +func TestShortInput(t *testing.T) { + standardInput := []byte{0, 0, 0, 0} + statedb := createStateDB() + evm := newEVM(statedb, vm.Config{}) + if _, _, err := evm.Call(ContractRef{}, EOAAddr, standardInput, 0, common.Big0); err != nil { + t.Fatalf("should return nil, but got err %v", err) + } +} diff --git a/l2geth/core/vm/errors.go b/l2geth/core/vm/errors.go index 1ab52fd982..197219400e 100644 --- a/l2geth/core/vm/errors.go +++ b/l2geth/core/vm/errors.go @@ -30,4 +30,5 @@ var ( ErrTuringDepth = errors.New("turing call depth exceeded") ErrTuringEmpty = errors.New("turing replay data not found") ErrGasUintOverflow = errors.New("gas uint64 overflow") + ErrTuringInputTooShort = errors.New("turing input too short") ) diff --git a/l2geth/core/vm/evm.go b/l2geth/core/vm/evm.go index ac28fbaa16..13d8b0e43f 100644 --- a/l2geth/core/vm/evm.go +++ b/l2geth/core/vm/evm.go @@ -617,6 +617,11 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Sanity and depth checks if isTuring2 || isGetRand2 { log.Debug("TURING REQUEST START", "input", input, "len(evm.Context.Turing)", len(evm.Context.Turing)) + // Check 0. the payload must be at least 36 bytes long + if len(input) < 36 { + log.Error("TURING ERROR: INPUT TOO SHORT", "input", input) + return nil, gas, ErrTuringInputTooShort + } // Check 1. can only run Turing once anywhere in the call stack if evm.Context.TuringDepth > 1 { log.Error("TURING ERROR: DEPTH > 1", "evm.Context.TuringDepth", evm.Context.TuringDepth) diff --git a/ops/scripts/geth.sh b/ops/scripts/geth.sh index 80b5e70b40..48df9cbf54 100755 --- a/ops/scripts/geth.sh +++ b/ops/scripts/geth.sh @@ -51,4 +51,5 @@ exec geth \ --mine \ --miner.etherbase $BLOCK_SIGNER_ADDRESS \ --rangelimit \ + --rpc.gascap ${GAS_CAP:-11000000} \ "$@"