mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
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.)
150 lines
3.9 KiB
Go
150 lines
3.9 KiB
Go
package rip7560
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
|
"github.com/status-im/keycard-go/hexutils"
|
|
"math/big"
|
|
"testing"
|
|
)
|
|
|
|
const DEFAULT_SENDER = "0x1111111111222222222233333333334444444444"
|
|
const DEFAULT_BALANCE = 1 << 62
|
|
|
|
type testContext struct {
|
|
genesisAlloc types.GenesisAlloc
|
|
t *testing.T
|
|
chainContext *ethapi.ChainContext
|
|
gaspool *core.GasPool
|
|
genesis *core.Genesis
|
|
genesisBlock *types.Block
|
|
}
|
|
|
|
func newTestContext(t *testing.T) *testContext {
|
|
return newTestContextBuilder(t).build()
|
|
}
|
|
|
|
type testContextBuilder struct {
|
|
t *testing.T
|
|
genesisAlloc types.GenesisAlloc
|
|
}
|
|
|
|
func newTestContextBuilder(t *testing.T) *testContextBuilder {
|
|
genesisAlloc := types.GenesisAlloc{}
|
|
|
|
return &testContextBuilder{
|
|
t: t,
|
|
genesisAlloc: genesisAlloc,
|
|
}
|
|
}
|
|
|
|
func (tb *testContextBuilder) build() *testContext {
|
|
genesis := core.DeveloperGenesisBlock(10_000_000, &common.Address{})
|
|
genesis.Timestamp = 100
|
|
genesisBlock := genesis.ToBlock()
|
|
gaspool := new(core.GasPool).AddGas(genesisBlock.GasLimit())
|
|
|
|
//TODO: fill some mock backend...
|
|
var backend ethapi.Backend
|
|
|
|
return &testContext{
|
|
t: tb.t,
|
|
genesisAlloc: tb.genesisAlloc,
|
|
chainContext: ethapi.NewChainContext(context.TODO(), backend),
|
|
genesis: genesis,
|
|
genesisBlock: genesisBlock,
|
|
gaspool: gaspool,
|
|
}
|
|
}
|
|
|
|
// add EOA account with balance
|
|
func (tt *testContextBuilder) withAccount(addr string, balance int64) *testContextBuilder {
|
|
tt.genesisAlloc[common.HexToAddress(addr)] = types.Account{Balance: big.NewInt(balance)}
|
|
return tt
|
|
}
|
|
|
|
func (tt *testContextBuilder) withCode(addr string, code []byte, balance int64) *testContextBuilder {
|
|
if len(code) == 0 {
|
|
tt.genesisAlloc[common.HexToAddress(addr)] = types.Account{
|
|
Balance: big.NewInt(balance),
|
|
}
|
|
} else {
|
|
tt.genesisAlloc[common.HexToAddress(addr)] = types.Account{
|
|
Code: code,
|
|
Balance: big.NewInt(balance),
|
|
}
|
|
}
|
|
return tt
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
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 returnWithData(core.PackValidationData(core.MAGIC_VALUE_SENDER, 0, 0))
|
|
}
|
|
|
|
// create EVM code from OpCode, byte and []bytes
|
|
func createCode(items ...interface{}) []byte {
|
|
var buffer bytes.Buffer
|
|
|
|
for _, item := range items {
|
|
switch v := item.(type) {
|
|
case string:
|
|
buffer.Write(hexutils.HexToBytes(v))
|
|
case vm.OpCode:
|
|
buffer.WriteByte(byte(v))
|
|
case byte:
|
|
buffer.WriteByte(v)
|
|
case []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). use int16, etc: %v", v))
|
|
}
|
|
buffer.WriteByte(byte(v))
|
|
default:
|
|
// should be a compile-time error...
|
|
panic(fmt.Errorf("unsupported type: %T", v))
|
|
}
|
|
}
|
|
|
|
return buffer.Bytes()
|
|
}
|