mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
test paymaster validations
This commit is contained in:
parent
6b7385d6a7
commit
b0b490f350
4 changed files with 83 additions and 18 deletions
|
|
@ -447,10 +447,10 @@ func preparePostOpMessage(vpr *ValidationPhaseResult, chainConfig *params.ChainC
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var paymasterAddress common.Address = [20]byte(tx.PaymasterData[0:20])
|
var paymasterAddress = tx.Paymaster
|
||||||
return &Message{
|
return &Message{
|
||||||
From: chainConfig.EntryPointAddress,
|
From: chainConfig.EntryPointAddress,
|
||||||
To: &paymasterAddress,
|
To: paymasterAddress,
|
||||||
Value: big.NewInt(0),
|
Value: big.NewInt(0),
|
||||||
GasLimit: tx.PaymasterGas - executionResult.UsedGas,
|
GasLimit: tx.PaymasterGas - executionResult.UsedGas,
|
||||||
GasPrice: tx.GasFeeCap,
|
GasPrice: tx.GasFeeCap,
|
||||||
|
|
@ -490,6 +490,9 @@ func validatePaymasterReturnData(data []byte) (context []byte, validAfter, valid
|
||||||
if magicExpected != MAGIC_VALUE_PAYMASTER {
|
if magicExpected != MAGIC_VALUE_PAYMASTER {
|
||||||
return nil, 0, 0, errors.New("paymaster did not return correct MAGIC_VALUE")
|
return nil, 0, 0, errors.New("paymaster did not return correct MAGIC_VALUE")
|
||||||
}
|
}
|
||||||
|
if len(context) > PAYMASTER_MAX_CONTEXT_SIZE {
|
||||||
|
return nil, 0, 0, errors.New("paymaster context too large")
|
||||||
|
}
|
||||||
return context, validAfter, validUntil, nil
|
return context, validAfter, validUntil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"math/big"
|
"math/big"
|
||||||
"slices"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -42,19 +41,6 @@ func TestPaymasterValidationFailure_revert(t *testing.T) {
|
||||||
}, "execution reverted")
|
}, "execution reverted")
|
||||||
}
|
}
|
||||||
|
|
||||||
func asBytes32(a int) []byte {
|
|
||||||
return common.LeftPadBytes(big.NewInt(int64(a)).Bytes(), 32)
|
|
||||||
}
|
|
||||||
func paymasterReturnValue(magic, validAfter, validUntil 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPaymasterValidationFailure_unparseable_return_value(t *testing.T) {
|
func TestPaymasterValidationFailure_unparseable_return_value(t *testing.T) {
|
||||||
|
|
||||||
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
||||||
|
|
@ -65,3 +51,45 @@ func TestPaymasterValidationFailure_unparseable_return_value(t *testing.T) {
|
||||||
Paymaster: &DEFAULT_PAYMASTER,
|
Paymaster: &DEFAULT_PAYMASTER,
|
||||||
}, "invalid paymaster return data")
|
}, "invalid paymaster return data")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPaymasterValidationFailure_wrong_magic(t *testing.T) {
|
||||||
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
||||||
|
withCode(DEFAULT_PAYMASTER.String(), returnWithData(paymasterReturnValue(1, 2, 3, []byte{})), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
PaymasterGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
Paymaster: &DEFAULT_PAYMASTER,
|
||||||
|
}, "paymaster did not return correct MAGIC_VALUE")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaymasterValidationFailure_contextTooLarge(t *testing.T) {
|
||||||
|
//paymaster returning huge context.
|
||||||
|
// first word is magic return value
|
||||||
|
// 2nd word is offset (fixed 64)
|
||||||
|
// 3rd word is length of context (max+1)
|
||||||
|
// then we return the total length of above (context itself is uninitialized string of max+1 zeroes)
|
||||||
|
pmCode := createCode(
|
||||||
|
//vm.PUSH1, 1, vm.PUSH0, vm.RETURN,
|
||||||
|
copyToMemory(core.PackValidationData(core.MAGIC_VALUE_PAYMASTER, 0, 0), 0),
|
||||||
|
copyToMemory(asBytes32(64), 32),
|
||||||
|
copyToMemory(asBytes32(core.PAYMASTER_MAX_CONTEXT_SIZE+1), 64),
|
||||||
|
push(core.PAYMASTER_MAX_CONTEXT_SIZE+96+1), vm.PUSH0, vm.RETURN)
|
||||||
|
|
||||||
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
||||||
|
withCode(DEFAULT_PAYMASTER.String(), pmCode, DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
PaymasterGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
Paymaster: &DEFAULT_PAYMASTER,
|
||||||
|
}, "paymaster context too large")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaymasterValidation_ok(t *testing.T) {
|
||||||
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
||||||
|
withCode(DEFAULT_PAYMASTER.String(), returnWithData(paymasterReturnValue(core.MAGIC_VALUE_PAYMASTER, 0, 0, []byte{})), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
PaymasterGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
Paymaster: &DEFAULT_PAYMASTER,
|
||||||
|
}, "ok")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/status-im/keycard-go/hexutils"
|
"github.com/status-im/keycard-go/hexutils"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -83,6 +84,23 @@ func (tt *testContextBuilder) withCode(addr string, code []byte, balance int64)
|
||||||
return tt
|
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
|
// 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
|
// NOTE: if data is not in 32-byte multiples, it will override the next bytes
|
||||||
// used by RETURN/REVERT
|
// used by RETURN/REVERT
|
||||||
|
|
@ -135,6 +153,8 @@ func createCode(items ...interface{}) []byte {
|
||||||
buffer.WriteByte(byte(v))
|
buffer.WriteByte(byte(v))
|
||||||
case uint16:
|
case uint16:
|
||||||
buffer.Write([]byte{byte(v >> 8), byte(v)})
|
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:
|
case int:
|
||||||
if v >= 256 {
|
if v >= 256 {
|
||||||
panic(fmt.Errorf("int defaults to int8 (byte). use int16, etc: %v", v))
|
panic(fmt.Errorf("int defaults to int8 (byte). use int16, etc: %v", v))
|
||||||
|
|
@ -148,3 +168,17 @@ func createCode(items ...interface{}) []byte {
|
||||||
|
|
||||||
return buffer.Bytes()
|
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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ func TestValidationFailure_sigerror(t *testing.T) {
|
||||||
func TestValidationFailure_validAfter(t *testing.T) {
|
func TestValidationFailure_validAfter(t *testing.T) {
|
||||||
|
|
||||||
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER,
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER,
|
||||||
returnData(core.PackValidationData(core.MAGIC_VALUE_SENDER, 300, 200)), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
returnWithData(core.PackValidationData(core.MAGIC_VALUE_SENDER, 300, 200)), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
||||||
ValidationGas: uint64(1000000000),
|
ValidationGas: uint64(1000000000),
|
||||||
GasFeeCap: big.NewInt(1000000000),
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
}, "RIP-7560 transaction validity not reached yet")
|
}, "RIP-7560 transaction validity not reached yet")
|
||||||
|
|
@ -62,7 +62,7 @@ func TestValidationFailure_validAfter(t *testing.T) {
|
||||||
func TestValidationFailure_validUntil(t *testing.T) {
|
func TestValidationFailure_validUntil(t *testing.T) {
|
||||||
|
|
||||||
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER,
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER,
|
||||||
returnData(core.PackValidationData(core.MAGIC_VALUE_SENDER, 1, 0)), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
returnWithData(core.PackValidationData(core.MAGIC_VALUE_SENDER, 1, 0)), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
||||||
ValidationGas: uint64(1000000000),
|
ValidationGas: uint64(1000000000),
|
||||||
GasFeeCap: big.NewInt(1000000000),
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
}, "RIP-7560 transaction validity expired")
|
}, "RIP-7560 transaction validity expired")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue