go-ethereum/tests/rip7560/rip7560TestUtils.go
2024-07-07 12:42:14 +03:00

184 lines
4.8 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"
"slices"
"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
}
// generate a push opcode and its following constant value
func push(n int) []byte {
if n < 0 {
panic("attempt to push negative")
}
if n < 256 {
return createCode(vm.PUSH1, byte(n))
}
if n < 65536 {
return createCode(vm.PUSH2, byte(n>>8), byte(n))
}
if n < 1<<32 {
return createCode(vm.PUSH4, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
}
panic("larger number")
}
// 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 uint32:
buffer.Write([]byte{byte(v >> 24), byte(v >> 16), 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()
}
func asBytes32(a int) []byte {
return common.LeftPadBytes(big.NewInt(int64(a)).Bytes(), 32)
}
func paymasterReturnValue(magic, validUntil, validAfter uint64, context []byte) []byte {
validationData := core.PackValidationData(magic, validUntil, validAfter)
//manual encode (bytes32 validationData, bytes context)
return slices.Concat(
common.LeftPadBytes(validationData, 32),
asBytes32(64),
asBytes32(len(context)),
context)
}