package staking_test import ( "errors" "math/big" "strings" "testing" "cosmossdk.io/math" stakingprecompile "github.com/0glabs/0g-chain/precompiles/staking" "github.com/0glabs/0g-chain/precompiles/testutil" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/stretchr/testify/suite" ) type StakingTestSuite struct { testutil.PrecompileTestSuite abi abi.ABI addr common.Address staking *stakingprecompile.StakingPrecompile stakingKeeper *stakingkeeper.Keeper signerOne *testutil.TestSigner signerTwo *testutil.TestSigner } func (suite *StakingTestSuite) SetupTest() { suite.PrecompileTestSuite.SetupTest() suite.stakingKeeper = suite.App.GetStakingKeeper() suite.addr = common.HexToAddress(stakingprecompile.PrecompileAddress) precompiles := suite.EvmKeeper.GetPrecompiles() precompile, ok := precompiles[suite.addr] suite.Assert().EqualValues(ok, true) suite.staking = precompile.(*stakingprecompile.StakingPrecompile) suite.signerOne = suite.GenSigner() suite.signerTwo = suite.GenSigner() abi, err := abi.JSON(strings.NewReader(stakingprecompile.StakingABI)) suite.Assert().NoError(err) suite.abi = abi } func (suite *StakingTestSuite) AddDelegation(from string, to string, amount math.Int) { accAddr, err := sdk.AccAddressFromHexUnsafe(from) suite.Require().NoError(err) valAddr, err := sdk.ValAddressFromHex(to) suite.Require().NoError(err) validator, found := suite.StakingKeeper.GetValidator(suite.Ctx, valAddr) if !found { consPriv := ed25519.GenPrivKey() newValidator, err := stakingtypes.NewValidator(valAddr, consPriv.PubKey(), stakingtypes.Description{}) suite.Require().NoError(err) validator = newValidator } validator.Tokens = validator.Tokens.Add(amount) validator.DelegatorShares = validator.DelegatorShares.Add(amount.ToLegacyDec()) suite.StakingKeeper.SetValidator(suite.Ctx, validator) bonded := suite.stakingKeeper.GetDelegatorBonded(suite.Ctx, accAddr) suite.StakingKeeper.SetDelegation(suite.Ctx, stakingtypes.Delegation{ DelegatorAddress: accAddr.String(), ValidatorAddress: valAddr.String(), Shares: bonded.Add(amount).ToLegacyDec(), }) } func (suite *StakingTestSuite) setupValidator(signer *testutil.TestSigner) { method := stakingprecompile.StakingFunctionCreateValidator description := stakingprecompile.Description{ Moniker: "test node", Identity: "test node identity", Website: "http://test.node.com", SecurityContact: "test node security contract", Details: "test node details", } commission := stakingprecompile.CommissionRates{ Rate: math.LegacyOneDec().BigInt(), MaxRate: math.LegacyOneDec().BigInt(), MaxChangeRate: math.LegacyOneDec().BigInt(), } minSelfDelegation := big.NewInt(1) pubkey := "eh/aR8BGUBIYI/Ust0NVBxZafLDAm7344F9dKzZU+7g=" value := big.NewInt(100000000) input, err := suite.abi.Pack( method, description, commission, minSelfDelegation, pubkey, value, ) suite.Assert().NoError(err) _, err = suite.runTx(input, signer, 10000000) suite.Assert().NoError(err) _, err = suite.stakingKeeper.ApplyAndReturnValidatorSetUpdates(suite.Ctx) suite.Assert().NoError(err) } func (suite *StakingTestSuite) firstBondedValidator() (sdk.ValAddress, error) { validators := suite.stakingKeeper.GetValidators(suite.Ctx, 10) for _, v := range validators { if v.IsBonded() { return sdk.ValAddressFromBech32(v.OperatorAddress) } } return nil, errors.New("no bonded validator") } func (suite *StakingTestSuite) runTx(input []byte, signer *testutil.TestSigner, gas uint64) ([]byte, error) { contract := vm.NewPrecompile(vm.AccountRef(signer.Addr), vm.AccountRef(suite.addr), big.NewInt(0), gas) contract.Input = input msgEthereumTx := evmtypes.NewTx(suite.EvmKeeper.ChainID(), 0, &suite.addr, big.NewInt(0), gas, big.NewInt(0), big.NewInt(0), big.NewInt(0), input, nil) msgEthereumTx.From = signer.HexAddr err := msgEthereumTx.Sign(suite.EthSigner, signer.Signer) suite.Assert().NoError(err, "failed to sign Ethereum message") proposerAddress := suite.Ctx.BlockHeader().ProposerAddress cfg, err := suite.EvmKeeper.EVMConfig(suite.Ctx, proposerAddress, suite.EvmKeeper.ChainID()) suite.Assert().NoError(err, "failed to instantiate EVM config") msg, err := msgEthereumTx.AsMessage(suite.EthSigner, big.NewInt(0)) suite.Assert().NoError(err, "failed to instantiate Ethereum message") evm := suite.EvmKeeper.NewEVM(suite.Ctx, msg, cfg, nil, suite.Statedb) precompiles := suite.EvmKeeper.GetPrecompiles() evm.WithPrecompiles(precompiles, []common.Address{suite.addr}) return suite.staking.Run(evm, contract, false) } func TestKeeperSuite(t *testing.T) { suite.Run(t, new(StakingTestSuite)) }