Skip to content

Commit

Permalink
feat: add header and comet info service (#15850)
Browse files Browse the repository at this point in the history
Co-authored-by: Aaron Craelius <[email protected]>
  • Loading branch information
tac0turtle and aaronc authored May 3, 2023
1 parent 1d03f41 commit 1705615
Show file tree
Hide file tree
Showing 27 changed files with 660 additions and 108 deletions.
14 changes: 8 additions & 6 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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)).
Expand Down Expand Up @@ -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)).
Expand Down
9 changes: 3 additions & 6 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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))

Expand Down
197 changes: 197 additions & 0 deletions baseapp/info.go
Original file line number Diff line number Diff line change
@@ -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}
}
7 changes: 7 additions & 0 deletions core/comet/doc.go
Original file line number Diff line number Diff line change
@@ -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
68 changes: 68 additions & 0 deletions core/comet/service.go
Original file line number Diff line number Diff line change
@@ -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
}
7 changes: 7 additions & 0 deletions core/header/doc.go
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions core/header/service.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 1705615

Please sign in to comment.