mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
Merge pull request #14 from eth-infinitism/test-deployer-flows
AA-379 Test deployer flows
This commit is contained in:
commit
2312c4fdde
3 changed files with 142 additions and 15 deletions
|
|
@ -177,8 +177,9 @@ func CheckNonceRip7560(tx *types.Rip7560AccountAbstractionTx, st *state.StateDB)
|
||||||
|
|
||||||
func ApplyRip7560ValidationPhases(chainConfig *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cfg vm.Config) (*ValidationPhaseResult, error) {
|
func ApplyRip7560ValidationPhases(chainConfig *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, cfg vm.Config) (*ValidationPhaseResult, error) {
|
||||||
blockContext := NewEVMBlockContext(header, bc, author)
|
blockContext := NewEVMBlockContext(header, bc, author)
|
||||||
|
sender := tx.Rip7560TransactionData().Sender
|
||||||
txContext := vm.TxContext{
|
txContext := vm.TxContext{
|
||||||
Origin: *tx.Rip7560TransactionData().Sender,
|
Origin: *sender,
|
||||||
GasPrice: tx.GasFeeCap(),
|
GasPrice: tx.GasFeeCap(),
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(blockContext, txContext, statedb, chainConfig, cfg)
|
evm := vm.NewEVM(blockContext, txContext, statedb, chainConfig, cfg)
|
||||||
|
|
@ -186,16 +187,25 @@ func ApplyRip7560ValidationPhases(chainConfig *params.ChainConfig, bc ChainConte
|
||||||
deployerMsg := prepareDeployerMessage(tx, chainConfig)
|
deployerMsg := prepareDeployerMessage(tx, chainConfig)
|
||||||
var deploymentUsedGas uint64
|
var deploymentUsedGas uint64
|
||||||
if deployerMsg != nil {
|
if deployerMsg != nil {
|
||||||
resultDeployer, err := ApplyMessage(evm, deployerMsg, gp)
|
var err error
|
||||||
|
var resultDeployer *ExecutionResult
|
||||||
|
if statedb.GetCodeSize(*sender) != 0 {
|
||||||
|
err = errors.New("sender already deployed")
|
||||||
|
} else {
|
||||||
|
resultDeployer, err = ApplyMessage(evm, deployerMsg, gp)
|
||||||
|
}
|
||||||
|
if err == nil && resultDeployer != nil {
|
||||||
|
err = resultDeployer.Err
|
||||||
|
deploymentUsedGas = resultDeployer.UsedGas
|
||||||
|
}
|
||||||
|
if err == nil && statedb.GetCodeSize(*sender) == 0 {
|
||||||
|
err = errors.New("sender not deployed")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
// TODO: bubble up the inner error message to the user, if possible
|
||||||
|
return nil, fmt.Errorf("account deployment failed: %v", err)
|
||||||
}
|
}
|
||||||
statedb.IntermediateRoot(true)
|
statedb.IntermediateRoot(true)
|
||||||
if resultDeployer.Failed() {
|
|
||||||
// TODO: bubble up the inner error message to the user, if possible
|
|
||||||
return nil, errors.New("account deployment failed - invalid transaction")
|
|
||||||
}
|
|
||||||
deploymentUsedGas = resultDeployer.UsedGas
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** Account Validation Frame ***/
|
/*** Account Validation Frame ***/
|
||||||
|
|
@ -338,19 +348,18 @@ func ApplyRip7560ExecutionPhase(config *params.ChainConfig, vpr *ValidationPhase
|
||||||
|
|
||||||
func prepareDeployerMessage(baseTx *types.Transaction, config *params.ChainConfig) *Message {
|
func prepareDeployerMessage(baseTx *types.Transaction, config *params.ChainConfig) *Message {
|
||||||
tx := baseTx.Rip7560TransactionData()
|
tx := baseTx.Rip7560TransactionData()
|
||||||
if len(tx.DeployerData) < 20 {
|
if tx.Deployer == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var deployerAddress common.Address = [20]byte(tx.DeployerData[0:20])
|
|
||||||
return &Message{
|
return &Message{
|
||||||
From: config.DeployerCallerAddress,
|
From: config.DeployerCallerAddress,
|
||||||
To: &deployerAddress,
|
To: tx.Deployer,
|
||||||
Value: big.NewInt(0),
|
Value: big.NewInt(0),
|
||||||
GasLimit: tx.ValidationGas,
|
GasLimit: tx.ValidationGas,
|
||||||
GasPrice: tx.GasFeeCap,
|
GasPrice: tx.GasFeeCap,
|
||||||
GasFeeCap: tx.GasFeeCap,
|
GasFeeCap: tx.GasFeeCap,
|
||||||
GasTipCap: tx.GasTipCap,
|
GasTipCap: tx.GasTipCap,
|
||||||
Data: tx.DeployerData[20:],
|
Data: tx.DeployerData,
|
||||||
AccessList: make(types.AccessList, 0),
|
AccessList: make(types.AccessList, 0),
|
||||||
SkipAccountChecks: true,
|
SkipAccountChecks: true,
|
||||||
IsRip7560Frame: true,
|
IsRip7560Frame: true,
|
||||||
|
|
|
||||||
88
tests/rip7560/deployer_test.go
Normal file
88
tests/rip7560/deployer_test.go
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
package rip7560
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DEPLOYER = common.HexToAddress("0xddddddddddeeeeeeeeeeddddddddddeeeeeeeeee")
|
||||||
|
|
||||||
|
func TestValidationFailure_deployerRevert(t *testing.T) {
|
||||||
|
handleTransaction(newTestContextBuilder(t).
|
||||||
|
withCode(DEFAULT_SENDER, []byte{}, DEFAULT_BALANCE).
|
||||||
|
withCode(DEPLOYER.Hex(), revertWithData([]byte{}), 0),
|
||||||
|
types.Rip7560AccountAbstractionTx{
|
||||||
|
Deployer: &DEPLOYER,
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
}, "account deployment failed: execution reverted")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidationFailure_deployerOOG(t *testing.T) {
|
||||||
|
handleTransaction(newTestContextBuilder(t).
|
||||||
|
withCode(DEFAULT_SENDER, []byte{}, DEFAULT_BALANCE).
|
||||||
|
withCode(DEPLOYER.Hex(), revertWithData([]byte{}), 0),
|
||||||
|
types.Rip7560AccountAbstractionTx{
|
||||||
|
Deployer: &DEPLOYER,
|
||||||
|
ValidationGas: 1,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
}, "account deployment failed: out of gas")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidationFailure_senderNotDeployed(t *testing.T) {
|
||||||
|
handleTransaction(newTestContextBuilder(t).
|
||||||
|
withCode(DEFAULT_SENDER, []byte{}, DEFAULT_BALANCE).
|
||||||
|
withCode(DEPLOYER.Hex(), returnWithData([]byte{}), 0),
|
||||||
|
types.Rip7560AccountAbstractionTx{
|
||||||
|
Deployer: &DEPLOYER,
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
}, "account deployment failed: sender not deployed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidationFailure_senderAlreadyDeployed(t *testing.T) {
|
||||||
|
accountCode := revertWithData([]byte{})
|
||||||
|
deployerCode := create2(accountCode)
|
||||||
|
sender := create2_addr(DEPLOYER, accountCode)
|
||||||
|
handleTransaction(newTestContextBuilder(t).
|
||||||
|
withCode(sender.Hex(), accountCode, DEFAULT_BALANCE).
|
||||||
|
withCode(DEPLOYER.Hex(), deployerCode, 0),
|
||||||
|
types.Rip7560AccountAbstractionTx{
|
||||||
|
Sender: &sender,
|
||||||
|
Deployer: &DEPLOYER,
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
}, "account deployment failed: sender already deployed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidationFailure_senderReverts(t *testing.T) {
|
||||||
|
accountCode := revertWithData([]byte{})
|
||||||
|
deployerCode := createCode(create2(accountCode), returnWithData([]byte{}))
|
||||||
|
sender := create2_addr(DEPLOYER, accountCode)
|
||||||
|
handleTransaction(newTestContextBuilder(t).
|
||||||
|
withCode(sender.Hex(), []byte{}, DEFAULT_BALANCE).
|
||||||
|
withCode(DEPLOYER.Hex(), deployerCode, 0),
|
||||||
|
types.Rip7560AccountAbstractionTx{
|
||||||
|
Sender: &sender,
|
||||||
|
Deployer: &DEPLOYER,
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
}, "execution reverted")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidation_deployer_ok(t *testing.T) {
|
||||||
|
accountCode := createAccountCode()
|
||||||
|
deployerCode := createCode(create2(accountCode), returnWithData([]byte{}))
|
||||||
|
sender := create2_addr(DEPLOYER, accountCode)
|
||||||
|
handleTransaction(newTestContextBuilder(t).
|
||||||
|
withCode(sender.Hex(), []byte{}, DEFAULT_BALANCE).
|
||||||
|
withCode(DEPLOYER.Hex(), deployerCode, 0),
|
||||||
|
types.Rip7560AccountAbstractionTx{
|
||||||
|
Sender: &sender,
|
||||||
|
Deployer: &DEPLOYER,
|
||||||
|
ValidationGas: 1000000000,
|
||||||
|
GasFeeCap: big.NewInt(1000000000),
|
||||||
|
}, "ok")
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"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"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"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"
|
||||||
|
|
@ -45,6 +46,31 @@ func newTestContextBuilder(t *testing.T) *testContextBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return a contract code that will deploy the given code
|
||||||
|
func create2_contract(deployedCode []byte) []byte {
|
||||||
|
|
||||||
|
return returnWithData(deployedCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the generated address when deploying the given code
|
||||||
|
func create2_addr(deployer common.Address, deployedCode []byte) common.Address {
|
||||||
|
|
||||||
|
contractCode := create2_contract(deployedCode)
|
||||||
|
data := createCode(0xff, deployer.Bytes(), common.Hash{}, crypto.Keccak256(contractCode))
|
||||||
|
return common.BytesToAddress(crypto.Keccak256(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate code to call create2
|
||||||
|
// note: parameter is the deployed code, not the full contract code
|
||||||
|
// always use zero value and zero salt.
|
||||||
|
func create2(deployedCode []byte) []byte {
|
||||||
|
contractCode := create2_contract(deployedCode)
|
||||||
|
return createCode(
|
||||||
|
copyToMemory(contractCode, 0),
|
||||||
|
push(0), push(len(contractCode)), push(0), push(0), vm.CREATE2,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (tb *testContextBuilder) build() *testContext {
|
func (tb *testContextBuilder) build() *testContext {
|
||||||
genesis := core.DeveloperGenesisBlock(10_000_000, &common.Address{})
|
genesis := core.DeveloperGenesisBlock(10_000_000, &common.Address{})
|
||||||
genesis.Timestamp = 100
|
genesis.Timestamp = 100
|
||||||
|
|
@ -69,7 +95,6 @@ func (tt *testContextBuilder) withAccount(addr string, balance int64) *testConte
|
||||||
tt.genesisAlloc[common.HexToAddress(addr)] = types.Account{Balance: big.NewInt(balance)}
|
tt.genesisAlloc[common.HexToAddress(addr)] = types.Account{Balance: big.NewInt(balance)}
|
||||||
return tt
|
return tt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tt *testContextBuilder) withCode(addr string, code []byte, balance int64) *testContextBuilder {
|
func (tt *testContextBuilder) withCode(addr string, code []byte, balance int64) *testContextBuilder {
|
||||||
if len(code) == 0 {
|
if len(code) == 0 {
|
||||||
tt.genesisAlloc[common.HexToAddress(addr)] = types.Account{
|
tt.genesisAlloc[common.HexToAddress(addr)] = types.Account{
|
||||||
|
|
@ -113,8 +138,9 @@ func copyToMemory(data []byte, offset uint) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
PUSHn := byte(int(vm.PUSH0) + len(data))
|
//push data up, as EVM is big-endian
|
||||||
ret = append(ret, createCode(PUSHn, data, vm.PUSH2, uint16(offset), vm.MSTORE)...)
|
v := common.RightPadBytes(data, 32)
|
||||||
|
ret = append(ret, createCode(vm.PUSH32, v, vm.PUSH2, uint16(offset), vm.MSTORE)...)
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
@ -160,6 +186,10 @@ func createCode(items ...interface{}) []byte {
|
||||||
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))
|
||||||
}
|
}
|
||||||
buffer.WriteByte(byte(v))
|
buffer.WriteByte(byte(v))
|
||||||
|
case common.Hash:
|
||||||
|
buffer.Write(v.Bytes())
|
||||||
|
case common.Address:
|
||||||
|
buffer.Write(v.Bytes())
|
||||||
default:
|
default:
|
||||||
// should be a compile-time error...
|
// should be a compile-time error...
|
||||||
panic(fmt.Errorf("unsupported type: %T", v))
|
panic(fmt.Errorf("unsupported type: %T", v))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue