From 6b7385d6a7a5b7323e44551b33aebb9622f4e732 Mon Sep 17 00:00:00 2001 From: Dror Tirosh Date: Mon, 1 Jul 2024 14:17:25 +0300 Subject: [PATCH] returnWithData, revertWithData arbitrary-length return or revert (currently, can't test it, since we check "error", and actual revert data is hidden. will be probably needed when testing paymaster.) --- tests/rip7560/rip7560TestUtils.go | 38 +++++++++++++++++++++++-------- tests/rip7560/validation_test.go | 15 +++++++----- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/tests/rip7560/rip7560TestUtils.go b/tests/rip7560/rip7560TestUtils.go index 1e50d9b7fb..a60b473066 100644 --- a/tests/rip7560/rip7560TestUtils.go +++ b/tests/rip7560/rip7560TestUtils.go @@ -83,20 +83,38 @@ func (tt *testContextBuilder) withCode(addr string, code []byte, balance int64) return tt } -// generate the code to return the given byte array (up to 32 bytes) -func returnData(data []byte) []byte { - datalen := len(data) - if datalen > 32 { - panic(fmt.Errorf("data length is too big %v", data)) +// create code to copy data into memory at the given offset +// NOTE: if data is not in 32-byte multiples, it will override the next bytes +// used by RETURN/REVERT +func copyToMemory(data []byte, offset uint) []byte { + ret := []byte{} + for len(data) > 32 { + ret = append(ret, createCode(vm.PUSH32, data[0:32], vm.PUSH2, uint16(offset), vm.MSTORE)...) + data = data[32:] + offset = offset + 32 } - PUSHn := byte(int(vm.PUSH0) + datalen) - ret := createCode(PUSHn, data, vm.PUSH0, vm.MSTORE, vm.PUSH1, datalen, vm.PUSH1, 0, vm.RETURN) + if len(data) > 0 { + PUSHn := byte(int(vm.PUSH0) + len(data)) + ret = append(ret, createCode(PUSHn, data, vm.PUSH2, uint16(offset), vm.MSTORE)...) + } + return ret +} + +// revert with given data +func revertWithData(data []byte) []byte { + ret := append(copyToMemory(data, 0), createCode(vm.PUSH2, uint16(len(data)), vm.PUSH0, vm.REVERT)...) + return ret +} + +// generate the code to return the given byte array (up to 32 bytes) +func returnWithData(data []byte) []byte { + ret := append(copyToMemory(data, 0), createCode(vm.PUSH2, uint16(len(data)), vm.PUSH0, vm.RETURN)...) return ret } func createAccountCode() []byte { - return returnData(core.PackValidationData(core.MAGIC_VALUE_SENDER, 0, 0)) + return returnWithData(core.PackValidationData(core.MAGIC_VALUE_SENDER, 0, 0)) } // create EVM code from OpCode, byte and []bytes @@ -115,9 +133,11 @@ func createCode(items ...interface{}) []byte { buffer.Write(v) case int8: buffer.WriteByte(byte(v)) + case uint16: + buffer.Write([]byte{byte(v >> 8), byte(v)}) case int: if v >= 256 { - panic(fmt.Errorf("int defaults to int8 (byte). int16, etc: %v", v)) + panic(fmt.Errorf("int defaults to int8 (byte). use int16, etc: %v", v)) } buffer.WriteByte(byte(v)) default: diff --git a/tests/rip7560/validation_test.go b/tests/rip7560/validation_test.go index cdbd5d3c24..1afec6c7f0 100644 --- a/tests/rip7560/validation_test.go +++ b/tests/rip7560/validation_test.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/tests" + "github.com/status-im/keycard-go/hexutils" "github.com/stretchr/testify/assert" "math/big" "testing" @@ -43,7 +44,7 @@ func TestValidationFailure_no_balance(t *testing.T) { } func TestValidationFailure_sigerror(t *testing.T) { - handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, returnData(core.PackValidationData(core.MAGIC_VALUE_SIGFAIL, 0, 0)), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ + handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, returnWithData(core.PackValidationData(core.MAGIC_VALUE_SIGFAIL, 0, 0)), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ ValidationGas: uint64(1000000000), GasFeeCap: big.NewInt(1000000000), }, "account signature error") @@ -104,9 +105,11 @@ func TestValidationFailure_account_revert(t *testing.T) { }, "execution reverted") } -func TestValidationFailure_account_out_of_range(t *testing.T) { +func TestValidationFailure_account_revert_with_reason(t *testing.T) { + // cast abi-encode 'Error(string)' hello + reason := hexutils.HexToBytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000") handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, - createCode(vm.PUSH0, vm.DUP1, vm.REVERT), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ + revertWithData(reason), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ ValidationGas: uint64(1000000000), GasFeeCap: big.NewInt(1000000000), }, "execution reverted") @@ -114,7 +117,7 @@ func TestValidationFailure_account_out_of_range(t *testing.T) { func TestValidationFailure_account_wrong_return_length(t *testing.T) { handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, - returnData([]byte{1, 2, 3}), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ + returnWithData([]byte{1, 2, 3}), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ ValidationGas: uint64(1000000000), GasFeeCap: big.NewInt(1000000000), }, "invalid account return data length") @@ -122,7 +125,7 @@ func TestValidationFailure_account_wrong_return_length(t *testing.T) { func TestValidationFailure_account_no_return_value(t *testing.T) { handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, - returnData([]byte{}), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ + returnWithData([]byte{}), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ ValidationGas: uint64(1000000000), GasFeeCap: big.NewInt(1000000000), }, "invalid account return data length") @@ -131,7 +134,7 @@ func TestValidationFailure_account_no_return_value(t *testing.T) { func TestValidationFailure_account_wrong_return_value(t *testing.T) { // create buffer of 32 byte array handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, - returnData(make([]byte, 32)), + returnWithData(make([]byte, 32)), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{ ValidationGas: uint64(1000000000), GasFeeCap: big.NewInt(1000000000),