diff --git a/baseapp/abci.go b/baseapp/abci.go index 6151e1508557..123f23197039 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -194,12 +194,14 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg WithBlockGasMeter(gasMeter). WithHeaderHash(req.Hash). WithConsensusParams(app.GetConsensusParams(app.deliverState.ctx)). - WithVoteInfos(req.LastCommitInfo.GetVotes()) + WithVoteInfos(req.LastCommitInfo.GetVotes()). + WithCometInfo(cometInfo{Misbehavior: req.ByzantineValidators, ValidatorsHash: req.Header.ValidatorsHash, ProposerAddress: req.Header.ProposerAddress, LastCommit: req.LastCommitInfo}) if app.checkState != nil { app.checkState.ctx = app.checkState.ctx. WithBlockGasMeter(gasMeter). - WithHeaderHash(req.Hash) + WithHeaderHash(req.Hash). + WithCometInfo(cometInfo{Misbehavior: req.ByzantineValidators, ValidatorsHash: req.Header.ValidatorsHash, ProposerAddress: req.Header.ProposerAddress, LastCommit: req.LastCommitInfo}) } if app.beginBlocker != nil { @@ -210,8 +212,6 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg } res.Events = sdk.MarkEventsToIndex(res.Events, app.indexEvents) } - // set the signed validators for addition to context in deliverTx - app.voteInfos = req.LastCommitInfo.GetVotes() // call the streaming service hook with the BeginBlock messages for _, abciListener := range app.streamingManager.ABCIListeners { @@ -287,7 +287,8 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci. WithVoteInfos(toVoteInfo(req.LocalLastCommit.Votes)). // this is a set of votes that are not finalized yet, wait for commit WithBlockHeight(req.Height). WithBlockTime(req.Time). - WithProposer(req.ProposerAddress) + WithProposer(req.ProposerAddress). + WithCometInfo(prepareProposalInfo{req}) app.prepareProposalState.ctx = app.prepareProposalState.ctx. WithConsensusParams(app.GetConsensusParams(app.prepareProposalState.ctx)). @@ -345,7 +346,8 @@ func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) (resp abci. WithBlockHeight(req.Height). WithBlockTime(req.Time). WithHeaderHash(req.Hash). - WithProposer(req.ProposerAddress) + WithProposer(req.ProposerAddress). + WithCometInfo(cometInfo{ProposerAddress: req.ProposerAddress, ValidatorsHash: req.NextValidatorsHash, Misbehavior: req.Misbehavior, LastCommit: req.ProposedLastCommit}) app.processProposalState.ctx = app.processProposalState.ctx. WithConsensusParams(app.GetConsensusParams(app.processProposalState.ctx)). diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index aaa6146a52b9..0c90cdd17863 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -51,7 +51,7 @@ var _ abci.Application = (*BaseApp)(nil) type BaseApp struct { // initialized on creation logger log.Logger - name string // application name from abci.Info + name string // application name from abci.BlockInfo db dbm.DB // common DB backend cms storetypes.CommitMultiStore // Main (uncached) state qms storetypes.MultiStore // Optional alternative multistore for querying only. @@ -91,9 +91,6 @@ type BaseApp struct { // an inter-block write-through cache provided to the context during deliverState interBlockCache storetypes.MultiStorePersistentCache - // absent validators from begin block - voteInfos []abci.VoteInfo - // paramStore is used to query for ABCI consensus parameters from an // application parameter store. paramStore ParamStore @@ -573,8 +570,8 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) sdk.Context panic(fmt.Sprintf("state is nil for mode %v", mode)) } ctx := modeState.ctx. - WithTxBytes(txBytes). - WithVoteInfos(app.voteInfos) + WithTxBytes(txBytes) + // WithVoteInfos(app.voteInfos) // TODO: identify if this is needed ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx)) diff --git a/baseapp/info.go b/baseapp/info.go new file mode 100644 index 000000000000..a934696bcdf2 --- /dev/null +++ b/baseapp/info.go @@ -0,0 +1,197 @@ +package baseapp + +import ( + "time" + + abci "github.com/cometbft/cometbft/abci/types" + + "cosmossdk.io/core/comet" +) + +var _ comet.BlockInfo = (*cometInfo)(nil) + +// CometInfo defines the properties provided by comet to the application +type cometInfo struct { + Misbehavior []abci.Misbehavior + ValidatorsHash []byte + ProposerAddress []byte + LastCommit abci.CommitInfo +} + +func (r cometInfo) GetEvidence() comet.EvidenceList { + return evidenceWrapper{evidence: r.Misbehavior} +} + +func (r cometInfo) GetValidatorsHash() []byte { + return r.ValidatorsHash +} + +func (r cometInfo) GetProposerAddress() []byte { + return r.ProposerAddress +} + +func (r cometInfo) GetLastCommit() comet.CommitInfo { + return commitInfoWrapper{r.LastCommit} +} + +type evidenceWrapper struct { + evidence []abci.Misbehavior +} + +func (e evidenceWrapper) Len() int { + return len(e.evidence) +} + +func (e evidenceWrapper) Get(i int) comet.Evidence { + return misbehaviorWrapper{e.evidence[i]} +} + +// commitInfoWrapper is a wrapper around abci.CommitInfo that implements CommitInfo interface +type commitInfoWrapper struct { + abci.CommitInfo +} + +var _ comet.CommitInfo = (*commitInfoWrapper)(nil) + +func (c commitInfoWrapper) Round() int32 { + return c.CommitInfo.Round +} + +func (c commitInfoWrapper) Votes() comet.VoteInfos { + return abciVoteInfoWrapper{c.CommitInfo.Votes} +} + +// abciVoteInfoWrapper is a wrapper around abci.VoteInfo that implements VoteInfos interface +type abciVoteInfoWrapper struct { + votes []abci.VoteInfo +} + +var _ comet.VoteInfos = (*abciVoteInfoWrapper)(nil) + +func (e abciVoteInfoWrapper) Len() int { + return len(e.votes) +} + +func (e abciVoteInfoWrapper) Get(i int) comet.VoteInfo { + return voteInfoWrapper{e.votes[i]} +} + +// voteInfoWrapper is a wrapper around abci.VoteInfo that implements VoteInfo interface +type voteInfoWrapper struct { + abci.VoteInfo +} + +var _ comet.VoteInfo = (*voteInfoWrapper)(nil) + +func (v voteInfoWrapper) SignedLastBlock() bool { + return v.VoteInfo.SignedLastBlock +} + +func (v voteInfoWrapper) Validator() comet.Validator { + return validatorWrapper{v.VoteInfo.Validator} +} + +// validatorWrapper is a wrapper around abci.Validator that implements Validator interface +type validatorWrapper struct { + abci.Validator +} + +var _ comet.Validator = (*validatorWrapper)(nil) + +func (v validatorWrapper) Address() []byte { + return v.Validator.Address +} + +func (v validatorWrapper) Power() int64 { + return v.Validator.Power +} + +type misbehaviorWrapper struct { + abci.Misbehavior +} + +func (m misbehaviorWrapper) Type() comet.MisbehaviorType { + return comet.MisbehaviorType(m.Misbehavior.Type) +} + +func (m misbehaviorWrapper) Height() int64 { + return m.Misbehavior.Height +} + +func (m misbehaviorWrapper) Validator() comet.Validator { + return validatorWrapper{m.Misbehavior.Validator} +} + +func (m misbehaviorWrapper) Time() time.Time { + return m.Misbehavior.Time +} + +func (m misbehaviorWrapper) TotalVotingPower() int64 { + return m.Misbehavior.TotalVotingPower +} + +type prepareProposalInfo struct { + abci.RequestPrepareProposal +} + +var _ comet.BlockInfo = (*prepareProposalInfo)(nil) + +func (r prepareProposalInfo) GetEvidence() comet.EvidenceList { + return evidenceWrapper{r.Misbehavior} +} + +func (r prepareProposalInfo) GetValidatorsHash() []byte { + return r.NextValidatorsHash +} + +func (r prepareProposalInfo) GetProposerAddress() []byte { + return r.RequestPrepareProposal.ProposerAddress +} + +func (r prepareProposalInfo) GetLastCommit() comet.CommitInfo { + return extendedCommitInfoWrapper{r.RequestPrepareProposal.LocalLastCommit} +} + +var _ comet.BlockInfo = (*prepareProposalInfo)(nil) + +type extendedCommitInfoWrapper struct { + abci.ExtendedCommitInfo +} + +var _ comet.CommitInfo = (*extendedCommitInfoWrapper)(nil) + +func (e extendedCommitInfoWrapper) Round() int32 { + return e.ExtendedCommitInfo.Round +} + +func (e extendedCommitInfoWrapper) Votes() comet.VoteInfos { + return extendedVoteInfoWrapperList{e.ExtendedCommitInfo.Votes} +} + +type extendedVoteInfoWrapperList struct { + votes []abci.ExtendedVoteInfo +} + +var _ comet.VoteInfos = (*extendedVoteInfoWrapperList)(nil) + +func (e extendedVoteInfoWrapperList) Len() int { + return len(e.votes) +} + +func (e extendedVoteInfoWrapperList) Get(i int) comet.VoteInfo { + return extendedVoteInfoWrapper{e.votes[i]} +} + +type extendedVoteInfoWrapper struct { + abci.ExtendedVoteInfo +} + +var _ comet.VoteInfo = (*extendedVoteInfoWrapper)(nil) + +func (e extendedVoteInfoWrapper) SignedLastBlock() bool { + return e.ExtendedVoteInfo.SignedLastBlock +} + +func (e extendedVoteInfoWrapper) Validator() comet.Validator { + return validatorWrapper{e.ExtendedVoteInfo.Validator} +} diff --git a/core/comet/doc.go b/core/comet/doc.go new file mode 100644 index 000000000000..c6553d097b43 --- /dev/null +++ b/core/comet/doc.go @@ -0,0 +1,7 @@ +/* +Package comet defines the Comet Service interface and BlockInfo types which applications +should use in order to get access to the current block's evidence, validators hash, proposer address. + +This information is specific to Comet +*/ +package comet diff --git a/core/comet/service.go b/core/comet/service.go new file mode 100644 index 000000000000..ab1e10c7afc1 --- /dev/null +++ b/core/comet/service.go @@ -0,0 +1,68 @@ +package comet + +import ( + "context" + "time" +) + +// BlockInfoService is an interface that can be used to get information specific to Comet +type BlockInfoService interface { + GetCometBlockInfo(context.Context) BlockInfo +} + +// BlockInfo is the information comet provides apps in ABCI +type BlockInfo interface { + GetEvidence() EvidenceList // Evidence misbehavior of the block + // ValidatorsHash returns the hash of the validators + // For Comet, it is the hash of the next validator set + GetValidatorsHash() []byte + GetProposerAddress() []byte // ProposerAddress returns the address of the block proposer + GetLastCommit() CommitInfo // DecidedLastCommit returns the last commit info +} + +// MisbehaviorType is the type of misbehavior for a validator +type MisbehaviorType int32 + +const ( + Unknown MisbehaviorType = 0 + DuplicateVote MisbehaviorType = 1 + LightClientAttack MisbehaviorType = 2 +) + +// Validator is the validator information of ABCI +type Validator interface { + Address() []byte + Power() int64 +} + +type EvidenceList interface { + Len() int + Get(int) Evidence +} + +// Evidence is the misbehavior information of ABCI +type Evidence interface { + Type() MisbehaviorType + Validator() Validator + Height() int64 + Time() time.Time + TotalVotingPower() int64 +} + +// CommitInfo is the commit information of ABCI +type CommitInfo interface { + Round() int32 + Votes() VoteInfos +} + +// VoteInfos is an interface to get specific votes in a efficient way +type VoteInfos interface { + Len() int + Get(int) VoteInfo +} + +// VoteInfo is the vote information of ABCI +type VoteInfo interface { + Validator() Validator + SignedLastBlock() bool +} diff --git a/core/header/doc.go b/core/header/doc.go new file mode 100644 index 000000000000..4ba3bcdbe818 --- /dev/null +++ b/core/header/doc.go @@ -0,0 +1,7 @@ +/* +Package header defines a generalized Header type that all consensus & networking layers must provide. + +If modules need access to the current block header information, like height, hash, time, or chain ID +they should use the Header Service interface. +*/ +package header diff --git a/core/header/service.go b/core/header/service.go new file mode 100644 index 000000000000..982b9a049c15 --- /dev/null +++ b/core/header/service.go @@ -0,0 +1,19 @@ +package header + +import ( + "context" + "time" +) + +// Service defines the interface in which you can get header information +type Service interface { + GetHeaderInfo(context.Context) Info +} + +// Info defines a struct that contains information about the header +type Info struct { + Height int64 // Height returns the height of the block + Hash []byte // Hash returns the hash of the block header + Time time.Time // Time returns the time of the block + ChainID string // ChainId returns the chain ID of the block +} diff --git a/docs/architecture/adr-063-core-module-api.md b/docs/architecture/adr-063-core-module-api.md index c065ce92ee75..e3dcaa2b1237 100644 --- a/docs/architecture/adr-063-core-module-api.md +++ b/docs/architecture/adr-063-core-module-api.md @@ -312,16 +312,46 @@ block headers, the runtime module for a specific version of Comet could provide type ValidatorUpdateService interface { SetValidatorUpdates(context.Context, []abci.ValidatorUpdate) } +``` + +Header Service defines a way to get header information about a block. This information is generalized for all implementations: + +```go + +type Service interface { + GetHeaderInfo(context.Context) Info +} + +type Info struct { + Height int64 // Height returns the height of the block + Hash []byte // Hash returns the hash of the block header + Time time.Time // Time returns the time of the block + ChainID string // ChainId returns the chain ID of the block +} +``` + +Comet Service provides a way to get comet specific information: -type BlockInfoService interface { - GetHeight() int64 // GetHeight returns the height of the block - Misbehavior() []abci.Misbehavior // Misbehavior returns the misbehavior of the block - GetHeaderHash() []byte // GetHeaderHash returns the hash of the block header - // GetValidatorsHash returns the hash of the validators +```go +type Service interface { + GetCometInfo(context.Context) Info +} + +type CometInfo struct { + Evidence []abci.Misbehavior // Misbehavior returns the misbehavior of the block + // ValidatorsHash returns the hash of the validators // For Comet, it is the hash of the next validators - GetValidatorsHash() []byte - GetProposerAddress() []byte // GetProposerAddress returns the address of the block proposer - GetDecidedLastCommit() abci.CommitInfo // GetDecidedLastCommit returns the last commit info + ValidatorsHash []byte + ProposerAddress []byte // ProposerAddress returns the address of the block proposer + DecidedLastCommit abci.CommitInfo // DecidedLastCommit returns the last commit info +} +``` + +If a user would like to provide a module other information they would need to implement another service like: + +```go +type RollKit Interface { + ... } ``` diff --git a/runtime/module.go b/runtime/module.go index 501bd93f4d9f..055eef22ebc0 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -4,20 +4,20 @@ import ( "fmt" "os" - "cosmossdk.io/core/genesis" - "cosmossdk.io/core/store" - "cosmossdk.io/log" - "github.com/cosmos/gogoproto/proto" - "google.golang.org/protobuf/reflect/protodesc" - "google.golang.org/protobuf/reflect/protoregistry" - runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/comet" "cosmossdk.io/core/event" + "cosmossdk.io/core/genesis" + "cosmossdk.io/core/header" + "cosmossdk.io/core/store" "cosmossdk.io/depinject" - + "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" + "github.com/cosmos/gogoproto/proto" + "google.golang.org/protobuf/reflect/protodesc" + "google.golang.org/protobuf/reflect/protoregistry" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" @@ -66,6 +66,8 @@ func init() { ProvideMemoryStoreService, ProvideTransientStoreService, ProvideEventService, + ProvideHeaderInfoService, + ProvideCometInfoService, ProvideBasicManager, ), appmodule.Invoke(SetupAppBuilder), @@ -233,6 +235,14 @@ func ProvideEventService() event.Service { return EventService{} } +func ProvideCometInfoService() comet.BlockInfoService { + return cometInfoService{} +} + +func ProvideHeaderInfoService(app *AppBuilder) header.Service { + return headerInfoService{} +} + func ProvideBasicManager(app *AppBuilder) module.BasicManager { return app.app.basicManager } diff --git a/runtime/services.go b/runtime/services.go index 34f86e612d08..a16a3a6b5a57 100644 --- a/runtime/services.go +++ b/runtime/services.go @@ -1,12 +1,16 @@ package runtime import ( + "context" + appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - abci "github.com/cometbft/cometbft/abci/types" + "cosmossdk.io/core/comet" + "cosmossdk.io/core/header" "github.com/cosmos/cosmos-sdk/runtime/services" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" ) @@ -23,18 +27,18 @@ func (a *App) registerRuntimeServices(cfg module.Configurator) error { return nil } -// ====================================================== -// BlockInfoService -// ====================================================== - -// BlockInfoService is the service that runtime will provide to modules which need Comet block information. -type BlockInfoService interface { - GetHeight() int64 // GetHeight returns the height of the block - Misbehavior() []abci.Misbehavior // Misbehavior returns the misbehavior of the block - GetHeaderHash() []byte // GetHeaderHash returns the hash of the block header - // GetValidatorsHash returns the hash of the validators - // For Comet, it is the hash of the next validators - GetValidatorsHash() []byte - GetProposerAddress() []byte // GetProposerAddress returns the address of the block proposer - GetDecidedLastCommit() abci.CommitInfo // GetDecidedLastCommit returns the last commit info +var _ comet.BlockInfoService = cometInfoService{} + +type cometInfoService struct{} + +func (cometInfoService) GetCometBlockInfo(ctx context.Context) comet.BlockInfo { + return sdk.UnwrapSDKContext(ctx).CometInfo() +} + +var _ header.Service = headerInfoService{} + +type headerInfoService struct{} + +func (headerInfoService) GetHeaderInfo(ctx context.Context) header.Info { + return sdk.UnwrapSDKContext(ctx).HeaderInfo() } diff --git a/simapp/app.go b/simapp/app.go index aee3169b0565..29da63e5dcab 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -343,7 +343,7 @@ func NewSimApp( // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( - appCodec, keys[evidencetypes.StoreKey], app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper.GetAddressCodec(), + appCodec, keys[evidencetypes.StoreKey], app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper.GetAddressCodec(), runtime.ProvideCometInfoService(), ) // If evidence needs to be handled for the app, set routes in router here and seal app.EvidenceKeeper = *evidenceKeeper diff --git a/simapp/go.mod b/simapp/go.mod index c792a212355e..5efe530ca9fa 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -198,7 +198,6 @@ replace ( // TODO tag all extracted modules after SDK refactor cosmossdk.io/api => ../api cosmossdk.io/client/v2 => ../client/v2 - cosmossdk.io/core => ../core cosmossdk.io/store => ../store cosmossdk.io/tools/confix => ../tools/confix cosmossdk.io/tools/rosetta => ../tools/rosetta @@ -212,6 +211,7 @@ replace ( // Below are the long-lived replace of the SimApp replace ( + cosmossdk.io/core => ../core // use cosmos fork of keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 // Simapp always use the latest version of the cosmos-sdk diff --git a/tests/go.mod b/tests/go.mod index 9ad3d04cde83..0454ff6ff35b 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( cosmossdk.io/api v0.4.1 + cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/errors v1.0.0-beta.7 cosmossdk.io/log v1.1.0 @@ -38,7 +39,6 @@ require ( cloud.google.com/go/storage v1.30.0 // indirect cosmossdk.io/client/v2 v2.0.0-20230309163709-87da587416ba // indirect cosmossdk.io/collections v0.1.0 // indirect - cosmossdk.io/core v0.6.2-0.20230323161322-ccd8d40119e4 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect @@ -193,7 +193,6 @@ require ( replace ( // TODO tag all extracted modules after SDK refactor cosmossdk.io/api => ../api - cosmossdk.io/core => ../core cosmossdk.io/store => ../store cosmossdk.io/x/evidence => ../x/evidence cosmossdk.io/x/feegrant => ../x/feegrant @@ -206,6 +205,7 @@ replace cosmossdk.io/x/tx => ../x/tx // Below are the long-lived replace for tests. replace ( + cosmossdk.io/core => ../core // We always want to test against the latest version of the simapp. cosmossdk.io/simapp => ../simapp github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 diff --git a/tests/integration/distribution/keeper/grpc_query_test.go b/tests/integration/distribution/keeper/grpc_query_test.go index 38d781806344..acfa51ecfc8d 100644 --- a/tests/integration/distribution/keeper/grpc_query_test.go +++ b/tests/integration/distribution/keeper/grpc_query_test.go @@ -171,7 +171,7 @@ func TestGRPCValidatorCommission(t *testing.T) { tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) tstaking.CreateValidator(f.valAddr, valConsPk0, sdk.NewInt(initialStake), true) - commission := sdk.DecCoins{{Denom: "token1", Amount: math.LegacyNewDec(4)}, {Denom: "token2", Amount: math.LegacyNewDec(2)}} + commission := sdk.DecCoins{sdk.DecCoin{Denom: "token1", Amount: math.LegacyNewDec(4)}, {Denom: "token2", Amount: math.LegacyNewDec(2)}} f.distrKeeper.SetValidatorAccumulatedCommission(f.sdkCtx, f.valAddr, types.ValidatorAccumulatedCommission{Commission: commission}) testCases := []struct { @@ -521,7 +521,7 @@ func TestGRPCDelegationRewards(t *testing.T) { f.distrKeeper.SetValidatorOutstandingRewards(f.sdkCtx, f.valAddr, types.ValidatorOutstandingRewards{Rewards: decCoins}) expRes := &types.QueryDelegationRewardsResponse{ - Rewards: sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initialStake / 10)}}, + Rewards: sdk.DecCoins{sdk.DecCoin{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initialStake / 10)}}, } // test command delegation rewards grpc diff --git a/tests/integration/evidence/keeper/infraction_test.go b/tests/integration/evidence/keeper/infraction_test.go index 3603ab299585..1d889cc2c795 100644 --- a/tests/integration/evidence/keeper/infraction_test.go +++ b/tests/integration/evidence/keeper/infraction_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "cosmossdk.io/core/comet" "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/x/evidence/exported" @@ -117,16 +118,19 @@ func TestHandleDoubleSign(t *testing.T) { // double sign less than max age oldTokens := f.stakingKeeper.Validator(ctx, operatorAddr).GetTokens() - evidence := abci.RequestBeginBlock{ + + nci := NewCometInfo(abci.RequestBeginBlock{ ByzantineValidators: []abci.Misbehavior{{ Validator: abci.Validator{Address: val.Address(), Power: power}, Type: abci.MisbehaviorType_DUPLICATE_VOTE, Time: time.Unix(0, 0), Height: 0, }}, - } + }) + + ctx = ctx.WithCometInfo(nci) - f.evidenceKeeper.BeginBlocker(ctx, evidence) + f.evidenceKeeper.BeginBlocker(ctx) // should be jailed and tombstoned assert.Assert(t, f.stakingKeeper.Validator(ctx, operatorAddr).IsJailed()) @@ -137,7 +141,7 @@ func TestHandleDoubleSign(t *testing.T) { assert.Assert(t, newTokens.LT(oldTokens)) // submit duplicate evidence - f.evidenceKeeper.BeginBlocker(ctx, evidence) + f.evidenceKeeper.BeginBlocker(ctx) // tokens should be the same (capped slash) assert.Assert(t, f.stakingKeeper.Validator(ctx, operatorAddr).GetTokens().Equal(newTokens)) @@ -184,22 +188,23 @@ func TestHandleDoubleSign_TooOld(t *testing.T) { ) assert.DeepEqual(t, amt, f.stakingKeeper.Validator(ctx, operatorAddr).GetBondedTokens()) - evidence := abci.RequestBeginBlock{ + nci := NewCometInfo(abci.RequestBeginBlock{ ByzantineValidators: []abci.Misbehavior{{ Validator: abci.Validator{Address: val.Address(), Power: power}, Type: abci.MisbehaviorType_DUPLICATE_VOTE, Time: ctx.BlockTime(), Height: 0, }}, - } + }) cp := f.app.BaseApp.GetConsensusParams(ctx) + ctx = ctx.WithCometInfo(nci) ctx = ctx.WithConsensusParams(cp) ctx = ctx.WithBlockTime(ctx.BlockTime().Add(cp.Evidence.MaxAgeDuration + 1)) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + cp.Evidence.MaxAgeNumBlocks + 1) - f.evidenceKeeper.BeginBlocker(ctx, evidence) + f.evidenceKeeper.BeginBlocker(ctx) assert.Assert(t, f.stakingKeeper.Validator(ctx, operatorAddr).IsJailed() == false) assert.Assert(t, f.slashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(val.Address())) == false) @@ -244,3 +249,80 @@ func testEquivocationHandler(_ interface{}) types.Handler { return nil } } + +type CometService struct { + Evidence []abci.Misbehavior +} + +func NewCometInfo(bg abci.RequestBeginBlock) comet.BlockInfo { + return CometService{ + Evidence: bg.ByzantineValidators, + } +} + +func (r CometService) GetEvidence() comet.EvidenceList { + return evidenceWrapper{evidence: r.Evidence} +} + +func (CometService) GetValidatorsHash() []byte { + return []byte{} +} + +func (CometService) GetProposerAddress() []byte { + return []byte{} +} + +func (CometService) GetLastCommit() comet.CommitInfo { + return nil +} + +type evidenceWrapper struct { + evidence []abci.Misbehavior +} + +func (e evidenceWrapper) Len() int { + return len(e.evidence) +} + +func (e evidenceWrapper) Get(i int) comet.Evidence { + return misbehaviorWrapper{e.evidence[i]} +} + +type misbehaviorWrapper struct { + abci.Misbehavior +} + +func (m misbehaviorWrapper) Type() comet.MisbehaviorType { + return comet.MisbehaviorType(m.Misbehavior.Type) +} + +func (m misbehaviorWrapper) Height() int64 { + return m.Misbehavior.Height +} + +func (m misbehaviorWrapper) Validator() comet.Validator { + return validatorWrapper{m.Misbehavior.Validator} +} + +func (m misbehaviorWrapper) Time() time.Time { + return m.Misbehavior.Time +} + +func (m misbehaviorWrapper) TotalVotingPower() int64 { + return m.Misbehavior.TotalVotingPower +} + +// validatorWrapper is a wrapper around abci.Validator that implements Validator interface +type validatorWrapper struct { + abci.Validator +} + +var _ comet.Validator = (*validatorWrapper)(nil) + +func (v validatorWrapper) Address() []byte { + return v.Validator.Address +} + +func (v validatorWrapper) Power() int64 { + return v.Validator.Power +} diff --git a/types/context.go b/types/context.go index da17b1881fca..b7a6a6a15d7b 100644 --- a/types/context.go +++ b/types/context.go @@ -11,6 +11,9 @@ import ( "cosmossdk.io/store/gaskv" storetypes "cosmossdk.io/store/types" + + "cosmossdk.io/core/comet" + "cosmossdk.io/core/header" ) /* @@ -22,10 +25,13 @@ but please do not over-use it. We try to keep all data structured and standard additions here would be better just to add to the Context struct */ type Context struct { - baseCtx context.Context - ms storetypes.MultiStore - header cmtproto.Header - headerHash []byte + baseCtx context.Context + ms storetypes.MultiStore + // Deprecated: Use HeaderService for height, time, and chainID and CometService for the rest + header cmtproto.Header + // Deprecated: Use HeaderService for hash + headerHash []byte + // Deprecated: Use HeaderService for chainID and CometService for the rest chainID string txBytes []byte logger log.Logger @@ -41,6 +47,8 @@ type Context struct { kvGasConfig storetypes.GasConfig transientKVGasConfig storetypes.GasConfig streamingManager storetypes.StreamingManager + cometInfo comet.BlockInfo + headerInfo header.Info } // Proposed rename, not done to avoid API breakage @@ -65,6 +73,8 @@ func (c Context) Priority() int64 { return c.prior func (c Context) KVGasConfig() storetypes.GasConfig { return c.kvGasConfig } func (c Context) TransientKVGasConfig() storetypes.GasConfig { return c.transientKVGasConfig } func (c Context) StreamingManager() storetypes.StreamingManager { return c.streamingManager } +func (c Context) CometInfo() comet.BlockInfo { return c.cometInfo } +func (c Context) HeaderInfo() header.Info { return c.headerInfo } // clone the header before returning func (c Context) BlockHeader() cmtproto.Header { @@ -262,6 +272,18 @@ func (c Context) WithStreamingManager(sm storetypes.StreamingManager) Context { return c } +// WithCometInfo returns a Context with an updated comet info +func (c Context) WithCometInfo(cometInfo comet.BlockInfo) Context { + c.cometInfo = cometInfo + return c +} + +// WithHeaderInfo returns a Context with an updated header info +func (c Context) WithHeaderInfo(headerInfo header.Info) Context { + c.headerInfo = headerInfo + return c +} + // TODO: remove??? func (c Context) IsZero() bool { return c.ms == nil diff --git a/x/evidence/go.mod b/x/evidence/go.mod index f1c36066892b..b624234bd3a6 100644 --- a/x/evidence/go.mod +++ b/x/evidence/go.mod @@ -26,7 +26,7 @@ require ( require ( cosmossdk.io/collections v0.1.0 // indirect - cosmossdk.io/x/tx v0.5.1-0.20230407182919-057d2e09bd63 // indirect + cosmossdk.io/x/tx v0.6.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect @@ -45,12 +45,12 @@ require ( github.com/cockroachdb/pebble v0.0.0-20230412222916-60cfeb46143b // indirect github.com/cockroachdb/redact v1.1.3 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect - github.com/confio/ics23/go v0.9.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.0-rc.1 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect - github.com/cosmos/iavl v0.21.0-beta.1 // indirect + github.com/cosmos/iavl v0.21.0 // indirect + github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.0 // indirect github.com/creachadair/taskgroup v0.4.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect @@ -92,6 +92,7 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/huandu/skiplist v1.2.0 // indirect + github.com/iancoleman/strcase v0.2.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect @@ -157,3 +158,10 @@ require ( // Fix upstream GHSA-h395-qcrw-5vmq vulnerability. // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 replace github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.8.1 + +replace ( + cosmossdk.io/core => ../../core + cosmossdk.io/store => ../../store + cosmossdk.io/x/tx => ../tx + github.com/cosmos/cosmos-sdk => ../../ +) diff --git a/x/evidence/go.sum b/x/evidence/go.sum index 83b496bbd110..4c9e42ba410c 100644 --- a/x/evidence/go.sum +++ b/x/evidence/go.sum @@ -39,8 +39,6 @@ cosmossdk.io/api v0.4.1 h1:0ikaYM6GyxTYYcfBiyR8YnLCfhNnhKpEFnaSepCTmqg= cosmossdk.io/api v0.4.1/go.mod h1:jR7k5ok90LxW2lFUXvd8Vpo/dr4PpiyVegxdm7b1ZdE= cosmossdk.io/collections v0.1.0 h1:nzJGeiq32KnZroSrhB6rPifw4I85Cgmzw/YAmr4luv8= cosmossdk.io/collections v0.1.0/go.mod h1:xbauc0YsbUF8qKMVeBZl0pFCunxBIhKN/WlxpZ3lBuo= -cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s= -cosmossdk.io/core v0.6.1/go.mod h1:g3MMBCBXtxbDWBURDVnJE7XML4BG5qENhs0gzkcpuFA= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= @@ -49,10 +47,6 @@ cosmossdk.io/log v1.1.0 h1:v0ogPHYeTzPcBTcPR1A3j1hkei4pZama8kz8LKlCMv0= cosmossdk.io/log v1.1.0/go.mod h1:6zjroETlcDs+mm62gd8Ig7mZ+N+fVOZS91V17H+M4N4= cosmossdk.io/math v1.0.0 h1:ro9w7eKx23om2tZz/VM2Pf+z2WAbGX1yDQQOJ6iGeJw= cosmossdk.io/math v1.0.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= -cosmossdk.io/store v0.1.0-alpha.1.0.20230328185921-37ba88872dbc h1:9piuA+NYmhe+SyMPtMoboLw/djgDbrI3dD5TG020Tnk= -cosmossdk.io/store v0.1.0-alpha.1.0.20230328185921-37ba88872dbc/go.mod h1:UFF5rmjN7WYVfxo6ArdY/l1+yyWMURBWOmSJypGqFHQ= -cosmossdk.io/x/tx v0.5.1-0.20230407182919-057d2e09bd63 h1:zHqj2VwZ/MStFmR7SUe/7gErOFhL9v2rkjmWPB/st34= -cosmossdk.io/x/tx v0.5.1-0.20230407182919-057d2e09bd63/go.mod h1:Oh3Kh+IPOfMEILNxVd2e8SLqRrIjYHpdGBfDg4ghU/k= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -168,8 +162,6 @@ github.com/cometbft/cometbft v0.37.1 h1:KLxkQTK2hICXYq21U2hn1W5hOVYUdQgDQ1uB+90x github.com/cometbft/cometbft v0.37.1/go.mod h1:Y2MMMN//O5K4YKd8ze4r9jmk4Y7h0ajqILXbH5JQFVs= github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= -github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= -github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= @@ -183,8 +175,6 @@ github.com/cosmos/cosmos-db v1.0.0-rc.1 h1:SjnT8B6WKMW9WEIX32qMhnEEKcI7ZP0+G1Sa9 github.com/cosmos/cosmos-db v1.0.0-rc.1/go.mod h1:Dnmk3flSf5lkwCqvvjNpoxjpXzhxnCAFzKHlbaForso= github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o= github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230419074131-aa683247d515 h1:KMbJ5nAA0Xk79z0D1oL3kiw9lBYiqlV3ZqUxXVbbgBY= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230419074131-aa683247d515/go.mod h1:BPvKPN63ettXrpz67uM1rHEqX/UVVkAfceFCPyp217E= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -193,8 +183,10 @@ github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.4.8 h1:BrHKc6WFZt8+jRV71vKSQE+JrfF+JAnzrKo2VP7wIZ4= github.com/cosmos/gogoproto v1.4.8/go.mod h1:hnb0DIEWTv+wdNzNcqus5xCQXq5+CXauq1FJuurRfVY= -github.com/cosmos/iavl v0.21.0-beta.1 h1:fBQeBc8HLZ14plJNcmGfaOXSSMLVEHvEQXiTXSD76m0= -github.com/cosmos/iavl v0.21.0-beta.1/go.mod h1:25YJYzilTErJ2mKfNB3xyWL9IsCwEQdNzdIutg2mh3U= +github.com/cosmos/iavl v0.21.0 h1:E39qwHl45PaQUe/mRA8lY4kOqaunOorVQufpv5JPgXk= +github.com/cosmos/iavl v0.21.0/go.mod h1:ejCWRfxvfmQTcligmeRcoQeB8VgHGxkVlIqKSKG7YaI= +github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= +github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/ledger-cosmos-go v0.13.0 h1:ex0CvCxToSR7j5WjrghPu2Bu9sSXKikjnVvUryNnx4s= github.com/cosmos/ledger-cosmos-go v0.13.0/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -489,6 +481,8 @@ github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= diff --git a/x/evidence/keeper/abci.go b/x/evidence/keeper/abci.go index cfa9fffa3054..3fea7d78ad9a 100644 --- a/x/evidence/keeper/abci.go +++ b/x/evidence/keeper/abci.go @@ -1,11 +1,12 @@ package keeper import ( + "context" "fmt" "time" + "cosmossdk.io/core/comet" "cosmossdk.io/x/evidence/types" - abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,19 +14,22 @@ import ( // BeginBlocker iterates through and handles any newly discovered evidence of // misbehavior submitted by CometBFT. Currently, only equivocation is handled. -func (k Keeper) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) { +func (k Keeper) BeginBlocker(goCtx context.Context) { defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) - for _, tmEvidence := range req.ByzantineValidators { - switch tmEvidence.Type { + bi := k.cometInfo.GetCometBlockInfo(goCtx).GetEvidence() + + ctx := sdk.UnwrapSDKContext(goCtx) + for i := 0; i < bi.Len(); i++ { + switch bi.Get(i).Type() { // It's still ongoing discussion how should we treat and slash attacks with // premeditation. So for now we agree to treat them in the same way. - case abci.MisbehaviorType_DUPLICATE_VOTE, abci.MisbehaviorType_LIGHT_CLIENT_ATTACK: - evidence := types.FromABCIEvidence(tmEvidence) + case comet.LightClientAttack, comet.DuplicateVote: + evidence := types.FromABCIEvidence(bi.Get(i)) k.handleEquivocationEvidence(ctx, evidence) default: - k.Logger(ctx).Error(fmt.Sprintf("ignored unknown evidence type: %s", tmEvidence.Type)) + k.Logger(ctx).Error(fmt.Sprintf("ignored unknown evidence type: %x", bi.Get(i).Type())) } } } diff --git a/x/evidence/keeper/keeper.go b/x/evidence/keeper/keeper.go index bd992e7ff56f..389c6897e845 100644 --- a/x/evidence/keeper/keeper.go +++ b/x/evidence/keeper/keeper.go @@ -10,6 +10,7 @@ import ( "cosmossdk.io/x/evidence/exported" "cosmossdk.io/x/evidence/types" + "cosmossdk.io/core/comet" "cosmossdk.io/errors" "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" @@ -28,12 +29,14 @@ type Keeper struct { stakingKeeper types.StakingKeeper slashingKeeper types.SlashingKeeper addressCodec address.Codec + + cometInfo comet.BlockInfoService } // NewKeeper creates a new Keeper object. func NewKeeper( cdc codec.BinaryCodec, storeKey storetypes.StoreKey, stakingKeeper types.StakingKeeper, - slashingKeeper types.SlashingKeeper, ac address.Codec, + slashingKeeper types.SlashingKeeper, ac address.Codec, ci comet.BlockInfoService, ) *Keeper { return &Keeper{ cdc: cdc, @@ -41,6 +44,7 @@ func NewKeeper( stakingKeeper: stakingKeeper, slashingKeeper: slashingKeeper, addressCodec: ac, + cometInfo: ci, } } diff --git a/x/evidence/keeper/keeper_test.go b/x/evidence/keeper/keeper_test.go index b155d659deee..fc88344051ac 100644 --- a/x/evidence/keeper/keeper_test.go +++ b/x/evidence/keeper/keeper_test.go @@ -78,6 +78,7 @@ type KeeperTestSuite struct { accountKeeper *evidencetestutil.MockAccountKeeper slashingKeeper *evidencetestutil.MockSlashingKeeper stakingKeeper *evidencetestutil.MockStakingKeeper + blockInfo *evidencetestutil.MockCometinfo queryClient types.QueryClient encCfg moduletestutil.TestEncodingConfig msgServer types.MsgServer @@ -96,6 +97,7 @@ func (suite *KeeperTestSuite) SetupTest() { slashingKeeper := evidencetestutil.NewMockSlashingKeeper(ctrl) accountKeeper := evidencetestutil.NewMockAccountKeeper(ctrl) bankKeeper := evidencetestutil.NewMockBankKeeper(ctrl) + suite.blockInfo = &evidencetestutil.MockCometinfo{} evidenceKeeper := keeper.NewKeeper( encCfg.Codec, @@ -103,6 +105,7 @@ func (suite *KeeperTestSuite) SetupTest() { stakingKeeper, slashingKeeper, address.NewBech32Codec("cosmos"), + &evidencetestutil.MockCometinfo{}, ) suite.stakingKeeper = stakingKeeper diff --git a/x/evidence/keeper/msg_server_test.go b/x/evidence/keeper/msg_server_test.go index 055d1b863976..cebc8c1a3817 100644 --- a/x/evidence/keeper/msg_server_test.go +++ b/x/evidence/keeper/msg_server_test.go @@ -42,7 +42,7 @@ func (s *KeeperTestSuite) TestSubmitEvidence() { name: "invalid address", req: &types.MsgSubmitEvidence{}, expErr: true, - expErrMsg: "invalid submitter address: decoding bech32 failed: invalid bech32 string length 0", + expErrMsg: "invalid submitter address: empty address string is not allowed", }, { name: "missing evidence", diff --git a/x/evidence/module.go b/x/evidence/module.go index a0c4c6fbbf59..9e76fa14fef8 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -13,6 +13,7 @@ import ( modulev1 "cosmossdk.io/api/cosmos/evidence/module/v1" "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/comet" "cosmossdk.io/depinject" store "cosmossdk.io/store/types" @@ -31,7 +32,6 @@ import ( ) var ( - _ module.BeginBlockAppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} _ module.AppModuleSimulation = AppModule{} ) @@ -125,8 +125,9 @@ func NewAppModule(keeper keeper.Keeper) AppModule { } var ( - _ appmodule.AppModule = AppModule{} - _ appmodule.HasServices = AppModule{} + _ appmodule.AppModule = AppModule{} + _ appmodule.HasServices = AppModule{} + _ appmodule.HasBeginBlocker = AppModule{} ) // IsOnePerModuleType implements the depinject.OnePerModuleType interface. @@ -169,8 +170,10 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw func (AppModule) ConsensusVersion() uint64 { return 1 } // BeginBlock executes all ABCI BeginBlock logic respective to the evidence module. -func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { - am.keeper.BeginBlocker(ctx, req) +func (am AppModule) BeginBlock(ctx context.Context) error { + am.keeper.BeginBlocker(ctx) + + return nil } // AppModuleSimulation functions @@ -209,6 +212,8 @@ type ModuleInputs struct { StakingKeeper types.StakingKeeper SlashingKeeper types.SlashingKeeper AddressCodec address.Codec + + BlockInfoService comet.BlockInfoService } type ModuleOutputs struct { @@ -219,7 +224,7 @@ type ModuleOutputs struct { } func ProvideModule(in ModuleInputs) ModuleOutputs { - k := keeper.NewKeeper(in.Cdc, in.Key, in.StakingKeeper, in.SlashingKeeper, in.AddressCodec) + k := keeper.NewKeeper(in.Cdc, in.Key, in.StakingKeeper, in.SlashingKeeper, in.AddressCodec, in.BlockInfoService) m := NewAppModule(*k) return ModuleOutputs{EvidenceKeeper: *k, Module: m} diff --git a/x/evidence/testutil/expected_keepers_mocks.go b/x/evidence/testutil/expected_keepers_mocks.go index e6b93cdf7f43..98b450424047 100644 --- a/x/evidence/testutil/expected_keepers_mocks.go +++ b/x/evidence/testutil/expected_keepers_mocks.go @@ -9,6 +9,7 @@ import ( reflect "reflect" time "time" + comet "cosmossdk.io/core/comet" math "cosmossdk.io/math" types "github.com/cosmos/cosmos-sdk/crypto/types" types0 "github.com/cosmos/cosmos-sdk/types" @@ -306,3 +307,40 @@ func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderMo mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToAccount", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) } + +// MockCometinfo is a mock of Cometinfo interface. +type MockCometinfo struct { + ctrl *gomock.Controller + recorder *MockCometinfoMockRecorder +} + +// MockCometinfoMockRecorder is the mock recorder for MockCometinfo. +type MockCometinfoMockRecorder struct { + mock *MockCometinfo +} + +// NewMockCometinfo creates a new mock instance. +func NewMockCometinfo(ctrl *gomock.Controller) *MockCometinfo { + mock := &MockCometinfo{ctrl: ctrl} + mock.recorder = &MockCometinfoMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCometinfo) EXPECT() *MockCometinfoMockRecorder { + return m.recorder +} + +// GetCometBlockInfo mocks base method. +func (m *MockCometinfo) GetCometBlockInfo(arg0 context.Context) comet.BlockInfo { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCometBlockInfo", arg0) + ret0, _ := ret[0].(comet.BlockInfo) + return ret0 +} + +// GetCometBlockInfo indicates an expected call of GetCometBlockInfo. +func (mr *MockCometinfoMockRecorder) GetCometBlockInfo(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCometBlockInfo", reflect.TypeOf((*MockCometinfo)(nil).GetCometBlockInfo), arg0) +} diff --git a/x/evidence/types/evidence.go b/x/evidence/types/evidence.go index 622907d6830a..cabdf59b0325 100644 --- a/x/evidence/types/evidence.go +++ b/x/evidence/types/evidence.go @@ -4,8 +4,8 @@ import ( "fmt" "time" + "cosmossdk.io/core/comet" "cosmossdk.io/x/evidence/exported" - abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/crypto/tmhash" sdk "github.com/cosmos/cosmos-sdk/types" @@ -74,17 +74,17 @@ func (e Equivocation) GetTotalPower() int64 { return 0 } // FromABCIEvidence converts a CometBFT concrete Evidence type to // SDK Evidence using Equivocation as the concrete type. -func FromABCIEvidence(e abci.Misbehavior) *Equivocation { +func FromABCIEvidence(e comet.Evidence) *Equivocation { bech32PrefixConsAddr := sdk.GetConfig().GetBech32ConsensusAddrPrefix() - consAddr, err := sdk.Bech32ifyAddressBytes(bech32PrefixConsAddr, e.Validator.Address) + consAddr, err := sdk.Bech32ifyAddressBytes(bech32PrefixConsAddr, e.Validator().Address()) if err != nil { panic(err) } return &Equivocation{ - Height: e.Height, - Power: e.Validator.Power, + Height: e.Height(), + Power: e.Validator().Power(), ConsensusAddress: consAddr, - Time: e.Time, + Time: e.Time(), } } diff --git a/x/evidence/types/evidence_test.go b/x/evidence/types/evidence_test.go index f5a174ca3120..4f13329c914c 100644 --- a/x/evidence/types/evidence_test.go +++ b/x/evidence/types/evidence_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" + "cosmossdk.io/core/comet" "cosmossdk.io/x/evidence/types" - abci "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -72,19 +72,65 @@ func TestEquivocationValidateBasic(t *testing.T) { func TestEvidenceAddressConversion(t *testing.T) { sdk.GetConfig().SetBech32PrefixForConsensusNode("testcnclcons", "testcnclconspub") - tmEvidence := abci.Misbehavior{ - Type: abci.MisbehaviorType_DUPLICATE_VOTE, - Validator: abci.Validator{ - Address: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - Power: 100, - }, - Height: 1, - Time: time.Now(), - TotalVotingPower: 100, - } + tmEvidence := NewCometMisbehavior(1, 100, time.Now(), comet.DuplicateVote, + validator{address: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, power: 100}) + evidence := types.FromABCIEvidence(tmEvidence) consAddr := evidence.GetConsensusAddress() // Check the address is the same after conversion - require.Equal(t, tmEvidence.Validator.Address, consAddr.Bytes()) + require.Equal(t, tmEvidence.Validator().Address(), consAddr.Bytes()) sdk.GetConfig().SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub) } + +type Misbehavior struct { + height int64 + time time.Time + totalVotingPower int64 + validator validator + misBehaviorType comet.MisbehaviorType +} + +func NewCometMisbehavior(height, tvp int64, t time.Time, tpe comet.MisbehaviorType, val validator) comet.Evidence { + return Misbehavior{ + height: height, + time: t, + totalVotingPower: tvp, + misBehaviorType: tpe, + validator: val, + } +} + +func (m Misbehavior) Type() comet.MisbehaviorType { + return m.misBehaviorType +} + +func (m Misbehavior) Height() int64 { + return m.height +} + +func (m Misbehavior) Validator() comet.Validator { + return m.validator +} + +func (m Misbehavior) Time() time.Time { + return m.time +} + +func (m Misbehavior) TotalVotingPower() int64 { + return m.totalVotingPower +} + +type validator struct { + address []byte + power int64 +} + +var _ comet.Validator = (*validator)(nil) + +func (v validator) Address() []byte { + return v.address +} + +func (v validator) Power() int64 { + return v.power +} diff --git a/x/evidence/types/expected_keepers.go b/x/evidence/types/expected_keepers.go index e21ca0530122..3405c5ed8bd5 100644 --- a/x/evidence/types/expected_keepers.go +++ b/x/evidence/types/expected_keepers.go @@ -4,6 +4,7 @@ import ( "context" "time" + "cosmossdk.io/core/comet" sdkmath "cosmossdk.io/math" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -44,4 +45,8 @@ type ( SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins } + + Cometinfo interface { + comet.BlockInfoService + } )