From fdd0c10101270e045c22159a1299454d2cff5f07 Mon Sep 17 00:00:00 2001 From: David Terpay Date: Wed, 23 Aug 2023 17:33:36 -0400 Subject: [PATCH 1/5] utilizing voting power from VEs --- baseapp/abci_test.go | 25 ++++++-- baseapp/abci_utils.go | 30 +++++----- baseapp/abci_utils_test.go | 57 +++++++++---------- baseapp/testutil/mock/mocks.go | 31 +++------- .../staking/keeper/vote_extensions_test.go | 2 +- 5 files changed, 73 insertions(+), 72 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index e24af9706503..ee322db5174a 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -1791,8 +1791,7 @@ func TestABCI_PrepareProposal_VoteExtensions(t *testing.T) { } consAddr := sdk.ConsAddress(addr.String()) - valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), consAddr.Bytes()).Return(math.NewInt(667), tmPk, nil) - valStore.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(1000), nil).AnyTimes() + valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), consAddr.Bytes()).Return(math.NewInt(0), tmPk, nil) // set up baseapp prepareOpt := func(bapp *baseapp.BaseApp) { @@ -1866,8 +1865,7 @@ func TestABCI_PrepareProposal_VoteExtensions(t *testing.T) { { Validator: abci.Validator{ Address: consAddr.Bytes(), - // this is being ignored by our validation function - Power: sdk.TokensToConsensusPower(math.NewInt(1000000), sdk.DefaultPowerReduction), + Power: 666, }, VoteExtension: ext, ExtensionSignature: extSig, @@ -1881,7 +1879,24 @@ func TestABCI_PrepareProposal_VoteExtensions(t *testing.T) { require.Equal(t, 1, len(resPrepareProposal.Txs)) // now vote extensions but our sole voter doesn't reach majority - valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), consAddr.Bytes()).Return(math.NewInt(666), tmPk, nil) + reqPrepareProposal = abci.RequestPrepareProposal{ + MaxTxBytes: 1000, + Height: 3, // this value can't be 0 + LocalLastCommit: abci.ExtendedCommitInfo{ + Round: 0, + Votes: []abci.ExtendedVoteInfo{ + { + Validator: abci.Validator{ + Address: consAddr.Bytes(), + Power: 666, + }, + VoteExtension: ext, + ExtensionSignature: extSig, + BlockIdFlag: cmtproto.BlockIDFlagNil, // This will ignore the vote extension + }, + }, + }, + } resPrepareProposal, err = suite.baseApp.PrepareProposal(&reqPrepareProposal) require.NoError(t, err) require.Equal(t, 0, len(resPrepareProposal.Txs)) diff --git a/baseapp/abci_utils.go b/baseapp/abci_utils.go index 9b5fe2e63328..2c4f9a349074 100644 --- a/baseapp/abci_utils.go +++ b/baseapp/abci_utils.go @@ -29,7 +29,6 @@ type ( // extension signatures. Typically, this will be implemented by the x/staking // module, which has knowledge of the CometBFT public key. ValidatorStore interface { - TotalBondedTokens(ctx context.Context) (math.Int, error) BondedTokensAndPubKeyByConsAddr(context.Context, sdk.ConsAddress) (math.Int, cmtprotocrypto.PublicKey, error) } @@ -62,8 +61,16 @@ func ValidateVoteExtensions( return buf.Bytes(), nil } - sumVP := math.NewInt(0) + var ( + // Total voting power of all vote extensions. + totalVP int64 + // Total voting power of all validators that submitted valid vote extensions. + sumVP int64 + ) + for _, vote := range extCommit.Votes { + totalVP += vote.Validator.Power + // Only check + include power if the vote is a commit vote. There must be super-majority, otherwise the // previous block (the block vote is for) could not have been committed. if vote.BlockIdFlag != cmtproto.BlockIDFlagCommit { @@ -86,7 +93,7 @@ func ValidateVoteExtensions( } valConsAddr := sdk.ConsAddress(vote.Validator.Address) - bondedTokens, cmtPubKeyProto, err := valStore.BondedTokensAndPubKeyByConsAddr(ctx, valConsAddr) + _, cmtPubKeyProto, err := valStore.BondedTokensAndPubKeyByConsAddr(ctx, valConsAddr) if err != nil { return fmt.Errorf("failed to get validator %X info (bonded tokens and public key): %w", valConsAddr, err) } @@ -112,19 +119,14 @@ func ValidateVoteExtensions( return fmt.Errorf("failed to verify validator %X vote extension signature", valConsAddr) } - sumVP = sumVP.Add(bondedTokens) + sumVP += vote.Validator.Power } - // Ensure we have at least 2/3 voting power that submitted valid vote - // extensions. - totalVP, err := valStore.TotalBondedTokens(ctx) - if err != nil { - return fmt.Errorf("failed to get total bonded tokens: %w", err) - } - - percentSubmitted := math.LegacyNewDecFromInt(sumVP).Quo(math.LegacyNewDecFromInt(totalVP)) - if percentSubmitted.LT(VoteExtensionThreshold) { - return fmt.Errorf("insufficient cumulative voting power received to verify vote extensions; got: %s, expected: >=%s", percentSubmitted, VoteExtensionThreshold) + if totalVP > 0 { + percentSubmitted := math.LegacyNewDecFromInt(math.NewInt(sumVP)).Quo(math.LegacyNewDecFromInt(math.NewInt(totalVP))) + if percentSubmitted.LT(VoteExtensionThreshold) { + return fmt.Errorf("insufficient cumulative voting power received to verify vote extensions; got: %s, expected: >=%s", percentSubmitted, VoteExtensionThreshold) + } } return nil diff --git a/baseapp/abci_utils_test.go b/baseapp/abci_utils_test.go index 58d8770ad05a..c2f3dda33d90 100644 --- a/baseapp/abci_utils_test.go +++ b/baseapp/abci_utils_test.go @@ -4,6 +4,7 @@ import ( "bytes" "testing" + "cosmossdk.io/math" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/secp256k1" cmtprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" @@ -13,8 +14,6 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" - "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" @@ -46,10 +45,10 @@ func newTestValidator() testValidator { } } -func (t testValidator) toValidator() abci.Validator { +func (t testValidator) toValidator(power int64) abci.Validator { return abci.Validator{ Address: t.consAddr.Bytes(), - Power: 0, // ignored for now + Power: power, } } @@ -78,10 +77,9 @@ func NewABCIUtilsTestSuite(t *testing.T) *ABCIUtilsTestSuite { s.valStore = valStore // set up mock - s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[0].consAddr.Bytes()).Return(math.NewInt(333), s.vals[0].tmPk, nil).AnyTimes() - s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[1].consAddr.Bytes()).Return(math.NewInt(333), s.vals[1].tmPk, nil).AnyTimes() - s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[2].consAddr.Bytes()).Return(math.NewInt(334), s.vals[2].tmPk, nil).AnyTimes() - s.valStore.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(1000), nil).AnyTimes() + s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[0].consAddr.Bytes()).Return(math.NewInt(0), s.vals[0].tmPk, nil).AnyTimes() + s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[1].consAddr.Bytes()).Return(math.NewInt(0), s.vals[1].tmPk, nil).AnyTimes() + s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[2].consAddr.Bytes()).Return(math.NewInt(0), s.vals[2].tmPk, nil).AnyTimes() // create context s.ctx = sdk.Context{}.WithConsensusParams(cmtproto.ConsensusParams{ @@ -92,7 +90,7 @@ func NewABCIUtilsTestSuite(t *testing.T) *ABCIUtilsTestSuite { return s } -func TestACITUtilsTestSuite(t *testing.T) { +func TestABCIUtilsTestSuite(t *testing.T) { suite.Run(t, NewABCIUtilsTestSuite(t)) } @@ -122,19 +120,19 @@ func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsHappyPath() { Round: 0, Votes: []abci.ExtendedVoteInfo{ { - Validator: s.vals[0].toValidator(), + Validator: s.vals[0].toValidator(333), VoteExtension: ext, ExtensionSignature: extSig0, BlockIdFlag: cmtproto.BlockIDFlagCommit, }, { - Validator: s.vals[1].toValidator(), + Validator: s.vals[1].toValidator(333), VoteExtension: ext, ExtensionSignature: extSig1, BlockIdFlag: cmtproto.BlockIDFlagCommit, }, { - Validator: s.vals[2].toValidator(), + Validator: s.vals[2].toValidator(334), VoteExtension: ext, ExtensionSignature: extSig2, BlockIdFlag: cmtproto.BlockIDFlagCommit, @@ -168,18 +166,18 @@ func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsSingleVoteAbsent() { Round: 0, Votes: []abci.ExtendedVoteInfo{ { - Validator: s.vals[0].toValidator(), + Validator: s.vals[0].toValidator(333), VoteExtension: ext, ExtensionSignature: extSig0, BlockIdFlag: cmtproto.BlockIDFlagCommit, }, - // validator of power >1/3 is missing, so commit-info shld still be valid + // validator of power <1/3 is missing, so commit-info shld still be valid { - Validator: s.vals[1].toValidator(), + Validator: s.vals[1].toValidator(333), BlockIdFlag: cmtproto.BlockIDFlagAbsent, }, { - Validator: s.vals[2].toValidator(), + Validator: s.vals[2].toValidator(334), VoteExtension: ext, ExtensionSignature: extSig2, BlockIdFlag: cmtproto.BlockIDFlagCommit, @@ -213,18 +211,18 @@ func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsSingleVoteNil() { Round: 0, Votes: []abci.ExtendedVoteInfo{ { - Validator: s.vals[0].toValidator(), + Validator: s.vals[0].toValidator(333), VoteExtension: ext, ExtensionSignature: extSig0, BlockIdFlag: cmtproto.BlockIDFlagCommit, }, - // validator of power <1/3 is missing, so commit-info shld still be valid + // validator of power <1/3 is missing, so commit-info should still be valid { - Validator: s.vals[1].toValidator(), + Validator: s.vals[1].toValidator(333), BlockIdFlag: cmtproto.BlockIDFlagNil, }, { - Validator: s.vals[2].toValidator(), + Validator: s.vals[2].toValidator(334), VoteExtension: ext, ExtensionSignature: extSig2, BlockIdFlag: cmtproto.BlockIDFlagCommit, @@ -248,26 +246,27 @@ func (s *ABCIUtilsTestSuite) TestValidateVoteExtensionsTwoVotesNilAbsent() { bz, err := marshalDelimitedFn(&cve) s.Require().NoError(err) - extSig2, err := s.vals[2].privKey.Sign(bz) + extSig0, err := s.vals[0].privKey.Sign(bz) s.Require().NoError(err) llc := abci.ExtendedCommitInfo{ Round: 0, Votes: []abci.ExtendedVoteInfo{ - // validator of power >2/3 is missing, so commit-info shld still be valid + // validator of power >2/3 is missing, so commit-info should not be valid { - Validator: s.vals[0].toValidator(), - BlockIdFlag: cmtproto.BlockIDFlagCommit, + Validator: s.vals[0].toValidator(333), + BlockIdFlag: cmtproto.BlockIDFlagCommit, + VoteExtension: ext, + ExtensionSignature: extSig0, }, { - Validator: s.vals[1].toValidator(), + Validator: s.vals[1].toValidator(333), BlockIdFlag: cmtproto.BlockIDFlagNil, }, { - Validator: s.vals[2].toValidator(), - VoteExtension: ext, - ExtensionSignature: extSig2, - BlockIdFlag: cmtproto.BlockIDFlagAbsent, + Validator: s.vals[2].toValidator(334), + VoteExtension: ext, + BlockIdFlag: cmtproto.BlockIDFlagAbsent, }, }, } diff --git a/baseapp/testutil/mock/mocks.go b/baseapp/testutil/mock/mocks.go index 482e8f59dd17..5e89844a6ef4 100644 --- a/baseapp/testutil/mock/mocks.go +++ b/baseapp/testutil/mock/mocks.go @@ -53,21 +53,6 @@ func (mr *MockValidatorStoreMockRecorder) BondedTokensAndPubKeyByConsAddr(arg0, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondedTokensAndPubKeyByConsAddr", reflect.TypeOf((*MockValidatorStore)(nil).BondedTokensAndPubKeyByConsAddr), arg0, arg1) } -// TotalBondedTokens mocks base method. -func (m *MockValidatorStore) TotalBondedTokens(ctx context.Context) (math.Int, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TotalBondedTokens", ctx) - ret0, _ := ret[0].(math.Int) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TotalBondedTokens indicates an expected call of TotalBondedTokens. -func (mr *MockValidatorStoreMockRecorder) TotalBondedTokens(ctx interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalBondedTokens", reflect.TypeOf((*MockValidatorStore)(nil).TotalBondedTokens), ctx) -} - // MockGasTx is a mock of GasTx interface. type MockGasTx struct { ctrl *gomock.Controller @@ -129,31 +114,31 @@ func (m *MockProposalTxVerifier) EXPECT() *MockProposalTxVerifierMockRecorder { } // PrepareProposalVerifyTx mocks base method. -func (m *MockProposalTxVerifier) PrepareProposalVerifyTx(tx types.Tx) ([]byte, error) { +func (m *MockProposalTxVerifier) PrepareProposalVerifyTx(arg0 types.Tx) ([]byte, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PrepareProposalVerifyTx", tx) + ret := m.ctrl.Call(m, "PrepareProposalVerifyTx", arg0) ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(error) return ret0, ret1 } // PrepareProposalVerifyTx indicates an expected call of PrepareProposalVerifyTx. -func (mr *MockProposalTxVerifierMockRecorder) PrepareProposalVerifyTx(tx interface{}) *gomock.Call { +func (mr *MockProposalTxVerifierMockRecorder) PrepareProposalVerifyTx(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareProposalVerifyTx", reflect.TypeOf((*MockProposalTxVerifier)(nil).PrepareProposalVerifyTx), tx) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareProposalVerifyTx", reflect.TypeOf((*MockProposalTxVerifier)(nil).PrepareProposalVerifyTx), arg0) } // ProcessProposalVerifyTx mocks base method. -func (m *MockProposalTxVerifier) ProcessProposalVerifyTx(txBz []byte) (types.Tx, error) { +func (m *MockProposalTxVerifier) ProcessProposalVerifyTx(arg0 []byte) (types.Tx, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ProcessProposalVerifyTx", txBz) + ret := m.ctrl.Call(m, "ProcessProposalVerifyTx", arg0) ret0, _ := ret[0].(types.Tx) ret1, _ := ret[1].(error) return ret0, ret1 } // ProcessProposalVerifyTx indicates an expected call of ProcessProposalVerifyTx. -func (mr *MockProposalTxVerifierMockRecorder) ProcessProposalVerifyTx(txBz interface{}) *gomock.Call { +func (mr *MockProposalTxVerifierMockRecorder) ProcessProposalVerifyTx(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessProposalVerifyTx", reflect.TypeOf((*MockProposalTxVerifier)(nil).ProcessProposalVerifyTx), txBz) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessProposalVerifyTx", reflect.TypeOf((*MockProposalTxVerifier)(nil).ProcessProposalVerifyTx), arg0) } diff --git a/tests/integration/staking/keeper/vote_extensions_test.go b/tests/integration/staking/keeper/vote_extensions_test.go index 7fa941e20072..4056cfe5b6bc 100644 --- a/tests/integration/staking/keeper/vote_extensions_test.go +++ b/tests/integration/staking/keeper/vote_extensions_test.go @@ -75,7 +75,7 @@ func TestValidateVoteExtensions(t *testing.T) { ve := abci.ExtendedVoteInfo{ Validator: abci.Validator{ Address: valbz, - Power: v.ConsensusPower(sdk.DefaultPowerReduction), + Power: 1000, }, VoteExtension: voteExt, ExtensionSignature: sig, From 032683812c943b93f8249c90bfa2908af37d1978 Mon Sep 17 00:00:00 2001 From: David Terpay Date: Wed, 23 Aug 2023 17:58:12 -0400 Subject: [PATCH 2/5] changelog --- CHANGELOG.md | 1 + baseapp/abci_utils_test.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3b88b773c94..cae9eae35462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (types) [#16583](https://github.com/cosmos/cosmos-sdk/pull/16583), [#17372](https://github.com/cosmos/cosmos-sdk/pull/17372) Add `MigrationModuleManager` to handle migration of upgrade module before other modules, ensuring access to the updated context with consensus parameters within the same block that executes the migration. +* (baseapp) [#17518](https://github.com/cosmos/cosmos-sdk/pull/17518) Utilizing voting power from vote extensions (comet) instead of the current bonded tokens (baseapp) to determine if a set of vote extensions are valid. ### API Breaking Changes diff --git a/baseapp/abci_utils_test.go b/baseapp/abci_utils_test.go index c2f3dda33d90..cd8dbaf70d2d 100644 --- a/baseapp/abci_utils_test.go +++ b/baseapp/abci_utils_test.go @@ -4,7 +4,6 @@ import ( "bytes" "testing" - "cosmossdk.io/math" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/secp256k1" cmtprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" @@ -14,6 +13,8 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" From f5d0bf25ebc2f818ffee07f545f54d6d562ca367 Mon Sep 17 00:00:00 2001 From: David Terpay Date: Thu, 24 Aug 2023 10:44:28 -0400 Subject: [PATCH 3/5] nit --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cae9eae35462..a7a8b1c88296 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,7 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (types) [#16583](https://github.com/cosmos/cosmos-sdk/pull/16583), [#17372](https://github.com/cosmos/cosmos-sdk/pull/17372) Add `MigrationModuleManager` to handle migration of upgrade module before other modules, ensuring access to the updated context with consensus parameters within the same block that executes the migration. -* (baseapp) [#17518](https://github.com/cosmos/cosmos-sdk/pull/17518) Utilizing voting power from vote extensions (comet) instead of the current bonded tokens (baseapp) to determine if a set of vote extensions are valid. +* (baseapp) [#17518](https://github.com/cosmos/cosmos-sdk/pull/17518) Utilizing voting power from vote extensions (CometBFT) instead of the current bonded tokens (x/staking) to determine if a set of vote extensions are valid. ### API Breaking Changes From cb1648c480d0f710d50f5824517a45b0fc446696 Mon Sep 17 00:00:00 2001 From: David Terpay Date: Thu, 24 Aug 2023 14:11:20 -0400 Subject: [PATCH 4/5] updating staking keeper interface --- baseapp/abci_test.go | 3 +-- baseapp/abci_utils.go | 8 ++++---- baseapp/abci_utils_test.go | 8 +++----- baseapp/testutil/mock/mocks.go | 20 +++++++++----------- docs/architecture/adr-064-abci-2.0.md | 26 +++++++++++++++++++++----- x/staking/keeper/validator.go | 10 +++++----- x/staking/types/expected_keepers.go | 6 +++--- 7 files changed, 46 insertions(+), 35 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index ee322db5174a..f4f84d1d62b4 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -26,7 +26,6 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/log" - "cosmossdk.io/math" pruningtypes "cosmossdk.io/store/pruning/types" "cosmossdk.io/store/snapshots" snapshottypes "cosmossdk.io/store/snapshots/types" @@ -1791,7 +1790,7 @@ func TestABCI_PrepareProposal_VoteExtensions(t *testing.T) { } consAddr := sdk.ConsAddress(addr.String()) - valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), consAddr.Bytes()).Return(math.NewInt(0), tmPk, nil) + valStore.EXPECT().GetPubKeyByConsAddr(gomock.Any(), consAddr.Bytes()).Return(tmPk, nil) // set up baseapp prepareOpt := func(bapp *baseapp.BaseApp) { diff --git a/baseapp/abci_utils.go b/baseapp/abci_utils.go index 2c4f9a349074..4b2568d57dd7 100644 --- a/baseapp/abci_utils.go +++ b/baseapp/abci_utils.go @@ -29,7 +29,7 @@ type ( // extension signatures. Typically, this will be implemented by the x/staking // module, which has knowledge of the CometBFT public key. ValidatorStore interface { - BondedTokensAndPubKeyByConsAddr(context.Context, sdk.ConsAddress) (math.Int, cmtprotocrypto.PublicKey, error) + GetPubKeyByConsAddr(context.Context, sdk.ConsAddress) (cmtprotocrypto.PublicKey, error) } // GasTx defines the contract that a transaction with a gas limit must implement. @@ -93,12 +93,12 @@ func ValidateVoteExtensions( } valConsAddr := sdk.ConsAddress(vote.Validator.Address) - _, cmtPubKeyProto, err := valStore.BondedTokensAndPubKeyByConsAddr(ctx, valConsAddr) + pubKeyProto, err := valStore.GetPubKeyByConsAddr(ctx, valConsAddr) if err != nil { - return fmt.Errorf("failed to get validator %X info (bonded tokens and public key): %w", valConsAddr, err) + return fmt.Errorf("failed to get validator %X public key: %w", valConsAddr, err) } - cmtPubKey, err := cryptoenc.PubKeyFromProto(cmtPubKeyProto) + cmtPubKey, err := cryptoenc.PubKeyFromProto(pubKeyProto) if err != nil { return fmt.Errorf("failed to convert validator %X public key: %w", valConsAddr, err) } diff --git a/baseapp/abci_utils_test.go b/baseapp/abci_utils_test.go index cd8dbaf70d2d..8c7fda91de95 100644 --- a/baseapp/abci_utils_test.go +++ b/baseapp/abci_utils_test.go @@ -13,8 +13,6 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" - "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" @@ -78,9 +76,9 @@ func NewABCIUtilsTestSuite(t *testing.T) *ABCIUtilsTestSuite { s.valStore = valStore // set up mock - s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[0].consAddr.Bytes()).Return(math.NewInt(0), s.vals[0].tmPk, nil).AnyTimes() - s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[1].consAddr.Bytes()).Return(math.NewInt(0), s.vals[1].tmPk, nil).AnyTimes() - s.valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), s.vals[2].consAddr.Bytes()).Return(math.NewInt(0), s.vals[2].tmPk, nil).AnyTimes() + s.valStore.EXPECT().GetPubKeyByConsAddr(gomock.Any(), s.vals[0].consAddr.Bytes()).Return(s.vals[0].tmPk, nil).AnyTimes() + s.valStore.EXPECT().GetPubKeyByConsAddr(gomock.Any(), s.vals[1].consAddr.Bytes()).Return(s.vals[1].tmPk, nil).AnyTimes() + s.valStore.EXPECT().GetPubKeyByConsAddr(gomock.Any(), s.vals[2].consAddr.Bytes()).Return(s.vals[2].tmPk, nil).AnyTimes() // create context s.ctx = sdk.Context{}.WithConsensusParams(cmtproto.ConsensusParams{ diff --git a/baseapp/testutil/mock/mocks.go b/baseapp/testutil/mock/mocks.go index 5e89844a6ef4..342201227d0c 100644 --- a/baseapp/testutil/mock/mocks.go +++ b/baseapp/testutil/mock/mocks.go @@ -8,7 +8,6 @@ import ( context "context" reflect "reflect" - math "cosmossdk.io/math" crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" types "github.com/cosmos/cosmos-sdk/types" gomock "github.com/golang/mock/gomock" @@ -37,20 +36,19 @@ func (m *MockValidatorStore) EXPECT() *MockValidatorStoreMockRecorder { return m.recorder } -// BondedTokensAndPubKeyByConsAddr mocks base method. -func (m *MockValidatorStore) BondedTokensAndPubKeyByConsAddr(arg0 context.Context, arg1 types.ConsAddress) (math.Int, crypto.PublicKey, error) { +// GetPubKeyByConsAddr mocks base method. +func (m *MockValidatorStore) GetPubKeyByConsAddr(arg0 context.Context, arg1 types.ConsAddress) (crypto.PublicKey, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BondedTokensAndPubKeyByConsAddr", arg0, arg1) - ret0, _ := ret[0].(math.Int) - ret1, _ := ret[1].(crypto.PublicKey) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret := m.ctrl.Call(m, "GetPubKeyByConsAddr", arg0, arg1) + ret0, _ := ret[0].(crypto.PublicKey) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// BondedTokensAndPubKeyByConsAddr indicates an expected call of BondedTokensAndPubKeyByConsAddr. -func (mr *MockValidatorStoreMockRecorder) BondedTokensAndPubKeyByConsAddr(arg0, arg1 interface{}) *gomock.Call { +// GetPubKeyByConsAddr indicates an expected call of GetPubKeyByConsAddr. +func (mr *MockValidatorStoreMockRecorder) GetPubKeyByConsAddr(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondedTokensAndPubKeyByConsAddr", reflect.TypeOf((*MockValidatorStore)(nil).BondedTokensAndPubKeyByConsAddr), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPubKeyByConsAddr", reflect.TypeOf((*MockValidatorStore)(nil).GetPubKeyByConsAddr), arg0, arg1) } // MockGasTx is a mock of GasTx interface. diff --git a/docs/architecture/adr-064-abci-2.0.md b/docs/architecture/adr-064-abci-2.0.md index f4665c3de7d7..cdbd88024d88 100644 --- a/docs/architecture/adr-064-abci-2.0.md +++ b/docs/architecture/adr-064-abci-2.0.md @@ -6,6 +6,7 @@ * 2023-04-06: Add upgrading section (@alexanderbez) * 2023-04-10: Simplify vote extension state persistence (@alexanderbez) * 2023-07-07: Revise vote extension state persistence (@alexanderbez) +* 2023-08-24: Revise vote extension power calculations and staking interface (@davidterpay) ## Status @@ -219,28 +220,37 @@ a default signature verification method which applications can use: ```go type ValidatorStore interface { - TotalBondedTokens(ctx context.Context) (math.Int, error) - BondedTokensAndPubKeyByConsAddr(context.Context, sdk.ConsAddress) (math.Int, cmtprotocrypto.PublicKey, error) + GetPubKeyByConsAddr(context.Context, sdk.ConsAddress) (cmtprotocrypto.PublicKey, error) } // ValidateVoteExtensions is a function that an application can execute in // ProcessProposal to verify vote extension signatures. func (app *BaseApp) ValidateVoteExtensions(ctx sdk.Context, currentHeight int64, extCommit abci.ExtendedCommitInfo) error { + votingPower := 0 + totalVotingPower := 0 + for _, vote := range extCommit.Votes { + totalVotingPower += vote.Validator.Power + if !vote.SignedLastBlock || len(vote.VoteExtension) == 0 { continue } valConsAddr := sdk.ConsAddress(vote.Validator.Address) - bondedTokens, cmtPubKey, err := valStore.BondedTokensAndPubKeyByConsAddr(ctx, valConsAddr) + pubKeyProto, err := valStore.GetPubKeyByConsAddr(ctx, valConsAddr) if err != nil { - return fmt.Errorf("failed to get bonded tokens and public key for validator %s: %w", valConsAddr, err) + return fmt.Errorf("failed to get public key for validator %s: %w", valConsAddr, err) } if len(vote.ExtensionSignature) == 0 { return fmt.Errorf("received a non-empty vote extension with empty signature for validator %s", valConsAddr) } + cmtPubKey, err := cryptoenc.PubKeyFromProto(pubKeyProto) + if err != nil { + return fmt.Errorf("failed to convert validator %X public key: %w", valConsAddr, err) + } + cve := cmtproto.CanonicalVoteExtension{ Extension: vote.VoteExtension, Height: currentHeight - 1, // the vote extension was signed in the previous height @@ -257,8 +267,14 @@ func (app *BaseApp) ValidateVoteExtensions(ctx sdk.Context, currentHeight int64, return errors.New("received vote with invalid signature") } - return nil + votingPower += vote.Validator.Power + } + + if (votingPower / totalVotingPower) < threshold { + return errors.New("not enough voting power for the vote extensions") } + + return nil } ``` diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index 1462b3e9a6fc..a08d2a4d9e1e 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -629,17 +629,17 @@ func (k Keeper) IsValidatorJailed(ctx context.Context, addr sdk.ConsAddress) (bo return v.Jailed, nil } -// BondedTokensAndPubKeyByConsAddr returns the consensus public key and bonded tokens by consensus address -func (k Keeper) BondedTokensAndPubKeyByConsAddr(ctx context.Context, addr sdk.ConsAddress) (math.Int, cmtprotocrypto.PublicKey, error) { +// GetPubKeyByConsAddr returns the consensus public key by consensus address. +func (k Keeper) GetPubKeyByConsAddr(ctx context.Context, addr sdk.ConsAddress) (cmtprotocrypto.PublicKey, error) { v, err := k.GetValidatorByConsAddr(ctx, addr) if err != nil { - return math.ZeroInt(), cmtprotocrypto.PublicKey{}, err + return cmtprotocrypto.PublicKey{}, err } pubkey, err := v.CmtConsPublicKey() if err != nil { - return math.ZeroInt(), cmtprotocrypto.PublicKey{}, err + return cmtprotocrypto.PublicKey{}, err } - return v.BondedTokens(), pubkey, nil + return pubkey, nil } diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index f46b817ea95e..3c3ae276ed16 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -74,9 +74,9 @@ type ValidatorSet interface { // MaxValidators returns the maximum amount of bonded validators MaxValidators(context.Context) (uint32, error) - // BondedTokensAndPubKeyByConsAddr returns the bonded tokens and consensus public key for a validator. - // Used in vote extension validation. - BondedTokensAndPubKeyByConsAddr(context.Context, sdk.ConsAddress) (math.Int, cmtprotocrypto.PublicKey, error) + // GetPubKeyByConsAddr returns the consensus public key for a validator. Used in vote + // extension validation. + GetPubKeyByConsAddr(context.Context, sdk.ConsAddress) (cmtprotocrypto.PublicKey, error) } // DelegationSet expected properties for the set of all delegations for a particular (noalias) From dc416ce6fca8bf8cc700f624f08bd8e1a7f1d326 Mon Sep 17 00:00:00 2001 From: David Terpay Date: Thu, 24 Aug 2023 14:25:51 -0400 Subject: [PATCH 5/5] updating expected keeper mocks --- x/staking/testutil/expected_keepers_mocks.go | 231 +++++++++---------- 1 file changed, 115 insertions(+), 116 deletions(-) diff --git a/x/staking/testutil/expected_keepers_mocks.go b/x/staking/testutil/expected_keepers_mocks.go index 463d4d7336fc..a28ef2a097ef 100644 --- a/x/staking/testutil/expected_keepers_mocks.go +++ b/x/staking/testutil/expected_keepers_mocks.go @@ -55,57 +55,57 @@ func (mr *MockAccountKeeperMockRecorder) AddressCodec() *gomock.Call { } // GetAccount mocks base method. -func (m *MockAccountKeeper) GetAccount(ctx context.Context, addr types.AccAddress) types.AccountI { +func (m *MockAccountKeeper) GetAccount(arg0 context.Context, arg1 types.AccAddress) types.AccountI { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAccount", ctx, addr) + ret := m.ctrl.Call(m, "GetAccount", arg0, arg1) ret0, _ := ret[0].(types.AccountI) return ret0 } // GetAccount indicates an expected call of GetAccount. -func (mr *MockAccountKeeperMockRecorder) GetAccount(ctx, addr interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) GetAccount(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetAccount), ctx, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetAccount), arg0, arg1) } // GetModuleAccount mocks base method. -func (m *MockAccountKeeper) GetModuleAccount(ctx context.Context, moduleName string) types.ModuleAccountI { +func (m *MockAccountKeeper) GetModuleAccount(arg0 context.Context, arg1 string) types.ModuleAccountI { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetModuleAccount", ctx, moduleName) + ret := m.ctrl.Call(m, "GetModuleAccount", arg0, arg1) ret0, _ := ret[0].(types.ModuleAccountI) return ret0 } // GetModuleAccount indicates an expected call of GetModuleAccount. -func (mr *MockAccountKeeperMockRecorder) GetModuleAccount(ctx, moduleName interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) GetModuleAccount(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAccount), ctx, moduleName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAccount), arg0, arg1) } // GetModuleAddress mocks base method. -func (m *MockAccountKeeper) GetModuleAddress(name string) types.AccAddress { +func (m *MockAccountKeeper) GetModuleAddress(arg0 string) types.AccAddress { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetModuleAddress", name) + ret := m.ctrl.Call(m, "GetModuleAddress", arg0) ret0, _ := ret[0].(types.AccAddress) return ret0 } // GetModuleAddress indicates an expected call of GetModuleAddress. -func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(name interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddress", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddress), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddress", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddress), arg0) } // IterateAccounts mocks base method. -func (m *MockAccountKeeper) IterateAccounts(ctx context.Context, process func(types.AccountI) bool) { +func (m *MockAccountKeeper) IterateAccounts(arg0 context.Context, arg1 func(types.AccountI) bool) { m.ctrl.T.Helper() - m.ctrl.Call(m, "IterateAccounts", ctx, process) + m.ctrl.Call(m, "IterateAccounts", arg0, arg1) } // IterateAccounts indicates an expected call of IterateAccounts. -func (mr *MockAccountKeeperMockRecorder) IterateAccounts(ctx, process interface{}) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) IterateAccounts(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccounts", reflect.TypeOf((*MockAccountKeeper)(nil).IterateAccounts), ctx, process) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccounts", reflect.TypeOf((*MockAccountKeeper)(nil).IterateAccounts), arg0, arg1) } // SetModuleAccount mocks base method. @@ -144,129 +144,129 @@ func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder { } // BurnCoins mocks base method. -func (m *MockBankKeeper) BurnCoins(ctx context.Context, name string, amt types.Coins) error { +func (m *MockBankKeeper) BurnCoins(arg0 context.Context, arg1 string, arg2 types.Coins) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BurnCoins", ctx, name, amt) + ret := m.ctrl.Call(m, "BurnCoins", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // BurnCoins indicates an expected call of BurnCoins. -func (mr *MockBankKeeperMockRecorder) BurnCoins(ctx, name, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) BurnCoins(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BurnCoins", reflect.TypeOf((*MockBankKeeper)(nil).BurnCoins), ctx, name, amt) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BurnCoins", reflect.TypeOf((*MockBankKeeper)(nil).BurnCoins), arg0, arg1, arg2) } // DelegateCoinsFromAccountToModule mocks base method. -func (m *MockBankKeeper) DelegateCoinsFromAccountToModule(ctx context.Context, senderAddr types.AccAddress, recipientModule string, amt types.Coins) error { +func (m *MockBankKeeper) DelegateCoinsFromAccountToModule(arg0 context.Context, arg1 types.AccAddress, arg2 string, arg3 types.Coins) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DelegateCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt) + ret := m.ctrl.Call(m, "DelegateCoinsFromAccountToModule", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(error) return ret0 } // DelegateCoinsFromAccountToModule indicates an expected call of DelegateCoinsFromAccountToModule. -func (mr *MockBankKeeperMockRecorder) DelegateCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) DelegateCoinsFromAccountToModule(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DelegateCoinsFromAccountToModule", reflect.TypeOf((*MockBankKeeper)(nil).DelegateCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DelegateCoinsFromAccountToModule", reflect.TypeOf((*MockBankKeeper)(nil).DelegateCoinsFromAccountToModule), arg0, arg1, arg2, arg3) } // GetAllBalances mocks base method. -func (m *MockBankKeeper) GetAllBalances(ctx context.Context, addr types.AccAddress) types.Coins { +func (m *MockBankKeeper) GetAllBalances(arg0 context.Context, arg1 types.AccAddress) types.Coins { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr) + ret := m.ctrl.Call(m, "GetAllBalances", arg0, arg1) ret0, _ := ret[0].(types.Coins) return ret0 } // GetAllBalances indicates an expected call of GetAllBalances. -func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetAllBalances(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllBalances", reflect.TypeOf((*MockBankKeeper)(nil).GetAllBalances), ctx, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllBalances", reflect.TypeOf((*MockBankKeeper)(nil).GetAllBalances), arg0, arg1) } // GetBalance mocks base method. -func (m *MockBankKeeper) GetBalance(ctx context.Context, addr types.AccAddress, denom string) types.Coin { +func (m *MockBankKeeper) GetBalance(arg0 context.Context, arg1 types.AccAddress, arg2 string) types.Coin { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBalance", ctx, addr, denom) + ret := m.ctrl.Call(m, "GetBalance", arg0, arg1, arg2) ret0, _ := ret[0].(types.Coin) return ret0 } // GetBalance indicates an expected call of GetBalance. -func (mr *MockBankKeeperMockRecorder) GetBalance(ctx, addr, denom interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetBalance(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*MockBankKeeper)(nil).GetBalance), ctx, addr, denom) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*MockBankKeeper)(nil).GetBalance), arg0, arg1, arg2) } // GetSupply mocks base method. -func (m *MockBankKeeper) GetSupply(ctx context.Context, denom string) types.Coin { +func (m *MockBankKeeper) GetSupply(arg0 context.Context, arg1 string) types.Coin { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSupply", ctx, denom) + ret := m.ctrl.Call(m, "GetSupply", arg0, arg1) ret0, _ := ret[0].(types.Coin) return ret0 } // GetSupply indicates an expected call of GetSupply. -func (mr *MockBankKeeperMockRecorder) GetSupply(ctx, denom interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) GetSupply(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSupply", reflect.TypeOf((*MockBankKeeper)(nil).GetSupply), ctx, denom) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSupply", reflect.TypeOf((*MockBankKeeper)(nil).GetSupply), arg0, arg1) } // LockedCoins mocks base method. -func (m *MockBankKeeper) LockedCoins(ctx context.Context, addr types.AccAddress) types.Coins { +func (m *MockBankKeeper) LockedCoins(arg0 context.Context, arg1 types.AccAddress) types.Coins { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LockedCoins", ctx, addr) + ret := m.ctrl.Call(m, "LockedCoins", arg0, arg1) ret0, _ := ret[0].(types.Coins) return ret0 } // LockedCoins indicates an expected call of LockedCoins. -func (mr *MockBankKeeperMockRecorder) LockedCoins(ctx, addr interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) LockedCoins(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LockedCoins", reflect.TypeOf((*MockBankKeeper)(nil).LockedCoins), ctx, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LockedCoins", reflect.TypeOf((*MockBankKeeper)(nil).LockedCoins), arg0, arg1) } // SendCoinsFromModuleToModule mocks base method. -func (m *MockBankKeeper) SendCoinsFromModuleToModule(ctx context.Context, senderPool, recipientPool string, amt types.Coins) error { +func (m *MockBankKeeper) SendCoinsFromModuleToModule(arg0 context.Context, arg1, arg2 string, arg3 types.Coins) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SendCoinsFromModuleToModule", ctx, senderPool, recipientPool, amt) + ret := m.ctrl.Call(m, "SendCoinsFromModuleToModule", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(error) return ret0 } // SendCoinsFromModuleToModule indicates an expected call of SendCoinsFromModuleToModule. -func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToModule(ctx, senderPool, recipientPool, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToModule(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToModule", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromModuleToModule), ctx, senderPool, recipientPool, amt) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToModule", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromModuleToModule), arg0, arg1, arg2, arg3) } // SpendableCoins mocks base method. -func (m *MockBankKeeper) SpendableCoins(ctx context.Context, addr types.AccAddress) types.Coins { +func (m *MockBankKeeper) SpendableCoins(arg0 context.Context, arg1 types.AccAddress) types.Coins { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SpendableCoins", ctx, addr) + ret := m.ctrl.Call(m, "SpendableCoins", arg0, arg1) ret0, _ := ret[0].(types.Coins) return ret0 } // SpendableCoins indicates an expected call of SpendableCoins. -func (mr *MockBankKeeperMockRecorder) SpendableCoins(ctx, addr interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) SpendableCoins(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoins", reflect.TypeOf((*MockBankKeeper)(nil).SpendableCoins), ctx, addr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoins", reflect.TypeOf((*MockBankKeeper)(nil).SpendableCoins), arg0, arg1) } // UndelegateCoinsFromModuleToAccount mocks base method. -func (m *MockBankKeeper) UndelegateCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins) error { +func (m *MockBankKeeper) UndelegateCoinsFromModuleToAccount(arg0 context.Context, arg1 string, arg2 types.AccAddress, arg3 types.Coins) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UndelegateCoinsFromModuleToAccount", ctx, senderModule, recipientAddr, amt) + ret := m.ctrl.Call(m, "UndelegateCoinsFromModuleToAccount", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(error) return ret0 } // UndelegateCoinsFromModuleToAccount indicates an expected call of UndelegateCoinsFromModuleToAccount. -func (mr *MockBankKeeperMockRecorder) UndelegateCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt interface{}) *gomock.Call { +func (mr *MockBankKeeperMockRecorder) UndelegateCoinsFromModuleToAccount(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UndelegateCoinsFromModuleToAccount", reflect.TypeOf((*MockBankKeeper)(nil).UndelegateCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UndelegateCoinsFromModuleToAccount", reflect.TypeOf((*MockBankKeeper)(nil).UndelegateCoinsFromModuleToAccount), arg0, arg1, arg2, arg3) } // MockValidatorSet is a mock of ValidatorSet interface. @@ -292,22 +292,6 @@ func (m *MockValidatorSet) EXPECT() *MockValidatorSetMockRecorder { return m.recorder } -// BondedTokensAndPubKeyByConsAddr mocks base method. -func (m *MockValidatorSet) BondedTokensAndPubKeyByConsAddr(arg0 context.Context, arg1 types.ConsAddress) (math.Int, crypto.PublicKey, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BondedTokensAndPubKeyByConsAddr", arg0, arg1) - ret0, _ := ret[0].(math.Int) - ret1, _ := ret[1].(crypto.PublicKey) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// BondedTokensAndPubKeyByConsAddr indicates an expected call of BondedTokensAndPubKeyByConsAddr. -func (mr *MockValidatorSetMockRecorder) BondedTokensAndPubKeyByConsAddr(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondedTokensAndPubKeyByConsAddr", reflect.TypeOf((*MockValidatorSet)(nil).BondedTokensAndPubKeyByConsAddr), arg0, arg1) -} - // Delegation mocks base method. func (m *MockValidatorSet) Delegation(arg0 context.Context, arg1 types.AccAddress, arg2 types.ValAddress) (types0.DelegationI, error) { m.ctrl.T.Helper() @@ -323,6 +307,21 @@ func (mr *MockValidatorSetMockRecorder) Delegation(arg0, arg1, arg2 interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delegation", reflect.TypeOf((*MockValidatorSet)(nil).Delegation), arg0, arg1, arg2) } +// GetPubKeyByConsAddr mocks base method. +func (m *MockValidatorSet) GetPubKeyByConsAddr(arg0 context.Context, arg1 types.ConsAddress) (crypto.PublicKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPubKeyByConsAddr", arg0, arg1) + ret0, _ := ret[0].(crypto.PublicKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPubKeyByConsAddr indicates an expected call of GetPubKeyByConsAddr. +func (mr *MockValidatorSetMockRecorder) GetPubKeyByConsAddr(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPubKeyByConsAddr", reflect.TypeOf((*MockValidatorSet)(nil).GetPubKeyByConsAddr), arg0, arg1) +} + // IterateBondedValidatorsByPower mocks base method. func (m *MockValidatorSet) IterateBondedValidatorsByPower(arg0 context.Context, arg1 func(int64, types0.ValidatorI) bool) error { m.ctrl.T.Helper() @@ -536,17 +535,17 @@ func (mr *MockDelegationSetMockRecorder) GetValidatorSet() *gomock.Call { } // IterateDelegations mocks base method. -func (m *MockDelegationSet) IterateDelegations(ctx context.Context, delegator types.AccAddress, fn func(int64, types0.DelegationI) bool) error { +func (m *MockDelegationSet) IterateDelegations(arg0 context.Context, arg1 types.AccAddress, arg2 func(int64, types0.DelegationI) bool) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IterateDelegations", ctx, delegator, fn) + ret := m.ctrl.Call(m, "IterateDelegations", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // IterateDelegations indicates an expected call of IterateDelegations. -func (mr *MockDelegationSetMockRecorder) IterateDelegations(ctx, delegator, fn interface{}) *gomock.Call { +func (mr *MockDelegationSetMockRecorder) IterateDelegations(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateDelegations", reflect.TypeOf((*MockDelegationSet)(nil).IterateDelegations), ctx, delegator, fn) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateDelegations", reflect.TypeOf((*MockDelegationSet)(nil).IterateDelegations), arg0, arg1, arg2) } // MockStakingHooks is a mock of StakingHooks interface. @@ -573,155 +572,155 @@ func (m *MockStakingHooks) EXPECT() *MockStakingHooksMockRecorder { } // AfterDelegationModified mocks base method. -func (m *MockStakingHooks) AfterDelegationModified(ctx context.Context, delAddr types.AccAddress, valAddr types.ValAddress) error { +func (m *MockStakingHooks) AfterDelegationModified(arg0 context.Context, arg1 types.AccAddress, arg2 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AfterDelegationModified", ctx, delAddr, valAddr) + ret := m.ctrl.Call(m, "AfterDelegationModified", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // AfterDelegationModified indicates an expected call of AfterDelegationModified. -func (mr *MockStakingHooksMockRecorder) AfterDelegationModified(ctx, delAddr, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) AfterDelegationModified(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterDelegationModified", reflect.TypeOf((*MockStakingHooks)(nil).AfterDelegationModified), ctx, delAddr, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterDelegationModified", reflect.TypeOf((*MockStakingHooks)(nil).AfterDelegationModified), arg0, arg1, arg2) } // AfterUnbondingInitiated mocks base method. -func (m *MockStakingHooks) AfterUnbondingInitiated(ctx context.Context, id uint64) error { +func (m *MockStakingHooks) AfterUnbondingInitiated(arg0 context.Context, arg1 uint64) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AfterUnbondingInitiated", ctx, id) + ret := m.ctrl.Call(m, "AfterUnbondingInitiated", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } // AfterUnbondingInitiated indicates an expected call of AfterUnbondingInitiated. -func (mr *MockStakingHooksMockRecorder) AfterUnbondingInitiated(ctx, id interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) AfterUnbondingInitiated(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterUnbondingInitiated", reflect.TypeOf((*MockStakingHooks)(nil).AfterUnbondingInitiated), ctx, id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterUnbondingInitiated", reflect.TypeOf((*MockStakingHooks)(nil).AfterUnbondingInitiated), arg0, arg1) } // AfterValidatorBeginUnbonding mocks base method. -func (m *MockStakingHooks) AfterValidatorBeginUnbonding(ctx context.Context, consAddr types.ConsAddress, valAddr types.ValAddress) error { +func (m *MockStakingHooks) AfterValidatorBeginUnbonding(arg0 context.Context, arg1 types.ConsAddress, arg2 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AfterValidatorBeginUnbonding", ctx, consAddr, valAddr) + ret := m.ctrl.Call(m, "AfterValidatorBeginUnbonding", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // AfterValidatorBeginUnbonding indicates an expected call of AfterValidatorBeginUnbonding. -func (mr *MockStakingHooksMockRecorder) AfterValidatorBeginUnbonding(ctx, consAddr, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) AfterValidatorBeginUnbonding(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorBeginUnbonding", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorBeginUnbonding), ctx, consAddr, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorBeginUnbonding", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorBeginUnbonding), arg0, arg1, arg2) } // AfterValidatorBonded mocks base method. -func (m *MockStakingHooks) AfterValidatorBonded(ctx context.Context, consAddr types.ConsAddress, valAddr types.ValAddress) error { +func (m *MockStakingHooks) AfterValidatorBonded(arg0 context.Context, arg1 types.ConsAddress, arg2 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AfterValidatorBonded", ctx, consAddr, valAddr) + ret := m.ctrl.Call(m, "AfterValidatorBonded", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // AfterValidatorBonded indicates an expected call of AfterValidatorBonded. -func (mr *MockStakingHooksMockRecorder) AfterValidatorBonded(ctx, consAddr, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) AfterValidatorBonded(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorBonded", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorBonded), ctx, consAddr, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorBonded", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorBonded), arg0, arg1, arg2) } // AfterValidatorCreated mocks base method. -func (m *MockStakingHooks) AfterValidatorCreated(ctx context.Context, valAddr types.ValAddress) error { +func (m *MockStakingHooks) AfterValidatorCreated(arg0 context.Context, arg1 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AfterValidatorCreated", ctx, valAddr) + ret := m.ctrl.Call(m, "AfterValidatorCreated", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } // AfterValidatorCreated indicates an expected call of AfterValidatorCreated. -func (mr *MockStakingHooksMockRecorder) AfterValidatorCreated(ctx, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) AfterValidatorCreated(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorCreated", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorCreated), ctx, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorCreated", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorCreated), arg0, arg1) } // AfterValidatorRemoved mocks base method. -func (m *MockStakingHooks) AfterValidatorRemoved(ctx context.Context, consAddr types.ConsAddress, valAddr types.ValAddress) error { +func (m *MockStakingHooks) AfterValidatorRemoved(arg0 context.Context, arg1 types.ConsAddress, arg2 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AfterValidatorRemoved", ctx, consAddr, valAddr) + ret := m.ctrl.Call(m, "AfterValidatorRemoved", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // AfterValidatorRemoved indicates an expected call of AfterValidatorRemoved. -func (mr *MockStakingHooksMockRecorder) AfterValidatorRemoved(ctx, consAddr, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) AfterValidatorRemoved(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorRemoved", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorRemoved), ctx, consAddr, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorRemoved", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorRemoved), arg0, arg1, arg2) } // BeforeDelegationCreated mocks base method. -func (m *MockStakingHooks) BeforeDelegationCreated(ctx context.Context, delAddr types.AccAddress, valAddr types.ValAddress) error { +func (m *MockStakingHooks) BeforeDelegationCreated(arg0 context.Context, arg1 types.AccAddress, arg2 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BeforeDelegationCreated", ctx, delAddr, valAddr) + ret := m.ctrl.Call(m, "BeforeDelegationCreated", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // BeforeDelegationCreated indicates an expected call of BeforeDelegationCreated. -func (mr *MockStakingHooksMockRecorder) BeforeDelegationCreated(ctx, delAddr, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) BeforeDelegationCreated(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeDelegationCreated", reflect.TypeOf((*MockStakingHooks)(nil).BeforeDelegationCreated), ctx, delAddr, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeDelegationCreated", reflect.TypeOf((*MockStakingHooks)(nil).BeforeDelegationCreated), arg0, arg1, arg2) } // BeforeDelegationRemoved mocks base method. -func (m *MockStakingHooks) BeforeDelegationRemoved(ctx context.Context, delAddr types.AccAddress, valAddr types.ValAddress) error { +func (m *MockStakingHooks) BeforeDelegationRemoved(arg0 context.Context, arg1 types.AccAddress, arg2 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BeforeDelegationRemoved", ctx, delAddr, valAddr) + ret := m.ctrl.Call(m, "BeforeDelegationRemoved", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // BeforeDelegationRemoved indicates an expected call of BeforeDelegationRemoved. -func (mr *MockStakingHooksMockRecorder) BeforeDelegationRemoved(ctx, delAddr, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) BeforeDelegationRemoved(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeDelegationRemoved", reflect.TypeOf((*MockStakingHooks)(nil).BeforeDelegationRemoved), ctx, delAddr, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeDelegationRemoved", reflect.TypeOf((*MockStakingHooks)(nil).BeforeDelegationRemoved), arg0, arg1, arg2) } // BeforeDelegationSharesModified mocks base method. -func (m *MockStakingHooks) BeforeDelegationSharesModified(ctx context.Context, delAddr types.AccAddress, valAddr types.ValAddress) error { +func (m *MockStakingHooks) BeforeDelegationSharesModified(arg0 context.Context, arg1 types.AccAddress, arg2 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BeforeDelegationSharesModified", ctx, delAddr, valAddr) + ret := m.ctrl.Call(m, "BeforeDelegationSharesModified", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // BeforeDelegationSharesModified indicates an expected call of BeforeDelegationSharesModified. -func (mr *MockStakingHooksMockRecorder) BeforeDelegationSharesModified(ctx, delAddr, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) BeforeDelegationSharesModified(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeDelegationSharesModified", reflect.TypeOf((*MockStakingHooks)(nil).BeforeDelegationSharesModified), ctx, delAddr, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeDelegationSharesModified", reflect.TypeOf((*MockStakingHooks)(nil).BeforeDelegationSharesModified), arg0, arg1, arg2) } // BeforeValidatorModified mocks base method. -func (m *MockStakingHooks) BeforeValidatorModified(ctx context.Context, valAddr types.ValAddress) error { +func (m *MockStakingHooks) BeforeValidatorModified(arg0 context.Context, arg1 types.ValAddress) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BeforeValidatorModified", ctx, valAddr) + ret := m.ctrl.Call(m, "BeforeValidatorModified", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } // BeforeValidatorModified indicates an expected call of BeforeValidatorModified. -func (mr *MockStakingHooksMockRecorder) BeforeValidatorModified(ctx, valAddr interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) BeforeValidatorModified(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeValidatorModified", reflect.TypeOf((*MockStakingHooks)(nil).BeforeValidatorModified), ctx, valAddr) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeValidatorModified", reflect.TypeOf((*MockStakingHooks)(nil).BeforeValidatorModified), arg0, arg1) } // BeforeValidatorSlashed mocks base method. -func (m *MockStakingHooks) BeforeValidatorSlashed(ctx context.Context, valAddr types.ValAddress, fraction math.LegacyDec) error { +func (m *MockStakingHooks) BeforeValidatorSlashed(arg0 context.Context, arg1 types.ValAddress, arg2 math.LegacyDec) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BeforeValidatorSlashed", ctx, valAddr, fraction) + ret := m.ctrl.Call(m, "BeforeValidatorSlashed", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // BeforeValidatorSlashed indicates an expected call of BeforeValidatorSlashed. -func (mr *MockStakingHooksMockRecorder) BeforeValidatorSlashed(ctx, valAddr, fraction interface{}) *gomock.Call { +func (mr *MockStakingHooksMockRecorder) BeforeValidatorSlashed(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeValidatorSlashed", reflect.TypeOf((*MockStakingHooks)(nil).BeforeValidatorSlashed), ctx, valAddr, fraction) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeValidatorSlashed", reflect.TypeOf((*MockStakingHooks)(nil).BeforeValidatorSlashed), arg0, arg1, arg2) }