diff --git a/command/sidechain/helper.go b/command/sidechain/helper.go index a3ca60da17..0f3ee8ceb6 100644 --- a/command/sidechain/helper.go +++ b/command/sidechain/helper.go @@ -6,6 +6,7 @@ import ( "math/big" "os" + "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/contracts" @@ -42,7 +43,7 @@ func GetAccountFromDir(dir string) (*wallet.Account, error) { } // GetValidatorInfo queries ChildValidatorSet smart contract and retrieves validator info for given address -func GetValidatorInfo(validatorAddr ethgo.Address, txRelayer txrelayer.TxRelayer) (map[string]interface{}, error) { +func GetValidatorInfo(validatorAddr ethgo.Address, txRelayer txrelayer.TxRelayer) (*polybft.ValidatorInfo, error) { getValidatorMethod := contractsapi.ChildValidatorSet.Abi.GetMethod("getValidator") encode, err := getValidatorMethod.Encode([]interface{}{validatorAddr}) @@ -76,7 +77,14 @@ func GetValidatorInfo(validatorAddr ethgo.Address, txRelayer txrelayer.TxRelayer return nil, fmt.Errorf("could not convert validator info result to a map") } - return decodedValidatorInfoMap, nil + return &polybft.ValidatorInfo{ + Address: validatorAddr.Address(), + Stake: decodedValidatorInfoMap["stake"].(*big.Int), //nolint:forcetypeassert + TotalStake: decodedValidatorInfoMap["totalStake"].(*big.Int), //nolint:forcetypeassert + Commission: decodedValidatorInfoMap["commission"].(*big.Int), //nolint:forcetypeassert + WithdrawableRewards: decodedValidatorInfoMap["withdrawableRewards"].(*big.Int), //nolint:forcetypeassert + Active: decodedValidatorInfoMap["active"].(bool), //nolint:forcetypeassert + }, nil } // GetDelegatorReward queries delegator reward for given validator and delegator addresses diff --git a/command/sidechain/validators/validator_info.go b/command/sidechain/validators/validator_info.go index e5bbdf34df..5d6c5486b5 100644 --- a/command/sidechain/validators/validator_info.go +++ b/command/sidechain/validators/validator_info.go @@ -2,7 +2,6 @@ package validators import ( "fmt" - "math/big" "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/command/helper" @@ -60,18 +59,18 @@ func runCommand(cmd *cobra.Command, _ []string) error { validatorAddr := validatorAccount.Ecdsa.Address() - responseMap, err := sidechainHelper.GetValidatorInfo(validatorAddr, txRelayer) + validatorInfo, err := sidechainHelper.GetValidatorInfo(validatorAddr, txRelayer) if err != nil { return fmt.Errorf("failed to get validator info for %s: %w", validatorAddr, err) } outputter.WriteCommandResult(&validatorsInfoResult{ - address: validatorAccount.Ecdsa.Address().String(), - stake: responseMap["stake"].(*big.Int).Uint64(), //nolint:forcetypeassert - totalStake: responseMap["totalStake"].(*big.Int).Uint64(), //nolint:forcetypeassert - commission: responseMap["commission"].(*big.Int).Uint64(), //nolint:forcetypeassert - withdrawableRewards: responseMap["withdrawableRewards"].(*big.Int).Uint64(), //nolint:forcetypeassert - active: responseMap["active"].(bool), //nolint:forcetypeassert + address: validatorInfo.Address.String(), + stake: validatorInfo.Stake.Uint64(), + totalStake: validatorInfo.TotalStake.Uint64(), + commission: validatorInfo.Commission.Uint64(), + withdrawableRewards: validatorInfo.WithdrawableRewards.Uint64(), + active: validatorInfo.Active, }) return nil diff --git a/consensus/polybft/system_state.go b/consensus/polybft/system_state.go index 90ceaa6f74..4a5f8efa42 100644 --- a/consensus/polybft/system_state.go +++ b/consensus/polybft/system_state.go @@ -14,6 +14,17 @@ import ( "github.com/umbracle/ethgo/contract" ) +// ValidatorInfo is data transfer object which holds validator information, +// provided by smart contract +type ValidatorInfo struct { + Address ethgo.Address + Stake *big.Int + TotalStake *big.Int + Commission *big.Int + WithdrawableRewards *big.Int + Active bool +} + // SystemState is an interface to interact with the consensus system contracts in the chain type SystemState interface { // GetValidatorSet retrieves current validator set from the smart contract diff --git a/e2e-polybft/bridge_test.go b/e2e-polybft/bridge_test.go index 2e577d002e..87be0fb236 100644 --- a/e2e-polybft/bridge_test.go +++ b/e2e-polybft/bridge_test.go @@ -626,43 +626,40 @@ func TestE2E_Bridge_ChangeVotingPower(t *testing.T) { // waiting two epochs, so that some rewards get accumulated require.NoError(t, cluster.WaitForBlock(10, 1*time.Minute)) - queryValidators := func(handler func(idx int, validatorInfo *validatorInfo)) { + queryValidators := func(handler func(idx int, validatorInfo *polybft.ValidatorInfo)) { for i, validatorAddr := range votingPowerChangeValidators { // query validator info - validatorInfoRaw, err := sidechain.GetValidatorInfo(validatorAddr, l2Relayer) + validatorInfo, err := sidechain.GetValidatorInfo(validatorAddr, l2Relayer) require.NoError(t, err) - rewards := validatorInfoRaw["withdrawableRewards"].(*big.Int) //nolint:forcetypeassert - totalStake := validatorInfoRaw["totalStake"].(*big.Int) //nolint:forcetypeassert - - handler(i, &validatorInfo{address: validatorAddr, rewards: rewards, totalStake: totalStake}) + handler(i, validatorInfo) } } - originalValidatorStorage := make(map[ethgo.Address]*validatorInfo, votingPowerChanges) + originalValidatorStorage := make(map[ethgo.Address]*polybft.ValidatorInfo, votingPowerChanges) - queryValidators(func(idx int, validator *validatorInfo) { + queryValidators(func(idx int, validator *polybft.ValidatorInfo) { t.Logf("[Validator#%d] Voting power (original)=%d, rewards=%d\n", - idx+1, validator.totalStake, validator.rewards) + idx+1, validator.TotalStake, validator.WithdrawableRewards) - originalValidatorStorage[validator.address] = validator + originalValidatorStorage[validator.Address] = validator // stake rewards - require.NoError(t, cluster.Servers[idx].Stake(validator.rewards.Uint64())) + require.NoError(t, cluster.Servers[idx].Stake(validator.WithdrawableRewards.Uint64())) }) // wait a two more epochs, so that stake is registered and two more checkpoints are sent. // Blocks are still produced, although voting power is slightly changed. require.NoError(t, cluster.WaitForBlock(finalBlockNumber, 1*time.Minute)) - queryValidators(func(idx int, validator *validatorInfo) { - t.Logf("[Validator#%d] Voting power (after stake)=%d\n", idx+1, validator.totalStake) + queryValidators(func(idx int, validator *polybft.ValidatorInfo) { + t.Logf("[Validator#%d] Voting power (after stake)=%d\n", idx+1, validator.TotalStake) - previousValidatorInfo := originalValidatorStorage[validator.address] - stakedAmount := new(big.Int).Add(previousValidatorInfo.rewards, previousValidatorInfo.totalStake) + previousValidatorInfo := originalValidatorStorage[validator.Address] + stakedAmount := new(big.Int).Add(previousValidatorInfo.WithdrawableRewards, previousValidatorInfo.TotalStake) // assert that total stake has increased by staked amount - require.Equal(t, stakedAmount, validator.totalStake) + require.Equal(t, stakedAmount, validator.TotalStake) }) l1Sender := ethgo.Address(manifest.RootchainConfig.AdminAddress) diff --git a/e2e-polybft/consensus_test.go b/e2e-polybft/consensus_test.go index c361e5aa44..d583a09f90 100644 --- a/e2e-polybft/consensus_test.go +++ b/e2e-polybft/consensus_test.go @@ -181,9 +181,8 @@ func TestE2E_Consensus_RegisterValidator(t *testing.T) { require.NoError(t, err) // assert registered validator's stake - stake := newValidatorInfo["totalStake"].(*big.Int) //nolint:forcetypeassert - t.Logf("New validator stake=%s\n", stake.String()) - require.Equal(t, newValidatorStake, stake) + t.Logf("New validator stake=%d\n", newValidatorInfo.TotalStake) + require.Equal(t, newValidatorStake, newValidatorInfo.TotalStake) // wait 3 more epochs, so that rewards get accumulated to the registered validator account cluster.WaitForBlock(20, 2*time.Minute) @@ -193,9 +192,8 @@ func TestE2E_Consensus_RegisterValidator(t *testing.T) { require.NoError(t, err) // assert registered validator's rewards - rewards := newValidatorInfo["withdrawableRewards"].(*big.Int) //nolint:forcetypeassert - t.Logf("New validator rewards=%s\n", rewards) - require.True(t, rewards.Cmp(big.NewInt(0)) > 0) + t.Logf("New validator rewards=%d\n", newValidatorInfo.WithdrawableRewards) + require.True(t, newValidatorInfo.WithdrawableRewards.Cmp(big.NewInt(0)) > 0) } func TestE2E_Consensus_Delegation_Undelegation(t *testing.T) { @@ -336,11 +334,11 @@ func TestE2E_Consensus_Validator_Unstake(t *testing.T) { // wait for one epoch to accumulate validator rewards require.NoError(t, cluster.WaitForBlock(5, 20*time.Second)) - validatorInfoRaw, err := sidechain.GetValidatorInfo(validatorAddr, txRelayer) + validatorInfo, err := sidechain.GetValidatorInfo(validatorAddr, txRelayer) require.NoError(t, err) - initialStake := validatorInfoRaw["totalStake"].(*big.Int) //nolint:forcetypeassert - t.Logf("Stake (before unstake)=%s\n", initialStake.String()) + initialStake := validatorInfo.TotalStake + t.Logf("Stake (before unstake)=%d\n", initialStake) // unstake entire balance (which should remove validator from the validator set in next epoch) require.NoError(t, srv.Unstake(initialStake.Uint64())) @@ -354,12 +352,12 @@ func TestE2E_Consensus_Validator_Unstake(t *testing.T) { // assert that validator isn't present in new validator set require.Equal(t, 4, validatorSet.Len()) - validatorInfoRaw, err = sidechain.GetValidatorInfo(validatorAddr, txRelayer) + validatorInfo, err = sidechain.GetValidatorInfo(validatorAddr, txRelayer) require.NoError(t, err) - reward := validatorInfoRaw["withdrawableRewards"].(*big.Int) //nolint:forcetypeassert + reward := validatorInfo.WithdrawableRewards t.Logf("Rewards=%d\n", reward) - t.Logf("Stake (after unstake)=%d\n", validatorInfoRaw["totalStake"].(*big.Int)) //nolint:forcetypeassert + t.Logf("Stake (after unstake)=%d\n", validatorInfo.TotalStake) require.Greater(t, reward.Uint64(), uint64(0)) oldValidatorBalance, err := srv.JSONRPC().Eth().GetBalance(validatorAcc.Ecdsa.Address(), ethgo.Latest) @@ -385,7 +383,7 @@ func TestE2E_Consensus_Validator_Unstake(t *testing.T) { // query rootchain validator set and make sure that validator which unstaked all the funds isn't present in validator set anymore // (execute it multiple times if needed, because it is unknown in advance how much time it is going to take until checkpoint is submitted) - rootchainValidators := []*validatorInfo{} + rootchainValidators := []*polybft.ValidatorInfo{} err = cluster.Bridge.WaitUntil(time.Second, 10*time.Second, func() (bool, error) { rootchainValidators, err = getRootchainValidators(l1Relayer, checkpointManagerAddr, rootchainSender) if err != nil { @@ -398,8 +396,8 @@ func TestE2E_Consensus_Validator_Unstake(t *testing.T) { require.Equal(t, 4, len(rootchainValidators)) for _, validator := range rootchainValidators { - if validator.address == validatorAddr { - t.Fatalf("not expected to find validator %v in the current validator set", validator.address) + if validator.Address == validatorAddr { + t.Fatalf("not expected to find validator %v in the current validator set", validator.Address) } } } diff --git a/e2e-polybft/helpers_test.go b/e2e-polybft/helpers_test.go index 75800dfd03..04f9e495f8 100644 --- a/e2e-polybft/helpers_test.go +++ b/e2e-polybft/helpers_test.go @@ -4,6 +4,7 @@ import ( "errors" "math/big" + "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi" "github.com/0xPolygon/polygon-edge/helper/hex" "github.com/0xPolygon/polygon-edge/txrelayer" @@ -29,14 +30,8 @@ func (s *e2eStateProvider) Txn(ethgo.Address, ethgo.Key, []byte) (contract.Txn, return nil, errors.New("send txn is not supported") } -type validatorInfo struct { - address ethgo.Address - rewards *big.Int - totalStake *big.Int -} - // getRootchainValidators queries rootchain validator set -func getRootchainValidators(relayer txrelayer.TxRelayer, checkpointManagerAddr, sender ethgo.Address) ([]*validatorInfo, error) { +func getRootchainValidators(relayer txrelayer.TxRelayer, checkpointManagerAddr, sender ethgo.Address) ([]*polybft.ValidatorInfo, error) { validatorsCountRaw, err := ABICall(relayer, contractsapi.CheckpointManager, checkpointManagerAddr, sender, "currentValidatorSetLength") if err != nil { @@ -49,7 +44,7 @@ func getRootchainValidators(relayer txrelayer.TxRelayer, checkpointManagerAddr, } currentValidatorSetMethod := contractsapi.CheckpointManager.Abi.GetMethod("currentValidatorSet") - validators := make([]*validatorInfo, validatorsCount) + validators := make([]*polybft.ValidatorInfo, validatorsCount) for i := 0; i < int(validatorsCount); i++ { validatorRaw, err := ABICall(relayer, contractsapi.CheckpointManager, @@ -74,9 +69,9 @@ func getRootchainValidators(relayer txrelayer.TxRelayer, checkpointManagerAddr, } //nolint:forcetypeassert - validators[i] = &validatorInfo{ - address: results["_address"].(ethgo.Address), - totalStake: results["votingPower"].(*big.Int), + validators[i] = &polybft.ValidatorInfo{ + Address: results["_address"].(ethgo.Address), + TotalStake: results["votingPower"].(*big.Int), } }