Skip to content

Commit

Permalink
fix issuse about contract Stack too deep
Browse files Browse the repository at this point in the history
  • Loading branch information
trestinlsd committed Feb 6, 2025
1 parent 0fdaebc commit 4aaaeeb
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 260 deletions.
50 changes: 20 additions & 30 deletions precompiles/avs/IAVSManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,24 @@ IAVSManager constant AVSMANAGER_CONTRACT = IAVSManager(AVSMANAGER_PRECOMPILE_ADD
/// @title AVS-Manager Precompile Contract
/// @dev The interface through which solidity contracts will interact with AVS-Manager
/// @custom:address 0x0000000000000000000000000000000000000901

struct AVSParams {
address sender;
string avsName;
uint64 minStakeAmount;
address taskAddr;
address slashAddr;
address rewardAddr;
address[] avsOwnerAddress;
address[] whitelistAddress;
string[] assetIds;
uint64 avsUnbondingPeriod;
uint64 minSelfDelegation;
string epochIdentifier;
uint64 miniOptInOperators;
uint64 minTotalStakeAmount;
uint64 avsRewardProportion;
uint64 avsSlashProportion;
}
interface IAVSManager {
// note:string and bytes will be hashed. address / uintX will not be hashed when using indexed.
event AVSRegistered(address indexed avsAddr, string sender, string avsName);
Expand Down Expand Up @@ -42,36 +59,9 @@ interface IAVSManager {
);

/// @dev Register AVS contract to EXO.
/// @param sender The external address for calling this method.
/// @param avsName The name of AVS.
/// @param minStakeAmount The minimum amount of funds staked by each operator.
/// @param taskAddr The task address of AVS.
/// @param slashAddr The slash address of AVS.
/// @param rewardAddr The reward address of AVS.
/// @param avsOwnerAddress The owners who have permission for AVS.
/// @param whitelistAddress The whitelist address of the operator.
/// @param assetIds The basic asset information of AVS.
/// @param avsUnbondingPeriod The unbonding duration of AVS.
/// @param minSelfDelegation The minimum delegation amount for an operator.
/// @param epochIdentifier The AVS epoch identifier.
/// @param params 1.miniOptInOperators The minimum number of opt-in operators.
///2.minTotalStakeAmount The minimum total amount of stake by all operators.
///3.avsReward The proportion of reward for AVS.
///4.avsSlash The proportion of slash for AVS.
/// @param params The params of AVS.
function registerAVS(
address sender,
string memory avsName,
uint64 minStakeAmount,
address taskAddr,
address slashAddr,
address rewardAddr,
address[] memory avsOwnerAddress,
address[] memory whitelistAddress,
string[] memory assetIds,
uint64 avsUnbondingPeriod,
uint64 minSelfDelegation,
string memory epochIdentifier,
uint64[] memory params
AVSParams calldata params
) external returns (bool success);

/// @dev Update AVS info to EXO.
Expand Down
146 changes: 84 additions & 62 deletions precompiles/avs/abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -617,69 +617,91 @@
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "string",
"name": "avsName",
"type": "string"
},
{
"internalType": "uint64",
"name": "minStakeAmount",
"type": "uint64"
},
{
"internalType": "address",
"name": "taskAddr",
"type": "address"
},
{
"internalType": "address",
"name": "slashAddr",
"type": "address"
},
{
"internalType": "address",
"name": "rewardAddr",
"type": "address"
},
{
"internalType": "address[]",
"name": "avsOwnerAddress",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "whitelistAddress",
"type": "address[]"
},
{
"internalType": "string[]",
"name": "assetIds",
"type": "string[]"
},
{
"internalType": "uint64",
"name": "avsUnbondingPeriod",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "minSelfDelegation",
"type": "uint64"
},
{
"internalType": "string",
"name": "epochIdentifier",
"type": "string"
},
{
"internalType": "uint64[]",
"components": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "string",
"name": "avsName",
"type": "string"
},
{
"internalType": "uint64",
"name": "minStakeAmount",
"type": "uint64"
},
{
"internalType": "address",
"name": "taskAddr",
"type": "address"
},
{
"internalType": "address",
"name": "slashAddr",
"type": "address"
},
{
"internalType": "address",
"name": "rewardAddr",
"type": "address"
},
{
"internalType": "address[]",
"name": "avsOwnerAddress",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "whitelistAddress",
"type": "address[]"
},
{
"internalType": "string[]",
"name": "assetIds",
"type": "string[]"
},
{
"internalType": "uint64",
"name": "avsUnbondingPeriod",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "minSelfDelegation",
"type": "uint64"
},
{
"internalType": "string",
"name": "epochIdentifier",
"type": "string"
},
{
"internalType": "uint64",
"name": "miniOptInOperators",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "minTotalStakeAmount",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "avsRewardProportion",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "avsSlashProportion",
"type": "uint64"
}
],
"internalType": "struct AVSParams",
"name": "params",
"type": "uint64[]"
"type": "tuple"
}
],
"name": "registerAVS",
Expand Down
151 changes: 53 additions & 98 deletions precompiles/avs/avs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,126 +85,81 @@ func (suite *AVSManagerPrecompileSuite) TestIsTransaction() {
})
}
}

func (suite *AVSManagerPrecompileSuite) TestRegisterAVS() {
func (s *AVSManagerPrecompileSuite) TestRegisterAVS() {
// Default variables used during tests.
gas := uint64(2_000)
senderAddress := utiltx.GenerateAddress()
avsName, slashAddress, rewardAddress := "avsTest", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB"
avsOwnerAddress := []common.Address{
suite.Address,
s.Address,
utiltx.GenerateAddress(),
utiltx.GenerateAddress(),
}
exoWhiteListAddress := []common.Address{
utiltx.GenerateAddress(),
utiltx.GenerateAddress(),
}
assetID := suite.AssetIDs
assetID := s.AssetIDs
minStakeAmount, taskAddr := uint64(3), "0xDF907c29719154eb9872f021d21CAE6E5025d7aB"
avsUnbondingPeriod, minSelfDelegation := uint64(3), uint64(3)
epochIdentifier := epochstypes.DayEpochID
params := []uint64{2, 3, 4, 4}
commonMalleate := func() (common.Address, []byte) {
input, err := suite.precompile.Pack(
avs.MethodRegisterAVS,
suite.Address,
avsName,
minStakeAmount,
common.HexToAddress(taskAddr),
common.HexToAddress(slashAddress),
common.HexToAddress(rewardAddress),
avsOwnerAddress,
exoWhiteListAddress,
assetID,
avsUnbondingPeriod,
minSelfDelegation,
epochIdentifier,
params,
)
suite.Require().NoError(err, "failed to pack input")
return common.HexToAddress("0x3e108c058e8066DA635321Dc3018294cA82ddEdf"), input
}

successRet, err := suite.precompile.Methods[avs.MethodRegisterAVS].Outputs.Pack(true)
suite.Require().NoError(err)

testcases := []struct {
method := s.precompile.Methods[avs.MethodRegisterAVS]
testCases := []struct {
name string
malleate func() (common.Address, []byte)
readOnly bool
expPass bool
sender common.Address
origin common.Address
malleate func() []interface{}
ibcSetup bool
expError bool
errContains string
returnBytes []byte
}{
{
name: "pass for avs-registered",
malleate: func() (common.Address, []byte) {
return commonMalleate()
name: "pass for avs-registered",
sender: senderAddress,
origin: senderAddress,
malleate: func() []interface{} {
return []interface{}{
avs.AVSParams{
Sender: senderAddress,
AvsName: avsName,
MinStakeAmount: minStakeAmount,
TaskAddr: common.HexToAddress(taskAddr),
SlashAddr: common.HexToAddress(slashAddress),
RewardAddr: common.HexToAddress(rewardAddress),
AvsOwnerAddresses: avsOwnerAddress,
WhitelistAddresses: exoWhiteListAddress,
AssetIds: assetID,
AvsUnbondingPeriod: avsUnbondingPeriod,
MinSelfDelegation: minSelfDelegation,
EpochIdentifier: epochIdentifier,
MiniOptInOperators: 1,
MinTotalStakeAmount: 1,
AvsRewardProportion: 5,
AvsSlashProportion: 5,
},
}
},
readOnly: false,
expPass: true,
returnBytes: successRet,
expError: false,
ibcSetup: true,
},
}

for _, tc := range testcases {
tc := tc
suite.Run(tc.name, func() {
baseFee := suite.App.FeeMarketKeeper.GetBaseFee(suite.Ctx)

// malleate testcase
caller, input := tc.malleate()

contract := vm.NewPrecompile(vm.AccountRef(caller), suite.precompile, big.NewInt(0), uint64(1e6))
contract.Input = input

contractAddr := contract.Address()
// Build and sign Ethereum transaction
txArgs := evmtypes.EvmTxArgs{
ChainID: suite.App.EvmKeeper.ChainID(),
Nonce: 0,
To: &contractAddr,
Amount: nil,
GasLimit: 100000,
GasPrice: app.MainnetMinGasPrices.BigInt(),
GasFeeCap: baseFee,
GasTipCap: big.NewInt(1),
Accesses: &ethtypes.AccessList{},
}
msgEthereumTx := evmtypes.NewTx(&txArgs)

msgEthereumTx.From = suite.Address.String()
err := msgEthereumTx.Sign(suite.EthSigner, suite.Signer)
suite.Require().NoError(err, "failed to sign Ethereum message")

// Instantiate config
proposerAddress := suite.Ctx.BlockHeader().ProposerAddress
cfg, err := suite.App.EvmKeeper.EVMConfig(suite.Ctx, proposerAddress, suite.App.EvmKeeper.ChainID())
suite.Require().NoError(err, "failed to instantiate EVM config")

msg, err := msgEthereumTx.AsMessage(suite.EthSigner, baseFee)
suite.Require().NoError(err, "failed to instantiate Ethereum message")

// Instantiate EVM
evm := suite.App.EvmKeeper.NewEVM(
suite.Ctx, msg, cfg, nil, suite.StateDB,
for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest()
contract := vm.NewContract(vm.AccountRef(tc.sender), s.precompile, big.NewInt(0), gas)
_, err := s.precompile.RegisterAVS(
s.Ctx,
tc.origin,
contract,
s.StateDB,
&method,
tc.malleate(),
)

params := suite.App.EvmKeeper.GetParams(suite.Ctx)
activePrecompiles := params.GetActivePrecompilesAddrs()
precompileMap := suite.App.EvmKeeper.Precompiles(activePrecompiles...)
err = vm.ValidatePrecompiles(precompileMap, activePrecompiles)
suite.Require().NoError(err, "invalid precompiles", activePrecompiles)
evm.WithPrecompiles(precompileMap, activePrecompiles)

// Run precompiled contract
bz, err := suite.precompile.Run(evm, contract, tc.readOnly)
// Check results
if tc.expPass {
suite.Require().NoError(err, "expected no error when running the precompile")
suite.Require().Equal(tc.returnBytes, bz, "the return doesn't match the expected result")
if tc.expError {
s.Require().ErrorContains(err, tc.errContains)
} else {
suite.Require().Error(err, "expected error to be returned when running the precompile")
suite.Require().Nil(bz, "expected returned bytes to be nil")
suite.Require().ErrorContains(err, tc.errContains)
s.Require().NoError(err)
}
})
}
Expand Down
Loading

0 comments on commit 4aaaeeb

Please sign in to comment.