fix: ValidatorStore interface doesn't match StakingKeeper (#17164)

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
This commit is contained in:
Facundo Medica
2023-08-03 22:53:05 +00:00
committed by GitHub
co-authored by Aleksandr Bezobchuk
parent 92dffb5fa8
commit c3ae0b09d4
9 changed files with 174 additions and 113 deletions
+3 -7
View File
@@ -1790,13 +1790,9 @@ func TestABCI_PrepareProposal_VoteExtensions(t *testing.T) {
},
}
val1 := mock.NewMockValidator(ctrl)
val1.EXPECT().BondedTokens().Return(math.NewInt(667))
val1.EXPECT().CmtConsPublicKey().Return(tmPk, nil).AnyTimes()
consAddr := sdk.ConsAddress(addr.String())
valStore.EXPECT().GetValidatorByConsAddr(gomock.Any(), consAddr.Bytes()).Return(val1, nil).AnyTimes()
valStore.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(1000)).AnyTimes()
valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), consAddr.Bytes()).Return(math.NewInt(667), tmPk, nil)
valStore.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(1000), nil).AnyTimes()
// set up baseapp
prepareOpt := func(bapp *baseapp.BaseApp) {
@@ -1884,7 +1880,7 @@ 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
val1.EXPECT().BondedTokens().Return(math.NewInt(666))
valStore.EXPECT().BondedTokensAndPubKeyByConsAddr(gomock.Any(), consAddr.Bytes()).Return(math.NewInt(666), tmPk, nil)
resPrepareProposal, err = suite.baseApp.PrepareProposal(&reqPrepareProposal)
require.NoError(t, err)
require.Equal(t, 0, len(resPrepareProposal.Txs))
+12 -27
View File
@@ -2,11 +2,11 @@ package baseapp
import (
"bytes"
"context"
"fmt"
"github.com/cockroachdb/errors"
abci "github.com/cometbft/cometbft/abci/types"
cmtcrypto "github.com/cometbft/cometbft/crypto"
cryptoenc "github.com/cometbft/cometbft/crypto/encoding"
cmtprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
@@ -15,7 +15,6 @@ import (
"cosmossdk.io/math"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/mempool"
)
@@ -26,20 +25,12 @@ import (
var VoteExtensionThreshold = math.LegacyNewDecWithPrec(667, 3)
type (
// Validator defines the interface contract require for verifying vote extension
// signatures. Typically, this will be implemented by the x/staking module,
// which has knowledge of the CometBFT public key.
Validator interface {
CmtConsPublicKey() (cmtprotocrypto.PublicKey, error)
BondedTokens() math.Int
}
// ValidatorStore defines the interface contract require for verifying vote
// extension signatures. Typically, this will be implemented by the x/staking
// module, which has knowledge of the CometBFT public key.
ValidatorStore interface {
GetValidatorByConsAddr(sdk.Context, cryptotypes.Address) (Validator, error)
TotalBondedTokens(ctx sdk.Context) math.Int
TotalBondedTokens(ctx context.Context) (math.Int, error)
BondedTokensAndPubKeyByConsAddr(context.Context, sdk.ConsAddress) (math.Int, cmtprotocrypto.PublicKey, error)
}
// GasTx defines the contract that a transaction with a gas limit must implement.
@@ -62,7 +53,6 @@ func ValidateVoteExtensions(
) error {
cp := ctx.ConsensusParams()
extsEnabled := cp.Abci != nil && currentHeight >= cp.Abci.VoteExtensionsEnableHeight && cp.Abci.VoteExtensionsEnableHeight != 0
marshalDelimitedFn := func(msg proto.Message) ([]byte, error) {
var buf bytes.Buffer
if err := protoio.NewDelimitedWriter(&buf).WriteMsg(msg); err != nil {
@@ -89,19 +79,10 @@ func ValidateVoteExtensions(
return fmt.Errorf("vote extensions enabled; received empty vote extension signature at height %d", currentHeight)
}
valConsAddr := cmtcrypto.Address(vote.Validator.Address)
validator, err := valStore.GetValidatorByConsAddr(ctx, valConsAddr)
valConsAddr := sdk.ConsAddress(vote.Validator.Address)
bondedTokens, cmtPubKeyProto, err := valStore.BondedTokensAndPubKeyByConsAddr(ctx, valConsAddr)
if err != nil {
return fmt.Errorf("failed to get validator %X: %w", valConsAddr, err)
}
if validator == nil {
return fmt.Errorf("validator %X not found", valConsAddr)
}
cmtPubKeyProto, err := validator.CmtConsPublicKey()
if err != nil {
return fmt.Errorf("failed to get validator %X public key: %w", valConsAddr, err)
return fmt.Errorf("failed to get validator %X info (bonded tokens and public key): %w", valConsAddr, err)
}
cmtPubKey, err := cryptoenc.PubKeyFromProto(cmtPubKeyProto)
@@ -125,12 +106,16 @@ func ValidateVoteExtensions(
return fmt.Errorf("failed to verify validator %X vote extension signature", valConsAddr)
}
sumVP = sumVP.Add(validator.BondedTokens())
sumVP = sumVP.Add(bondedTokens)
}
// Ensure we have at least 2/3 voting power that submitted valid vote
// extensions.
totalVP := valStore.TotalBondedTokens(ctx)
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)
+18 -69
View File
@@ -5,68 +5,15 @@
package mock
import (
context "context"
reflect "reflect"
math "cosmossdk.io/math"
crypto "github.com/cometbft/cometbft/proto/tendermint/crypto"
baseapp "github.com/cosmos/cosmos-sdk/baseapp"
types "github.com/cosmos/cosmos-sdk/crypto/types"
types0 "github.com/cosmos/cosmos-sdk/types"
types "github.com/cosmos/cosmos-sdk/types"
gomock "github.com/golang/mock/gomock"
)
// MockValidator is a mock of Validator interface.
type MockValidator struct {
ctrl *gomock.Controller
recorder *MockValidatorMockRecorder
}
// MockValidatorMockRecorder is the mock recorder for MockValidator.
type MockValidatorMockRecorder struct {
mock *MockValidator
}
// NewMockValidator creates a new mock instance.
func NewMockValidator(ctrl *gomock.Controller) *MockValidator {
mock := &MockValidator{ctrl: ctrl}
mock.recorder = &MockValidatorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockValidator) EXPECT() *MockValidatorMockRecorder {
return m.recorder
}
// BondedTokens mocks base method.
func (m *MockValidator) BondedTokens() math.Int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BondedTokens")
ret0, _ := ret[0].(math.Int)
return ret0
}
// BondedTokens indicates an expected call of BondedTokens.
func (mr *MockValidatorMockRecorder) BondedTokens() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondedTokens", reflect.TypeOf((*MockValidator)(nil).BondedTokens))
}
// CmtConsPublicKey mocks base method.
func (m *MockValidator) CmtConsPublicKey() (crypto.PublicKey, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CmtConsPublicKey")
ret0, _ := ret[0].(crypto.PublicKey)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CmtConsPublicKey indicates an expected call of CmtConsPublicKey.
func (mr *MockValidatorMockRecorder) CmtConsPublicKey() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CmtConsPublicKey", reflect.TypeOf((*MockValidator)(nil).CmtConsPublicKey))
}
// MockValidatorStore is a mock of ValidatorStore interface.
type MockValidatorStore struct {
ctrl *gomock.Controller
@@ -90,27 +37,29 @@ func (m *MockValidatorStore) EXPECT() *MockValidatorStoreMockRecorder {
return m.recorder
}
// GetValidatorByConsAddr mocks base method.
func (m *MockValidatorStore) GetValidatorByConsAddr(arg0 types0.Context, arg1 types.Address) (baseapp.Validator, error) {
// BondedTokensAndPubKeyByConsAddr mocks base method.
func (m *MockValidatorStore) BondedTokensAndPubKeyByConsAddr(arg0 context.Context, arg1 types.ConsAddress) (math.Int, crypto.PublicKey, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetValidatorByConsAddr", arg0, arg1)
ret0, _ := ret[0].(baseapp.Validator)
ret1, _ := ret[1].(error)
return ret0, ret1
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
}
// GetValidatorByConsAddr indicates an expected call of GetValidatorByConsAddr.
func (mr *MockValidatorStoreMockRecorder) GetValidatorByConsAddr(arg0, arg1 interface{}) *gomock.Call {
// BondedTokensAndPubKeyByConsAddr indicates an expected call of BondedTokensAndPubKeyByConsAddr.
func (mr *MockValidatorStoreMockRecorder) BondedTokensAndPubKeyByConsAddr(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidatorByConsAddr", reflect.TypeOf((*MockValidatorStore)(nil).GetValidatorByConsAddr), arg0, arg1)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondedTokensAndPubKeyByConsAddr", reflect.TypeOf((*MockValidatorStore)(nil).BondedTokensAndPubKeyByConsAddr), arg0, arg1)
}
// TotalBondedTokens mocks base method.
func (m *MockValidatorStore) TotalBondedTokens(ctx types0.Context) math.Int {
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)
return ret0
ret1, _ := ret[1].(error)
return ret0, ret1
}
// TotalBondedTokens indicates an expected call of TotalBondedTokens.
@@ -180,7 +129,7 @@ func (m *MockProposalTxVerifier) EXPECT() *MockProposalTxVerifierMockRecorder {
}
// PrepareProposalVerifyTx mocks base method.
func (m *MockProposalTxVerifier) PrepareProposalVerifyTx(tx types0.Tx) ([]byte, error) {
func (m *MockProposalTxVerifier) PrepareProposalVerifyTx(tx types.Tx) ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PrepareProposalVerifyTx", tx)
ret0, _ := ret[0].([]byte)
@@ -195,10 +144,10 @@ func (mr *MockProposalTxVerifierMockRecorder) PrepareProposalVerifyTx(tx interfa
}
// ProcessProposalVerifyTx mocks base method.
func (m *MockProposalTxVerifier) ProcessProposalVerifyTx(txBz []byte) (types0.Tx, error) {
func (m *MockProposalTxVerifier) ProcessProposalVerifyTx(txBz []byte) (types.Tx, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ProcessProposalVerifyTx", txBz)
ret0, _ := ret[0].(types0.Tx)
ret0, _ := ret[0].(types.Tx)
ret1, _ := ret[1].(error)
return ret0, ret1
}