mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
initial paymaster test flows
This commit is contained in:
parent
1fc0bd420e
commit
95a378640e
2 changed files with 91 additions and 8 deletions
|
|
@ -37,9 +37,16 @@ func UnpackValidationData(validationData []byte) (authorizerMagic uint64, validU
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnpackPaymasterValidationReturn(paymasterValidationReturn []byte) (validationData, context []byte) {
|
func UnpackPaymasterValidationReturn(paymasterValidationReturn []byte) (validationData, context []byte) {
|
||||||
|
if len(paymasterValidationReturn) < 96 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
validationData = paymasterValidationReturn[0:32]
|
validationData = paymasterValidationReturn[0:32]
|
||||||
//2nd bytes32 is ignored (its an offset value)
|
//2nd bytes32 is ignored (its an offset value)
|
||||||
contextLen := new(big.Int).SetBytes(paymasterValidationReturn[64:96])
|
contextLen := new(big.Int).SetBytes(paymasterValidationReturn[64:96])
|
||||||
|
if uint64(len(paymasterValidationReturn)) < 96+contextLen.Uint64() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
context = paymasterValidationReturn[96 : 96+contextLen.Uint64()]
|
context = paymasterValidationReturn[96 : 96+contextLen.Uint64()]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -133,17 +140,17 @@ func BuyGasRip7560Transaction(st *types.Rip7560AccountAbstractionTx, state vm.St
|
||||||
mgval = mgval.Mul(mgval, gasFeeCap)
|
mgval = mgval.Mul(mgval, gasFeeCap)
|
||||||
balanceCheck := new(uint256.Int).Set(mgval)
|
balanceCheck := new(uint256.Int).Set(mgval)
|
||||||
|
|
||||||
chargeFrom := *st.Sender
|
chargeFrom := st.Sender
|
||||||
|
|
||||||
if len(st.PaymasterData) >= 20 {
|
if st.Paymaster != nil {
|
||||||
chargeFrom = [20]byte(st.PaymasterData[:20])
|
chargeFrom = st.Paymaster
|
||||||
}
|
}
|
||||||
|
|
||||||
if have, want := state.GetBalance(chargeFrom), balanceCheck; have.Cmp(want) < 0 {
|
if have, want := state.GetBalance(*chargeFrom), balanceCheck; have.Cmp(want) < 0 {
|
||||||
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, chargeFrom.Hex(), have, want)
|
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, chargeFrom.Hex(), have, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SubBalance(chargeFrom, mgval, 0)
|
state.SubBalance(*chargeFrom, mgval, 0)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,6 +217,9 @@ func ApplyRip7560ValidationPhases(chainConfig *params.ChainConfig, bc ChainConte
|
||||||
}
|
}
|
||||||
|
|
||||||
paymasterContext, pmValidationUsedGas, pmValidAfter, pmValidUntil, err := applyPaymasterValidationFrame(tx, chainConfig, signingHash, evm, gp, statedb, header)
|
paymasterContext, pmValidationUsedGas, pmValidAfter, pmValidUntil, err := applyPaymasterValidationFrame(tx, chainConfig, signingHash, evm, gp, statedb, header)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
vpr := &ValidationPhaseResult{
|
vpr := &ValidationPhaseResult{
|
||||||
Tx: tx,
|
Tx: tx,
|
||||||
TxHash: tx.Hash(),
|
TxHash: tx.Hash(),
|
||||||
|
|
@ -241,6 +251,9 @@ func applyPaymasterValidationFrame(tx *types.Transaction, chainConfig *params.Ch
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, 0, err
|
return nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
|
if resultPm.Failed() {
|
||||||
|
return nil, 0, 0, 0, resultPm.Err
|
||||||
|
}
|
||||||
statedb.IntermediateRoot(true)
|
statedb.IntermediateRoot(true)
|
||||||
if resultPm.Failed() {
|
if resultPm.Failed() {
|
||||||
return nil, 0, 0, 0, errors.New("paymaster validation failed - invalid transaction")
|
return nil, 0, 0, 0, errors.New("paymaster validation failed - invalid transaction")
|
||||||
|
|
@ -370,10 +383,10 @@ func prepareAccountValidationMessage(baseTx *types.Transaction, chainConfig *par
|
||||||
|
|
||||||
func preparePaymasterValidationMessage(baseTx *types.Transaction, config *params.ChainConfig, signingHash common.Hash) (*Message, error) {
|
func preparePaymasterValidationMessage(baseTx *types.Transaction, config *params.ChainConfig, signingHash common.Hash) (*Message, error) {
|
||||||
tx := baseTx.Rip7560TransactionData()
|
tx := baseTx.Rip7560TransactionData()
|
||||||
if len(tx.PaymasterData) < 20 {
|
paymasterAddress := tx.Paymaster
|
||||||
|
if paymasterAddress == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var paymasterAddress common.Address = [20]byte(tx.PaymasterData[0:20])
|
|
||||||
jsondata := `[
|
jsondata := `[
|
||||||
{"type":"function","name":"validatePaymasterTransaction","inputs": [{"name": "version","type": "uint256"},{"name": "txHash","type": "bytes32"},{"name": "transaction","type": "bytes"}]}
|
{"type":"function","name":"validatePaymasterTransaction","inputs": [{"name": "version","type": "uint256"},{"name": "txHash","type": "bytes32"},{"name": "transaction","type": "bytes"}]}
|
||||||
]`
|
]`
|
||||||
|
|
@ -387,7 +400,7 @@ func preparePaymasterValidationMessage(baseTx *types.Transaction, config *params
|
||||||
}
|
}
|
||||||
return &Message{
|
return &Message{
|
||||||
From: config.EntryPointAddress,
|
From: config.EntryPointAddress,
|
||||||
To: &paymasterAddress,
|
To: paymasterAddress,
|
||||||
Value: big.NewInt(0),
|
Value: big.NewInt(0),
|
||||||
GasLimit: tx.PaymasterGas,
|
GasLimit: tx.PaymasterGas,
|
||||||
GasPrice: tx.GasFeeCap,
|
GasPrice: tx.GasFeeCap,
|
||||||
|
|
@ -470,6 +483,9 @@ func validatePaymasterReturnData(data []byte) (context []byte, validAfter, valid
|
||||||
return nil, 0, 0, errors.New("invalid paymaster return data length")
|
return nil, 0, 0, errors.New("invalid paymaster return data length")
|
||||||
}
|
}
|
||||||
validationData, context := UnpackPaymasterValidationReturn(data)
|
validationData, context := UnpackPaymasterValidationReturn(data)
|
||||||
|
if validationData == nil {
|
||||||
|
return nil, 0, 0, errors.New("invalid paymaster return data")
|
||||||
|
}
|
||||||
magicExpected, validAfter, validUntil := UnpackValidationData(validationData)
|
magicExpected, validAfter, validUntil := UnpackValidationData(validationData)
|
||||||
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")
|
||||||
|
|
|
||||||
67
tests/rip7560/paymaster_test.go
Normal file
67
tests/rip7560/paymaster_test.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package rip7560
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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"
|
||||||
|
"math/big"
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DEFAULT_PAYMASTER = common.HexToAddress("0xaaaaaaaaaabbbbbbbbbbccccccccccdddddddddd")
|
||||||
|
|
||||||
|
func TestPaymasterValidationFailure_nobalance(t *testing.T) {
|
||||||
|
|
||||||
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
||||||
|
withCode(DEFAULT_PAYMASTER.String(), createCode(vm.PUSH0, vm.DUP1, vm.REVERT), 1), types.Rip7560AccountAbstractionTx{
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
Paymaster: &DEFAULT_PAYMASTER,
|
||||||
|
}, "insufficient funds for gas * price + value: address 0xaaAaaAAAAAbBbbbbBbBBCCCCcCCCcCdddDDDdddd have 1 want 1000000000000000000")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaymasterValidationFailure_oog(t *testing.T) {
|
||||||
|
|
||||||
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
||||||
|
withCode(DEFAULT_PAYMASTER.String(), createCode(vm.PUSH0, vm.DUP1, vm.REVERT), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
Paymaster: &DEFAULT_PAYMASTER,
|
||||||
|
}, "out of gas")
|
||||||
|
}
|
||||||
|
func TestPaymasterValidationFailure_revert(t *testing.T) {
|
||||||
|
|
||||||
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
||||||
|
withCode(DEFAULT_PAYMASTER.String(), createCode(vm.PUSH0, vm.DUP1, vm.REVERT), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
||||||
|
ValidationGas: uint64(1000000000),
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
Paymaster: &DEFAULT_PAYMASTER,
|
||||||
|
PaymasterGas: 1000000000,
|
||||||
|
}, "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) {
|
||||||
|
|
||||||
|
handleTransaction(newTestContextBuilder(t).withCode(DEFAULT_SENDER, createAccountCode(), 0).
|
||||||
|
withCode(DEFAULT_PAYMASTER.String(), createAccountCode(), DEFAULT_BALANCE), types.Rip7560AccountAbstractionTx{
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
PaymasterGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
Paymaster: &DEFAULT_PAYMASTER,
|
||||||
|
}, "invalid paymaster return data")
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue