mirror of
https://github.com/tendermint/tendermint.git
synced 2026-04-24 01:30:32 +00:00
Rebased and git-squashed the commits in PR #7091
add processproposal proto/boilerplate/logic mockery gofmt fix test gofmt move UNKNOWN response behaviour to reject
This commit is contained in:
@@ -43,6 +43,7 @@ type Client interface {
|
||||
OfferSnapshotAsync(types.RequestOfferSnapshot) *ReqRes
|
||||
LoadSnapshotChunkAsync(types.RequestLoadSnapshotChunk) *ReqRes
|
||||
ApplySnapshotChunkAsync(types.RequestApplySnapshotChunk) *ReqRes
|
||||
ProcessProposalAsync(types.RequestProcessProposal) *ReqRes
|
||||
|
||||
FlushSync() error
|
||||
EchoSync(msg string) (*types.ResponseEcho, error)
|
||||
@@ -60,6 +61,7 @@ type Client interface {
|
||||
OfferSnapshotSync(types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error)
|
||||
LoadSnapshotChunkSync(types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error)
|
||||
ApplySnapshotChunkSync(types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error)
|
||||
ProcessProposalSync(types.RequestProcessProposal) (*types.ResponseProcessProposal, error)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
@@ -309,6 +309,28 @@ func (cli *grpcClient) PrepareProposalAsync(params types.RequestPrepareProposal)
|
||||
return cli.finishAsyncCall(req, &types.Response{Value: &types.Response_PrepareProposal{PrepareProposal: res}})
|
||||
}
|
||||
|
||||
func (cli *grpcClient) ProcessProposalAsync(
|
||||
ctx context.Context,
|
||||
params types.RequestProcessProposal,
|
||||
) (*ReqRes, error) {
|
||||
|
||||
req := types.ToRequestProcessProposal(params)
|
||||
res, err := cli.client.ProcessProposal(ctx, req.GetProcessProposal(), grpc.WaitForReady(true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cli.finishAsyncCall(
|
||||
ctx,
|
||||
req,
|
||||
&types.Response{
|
||||
Value: &types.Response_ProcessProposal{
|
||||
ProcessProposal: res,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// finishAsyncCall creates a ReqRes for an async call, and immediately populates it
|
||||
// with the response. We don't complete it until it's been ordered via the channel.
|
||||
func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) *ReqRes {
|
||||
@@ -432,3 +454,15 @@ func (cli *grpcClient) PrepareProposalSync(
|
||||
reqres := cli.PrepareProposalAsync(params)
|
||||
return cli.finishSyncCall(reqres).GetPrepareProposal(), cli.Error()
|
||||
}
|
||||
|
||||
func (cli *grpcClient) ProcessProposalSync(
|
||||
ctx context.Context,
|
||||
params types.RequestProcessProposal,
|
||||
) (*types.ResponseProcessProposal, error) {
|
||||
|
||||
reqres, err := cli.ProcessProposalAsync(ctx, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cli.finishSyncCall(reqres).GetProcessProposal(), cli.Error()
|
||||
}
|
||||
|
||||
@@ -218,6 +218,20 @@ func (app *localClient) PrepareProposalAsync(req types.RequestPrepareProposal) *
|
||||
)
|
||||
}
|
||||
|
||||
func (app *localClient) ProcessProposalAsync(
|
||||
ctx context.Context,
|
||||
req types.RequestProcessProposal,
|
||||
) (*ReqRes, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
|
||||
res := app.Application.ProcessProposal(req)
|
||||
return app.callback(
|
||||
types.ToRequestProcessProposal(req),
|
||||
types.ToResponseProcessProposal(res),
|
||||
), nil
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
func (app *localClient) FlushSync() error {
|
||||
@@ -342,6 +356,17 @@ func (app *localClient) PrepareProposalSync(req types.RequestPrepareProposal) (*
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (app *localClient) ProcessProposalSync(
|
||||
ctx context.Context,
|
||||
req types.RequestProcessProposal,
|
||||
) (*types.ResponseProcessProposal, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
|
||||
res := app.Application.ProcessProposal(req)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
func (app *localClient) callback(req *types.Request, res *types.Response) *ReqRes {
|
||||
|
||||
@@ -283,6 +283,13 @@ func (cli *socketClient) PrepareProposalAsync(req types.RequestPrepareProposal)
|
||||
return cli.queueRequest(types.ToRequestPrepareProposal(req))
|
||||
}
|
||||
|
||||
func (cli *socketClient) ProcessProposalAsync(
|
||||
ctx context.Context,
|
||||
req types.RequestProcessProposal,
|
||||
) (*ReqRes, error) {
|
||||
return cli.queueRequestAsync(ctx, types.ToRequestProcessProposal(req))
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func (cli *socketClient) FlushSync() error {
|
||||
@@ -430,6 +437,18 @@ func (cli *socketClient) PrepareProposalSync(req types.RequestPrepareProposal) (
|
||||
return reqres.Response.GetPrepareProposal(), cli.Error()
|
||||
}
|
||||
|
||||
func (cli *socketClient) ProcessProposalSync(
|
||||
ctx context.Context,
|
||||
req types.RequestProcessProposal,
|
||||
) (*types.ResponseProcessProposal, error) {
|
||||
|
||||
reqres, err := cli.queueRequestAndFlushSync(ctx, types.ToRequestProcessProposal(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reqres.Response.GetProcessProposal(), nil
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func (cli *socketClient) queueRequest(req *types.Request) *ReqRes {
|
||||
|
||||
@@ -179,6 +179,16 @@ func (app *PersistentKVStoreApplication) PrepareProposal(
|
||||
return types.ResponsePrepareProposal{BlockData: req.BlockData}
|
||||
}
|
||||
|
||||
func (app *PersistentKVStoreApplication) ProcessProposal(
|
||||
req types.RequestProcessProposal) types.ResponseProcessProposal {
|
||||
for _, tx := range req.Txs {
|
||||
if len(tx) == 0 {
|
||||
return types.ResponseProcessProposal{Result: types.ResponseProcessProposal_REJECT}
|
||||
}
|
||||
}
|
||||
return types.ResponseProcessProposal{Result: types.ResponseProcessProposal_ACCEPT}
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// update validators
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ type Application interface {
|
||||
DeliverTx(RequestDeliverTx) ResponseDeliverTx // Deliver a tx for full processing
|
||||
EndBlock(RequestEndBlock) ResponseEndBlock // Signals the end of a block, returns changes to the validator set
|
||||
Commit() ResponseCommit // Commit the state and return the application Merkle root hash
|
||||
ProcessProposal(RequestProcessProposal) ResponseProcessProposal
|
||||
|
||||
// State Sync Connection
|
||||
ListSnapshots(RequestListSnapshots) ResponseListSnapshots // List available snapshots
|
||||
@@ -102,6 +103,10 @@ func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepa
|
||||
}
|
||||
}
|
||||
|
||||
func (BaseApplication) ProcessProposal(req RequestProcessProposal) ResponseProcessProposal {
|
||||
return ResponseProcessProposal{}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
// GRPCApplication is a GRPC wrapper for Application
|
||||
@@ -195,3 +200,9 @@ func (app *GRPCApplication) PrepareProposal(
|
||||
res := app.app.PrepareProposal(*req)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (app *GRPCApplication) ProcessProposal(
|
||||
ctx context.Context, req *RequestProcessProposal) (*ResponseProcessProposal, error) {
|
||||
res := app.app.ProcessProposal(*req)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
@@ -165,6 +165,12 @@ func ToRequestPrepareProposal(req RequestPrepareProposal) *Request {
|
||||
}
|
||||
}
|
||||
|
||||
func ToRequestProcessProposal(req RequestProcessProposal) *Request {
|
||||
return &Request{
|
||||
Value: &Request_ProcessProposal{&req},
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func ToResponseException(errStr string) *Response {
|
||||
@@ -268,3 +274,9 @@ func ToResponsePrepareProposal(res ResponsePrepareProposal) *Response {
|
||||
Value: &Response_PrepareProposal{&res},
|
||||
}
|
||||
}
|
||||
|
||||
func ToResponseProcessProposal(res ResponseProcessProposal) *Response {
|
||||
return &Response{
|
||||
Value: &Response_ProcessProposal{&res},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,21 @@ func (r ResponseQuery) IsErr() bool {
|
||||
return r.Code != CodeTypeOK
|
||||
}
|
||||
|
||||
// IsUnknown returns true if Code is Unknown
|
||||
func (r ResponseProcessProposal) IsUnknown() bool {
|
||||
return r.Result == ResponseProcessProposal_UNKNOWN
|
||||
}
|
||||
|
||||
// IsOK returns true if Code is OK
|
||||
func (r ResponseProcessProposal) IsOK() bool {
|
||||
return r.Result == ResponseProcessProposal_ACCEPT
|
||||
}
|
||||
|
||||
// IsErr returns true if Code is something other than OK.
|
||||
func (r ResponseProcessProposal) IsErr() bool {
|
||||
return r.Result != ResponseProcessProposal_ACCEPT
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// override JSON marshaling so we emit defaults (ie. disable omitempty)
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
|
||||
// Make proposal
|
||||
propBlockID := types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()}
|
||||
proposal := types.NewProposal(height, round, lazyProposer.ValidRound, propBlockID)
|
||||
proposal := types.NewProposal(height, round, lazyProposer.TwoThirdPrevoteRound, propBlockID)
|
||||
p := proposal.ToProto()
|
||||
if err := lazyProposer.privValidator.SignProposal(lazyProposer.state.ChainID, p); err == nil {
|
||||
proposal.Signature = p.Signature
|
||||
@@ -462,7 +462,7 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int32, cs *St
|
||||
|
||||
// Create a new proposal block from state/txs from the mempool.
|
||||
block1, blockParts1 := cs.createProposalBlock()
|
||||
polRound, propBlockID := cs.ValidRound, types.BlockID{Hash: block1.Hash(), PartSetHeader: blockParts1.Header()}
|
||||
polRound, propBlockID := cs.TwoThirdPrevoteRound, types.BlockID{Hash: block1.Hash(), PartSetHeader: blockParts1.Header()}
|
||||
proposal1 := types.NewProposal(height, round, polRound, propBlockID)
|
||||
p1 := proposal1.ToProto()
|
||||
if err := cs.privValidator.SignProposal(cs.state.ChainID, p1); err != nil {
|
||||
@@ -476,7 +476,7 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int32, cs *St
|
||||
|
||||
// Create a new proposal block from state/txs from the mempool.
|
||||
block2, blockParts2 := cs.createProposalBlock()
|
||||
polRound, propBlockID = cs.ValidRound, types.BlockID{Hash: block2.Hash(), PartSetHeader: blockParts2.Header()}
|
||||
polRound, propBlockID = cs.TwoThirdPrevoteRound, types.BlockID{Hash: block2.Hash(), PartSetHeader: blockParts2.Header()}
|
||||
proposal2 := types.NewProposal(height, round, polRound, propBlockID)
|
||||
p2 := proposal2.ToProto()
|
||||
if err := cs.privValidator.SignProposal(cs.state.ChainID, p2); err != nil {
|
||||
|
||||
@@ -208,7 +208,7 @@ func decideProposal(
|
||||
) (proposal *types.Proposal, block *types.Block) {
|
||||
cs1.mtx.Lock()
|
||||
block, blockParts := cs1.createProposalBlock()
|
||||
validRound := cs1.ValidRound
|
||||
validRound := cs1.TwoThirdPrevoteRound
|
||||
chainID := cs1.state.ChainID
|
||||
cs1.mtx.Unlock()
|
||||
if block == nil {
|
||||
|
||||
@@ -667,9 +667,9 @@ func (cs *State) updateToState(state sm.State) {
|
||||
cs.LockedRound = -1
|
||||
cs.LockedBlock = nil
|
||||
cs.LockedBlockParts = nil
|
||||
cs.ValidRound = -1
|
||||
cs.ValidBlock = nil
|
||||
cs.ValidBlockParts = nil
|
||||
cs.TwoThirdPrevoteRound = -1
|
||||
cs.TwoThirdPrevoteBlock = nil
|
||||
cs.TwoThirdPrevoteBlockParts = nil
|
||||
cs.Votes = cstypes.NewHeightVoteSet(state.ChainID, height, validators)
|
||||
cs.CommitRound = -1
|
||||
cs.LastValidators = state.LastValidators
|
||||
@@ -1126,9 +1126,9 @@ func (cs *State) defaultDecideProposal(height int64, round int32) {
|
||||
var blockParts *types.PartSet
|
||||
|
||||
// Decide on block
|
||||
if cs.ValidBlock != nil {
|
||||
if cs.TwoThirdPrevoteBlock != nil {
|
||||
// If there is valid block, choose that.
|
||||
block, blockParts = cs.ValidBlock, cs.ValidBlockParts
|
||||
block, blockParts = cs.TwoThirdPrevoteBlock, cs.TwoThirdPrevoteBlockParts
|
||||
} else {
|
||||
// Create a new proposal block from state/txs from the mempool.
|
||||
block, blockParts = cs.createProposalBlock()
|
||||
@@ -1145,7 +1145,7 @@ func (cs *State) defaultDecideProposal(height int64, round int32) {
|
||||
|
||||
// Make proposal
|
||||
propBlockID := types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()}
|
||||
proposal := types.NewProposal(height, round, cs.ValidRound, propBlockID)
|
||||
proposal := types.NewProposal(height, round, cs.TwoThirdPrevoteRound, propBlockID)
|
||||
p := proposal.ToProto()
|
||||
if err := cs.privValidator.SignProposal(cs.state.ChainID, p); err == nil {
|
||||
proposal.Signature = p.Signature
|
||||
@@ -1276,6 +1276,19 @@ func (cs *State) defaultDoPrevote(height int64, round int32) {
|
||||
return
|
||||
}
|
||||
|
||||
stateMachineValidBlock, err := cs.blockExec.ProcessProposal(cs.ProposalBlock)
|
||||
if err != nil {
|
||||
cs.Logger.Error("state machine returned an error when trying to process proposal block", "err", err)
|
||||
}
|
||||
|
||||
// Vote nil if application invalidated the block
|
||||
if !stateMachineValidBlock {
|
||||
// Consensus says we must vote nil
|
||||
logger.Error("prevote step: consensus deems this block to be mustVoteNil", "err", err)
|
||||
cs.signAddVote(tmproto.PrevoteType, nil, types.PartSetHeader{})
|
||||
return
|
||||
}
|
||||
|
||||
// Prevote cs.ProposalBlock
|
||||
// NOTE: the proposal signature is validated when it is received,
|
||||
// and the proposal block parts are validated as they are received (against the merkle hash in the proposal)
|
||||
@@ -1913,7 +1926,7 @@ func (cs *State) handleCompleteProposal(blockHeight int64) {
|
||||
// Update Valid* if we can.
|
||||
prevotes := cs.Votes.Prevotes(cs.Round)
|
||||
blockID, hasTwoThirds := prevotes.TwoThirdsMajority()
|
||||
if hasTwoThirds && !blockID.IsZero() && (cs.ValidRound < cs.Round) {
|
||||
if hasTwoThirds && !blockID.IsZero() && (cs.TwoThirdPrevoteRound < cs.Round) {
|
||||
if cs.ProposalBlock.HashesTo(blockID.Hash) {
|
||||
cs.Logger.Debug(
|
||||
"updating valid block to new proposal block",
|
||||
@@ -1921,9 +1934,9 @@ func (cs *State) handleCompleteProposal(blockHeight int64) {
|
||||
"valid_block_hash", log.NewLazyBlockHash(cs.ProposalBlock),
|
||||
)
|
||||
|
||||
cs.ValidRound = cs.Round
|
||||
cs.ValidBlock = cs.ProposalBlock
|
||||
cs.ValidBlockParts = cs.ProposalBlockParts
|
||||
cs.TwoThirdPrevoteRound = cs.Round
|
||||
cs.TwoThirdPrevoteBlock = cs.ProposalBlock
|
||||
cs.TwoThirdPrevoteBlockParts = cs.ProposalBlockParts
|
||||
}
|
||||
// TODO: In case there is +2/3 majority in Prevotes set for some
|
||||
// block and cs.ProposalBlock contains different block, either
|
||||
@@ -2083,12 +2096,12 @@ func (cs *State) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error
|
||||
|
||||
// Update Valid* if we can.
|
||||
// NOTE: our proposal block may be nil or not what received a polka..
|
||||
if len(blockID.Hash) != 0 && (cs.ValidRound < vote.Round) && (vote.Round == cs.Round) {
|
||||
if len(blockID.Hash) != 0 && (cs.TwoThirdPrevoteRound < vote.Round) && (vote.Round == cs.Round) {
|
||||
if cs.ProposalBlock.HashesTo(blockID.Hash) {
|
||||
cs.Logger.Debug("updating valid block because of POL", "valid_round", cs.ValidRound, "pol_round", vote.Round)
|
||||
cs.ValidRound = vote.Round
|
||||
cs.ValidBlock = cs.ProposalBlock
|
||||
cs.ValidBlockParts = cs.ProposalBlockParts
|
||||
cs.Logger.Debug("updating valid block because of POL", "valid_round", cs.TwoThirdPrevoteRound, "pol_round", vote.Round)
|
||||
cs.TwoThirdPrevoteRound = vote.Round
|
||||
cs.TwoThirdPrevoteBlock = cs.ProposalBlock
|
||||
cs.TwoThirdPrevoteBlockParts = cs.ProposalBlockParts
|
||||
} else {
|
||||
cs.Logger.Debug(
|
||||
"valid block we do not know about; set ProposalBlock=nil",
|
||||
|
||||
@@ -1199,9 +1199,9 @@ func TestProposeValidBlock(t *testing.T) {
|
||||
|
||||
rs = cs1.GetRoundState()
|
||||
assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), propBlockHash))
|
||||
assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), rs.ValidBlock.Hash()))
|
||||
assert.True(t, rs.Proposal.POLRound == rs.ValidRound)
|
||||
assert.True(t, bytes.Equal(rs.Proposal.BlockID.Hash, rs.ValidBlock.Hash()))
|
||||
assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), rs.TwoThirdPrevoteBlock.Hash()))
|
||||
assert.True(t, rs.Proposal.POLRound == rs.TwoThirdPrevoteRound)
|
||||
assert.True(t, bytes.Equal(rs.Proposal.BlockID.Hash, rs.TwoThirdPrevoteBlock.Hash()))
|
||||
}
|
||||
|
||||
// What we want:
|
||||
@@ -1249,9 +1249,9 @@ func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
|
||||
|
||||
rs = cs1.GetRoundState()
|
||||
|
||||
assert.True(t, rs.ValidBlock == nil)
|
||||
assert.True(t, rs.ValidBlockParts == nil)
|
||||
assert.True(t, rs.ValidRound == -1)
|
||||
assert.True(t, rs.TwoThirdPrevoteBlock == nil)
|
||||
assert.True(t, rs.TwoThirdPrevoteBlockParts == nil)
|
||||
assert.True(t, rs.TwoThirdPrevoteRound == -1)
|
||||
|
||||
// vs2 send (delayed) prevote for propBlock
|
||||
signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs4)
|
||||
@@ -1260,9 +1260,9 @@ func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
|
||||
|
||||
rs = cs1.GetRoundState()
|
||||
|
||||
assert.True(t, bytes.Equal(rs.ValidBlock.Hash(), propBlockHash))
|
||||
assert.True(t, rs.ValidBlockParts.Header().Equals(propBlockParts.Header()))
|
||||
assert.True(t, rs.ValidRound == round)
|
||||
assert.True(t, bytes.Equal(rs.TwoThirdPrevoteBlock.Hash(), propBlockHash))
|
||||
assert.True(t, rs.TwoThirdPrevoteBlockParts.Header().Equals(propBlockParts.Header()))
|
||||
assert.True(t, rs.TwoThirdPrevoteRound == round)
|
||||
}
|
||||
|
||||
// What we want:
|
||||
@@ -1316,9 +1316,9 @@ func TestSetValidBlockOnDelayedProposal(t *testing.T) {
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
rs := cs1.GetRoundState()
|
||||
|
||||
assert.True(t, bytes.Equal(rs.ValidBlock.Hash(), propBlockHash))
|
||||
assert.True(t, rs.ValidBlockParts.Header().Equals(propBlockParts.Header()))
|
||||
assert.True(t, rs.ValidRound == round)
|
||||
assert.True(t, bytes.Equal(rs.TwoThirdPrevoteBlock.Hash(), propBlockHash))
|
||||
assert.True(t, rs.TwoThirdPrevoteBlockParts.Header().Equals(propBlockParts.Header()))
|
||||
assert.True(t, rs.TwoThirdPrevoteRound == round)
|
||||
}
|
||||
|
||||
// 4 vals, 3 Nil Precommits at P0
|
||||
|
||||
@@ -81,11 +81,11 @@ type RoundState struct {
|
||||
LockedBlockParts *types.PartSet `json:"locked_block_parts"`
|
||||
|
||||
// Last known round with POL for non-nil valid block.
|
||||
ValidRound int32 `json:"valid_round"`
|
||||
ValidBlock *types.Block `json:"valid_block"` // Last known block of POL mentioned above.
|
||||
TwoThirdPrevoteRound int32 `json:"valid_round"`
|
||||
TwoThirdPrevoteBlock *types.Block `json:"valid_block"` // Last known block of POL mentioned above.
|
||||
|
||||
// Last known block parts of POL mentioned above.
|
||||
ValidBlockParts *types.PartSet `json:"valid_block_parts"`
|
||||
TwoThirdPrevoteBlockParts *types.PartSet `json:"valid_block_parts"`
|
||||
Votes *HeightVoteSet `json:"votes"`
|
||||
CommitRound int32 `json:"commit_round"` //
|
||||
LastCommit *types.VoteSet `json:"last_commit"` // Last precommits at Height-1
|
||||
@@ -119,7 +119,7 @@ func (rs *RoundState) RoundStateSimple() RoundStateSimple {
|
||||
StartTime: rs.StartTime,
|
||||
ProposalBlockHash: rs.ProposalBlock.Hash(),
|
||||
LockedBlockHash: rs.LockedBlock.Hash(),
|
||||
ValidBlockHash: rs.ValidBlock.Hash(),
|
||||
ValidBlockHash: rs.TwoThirdPrevoteBlock.Hash(),
|
||||
Votes: votesJSON,
|
||||
Proposer: types.ValidatorInfo{
|
||||
Address: addr,
|
||||
@@ -186,8 +186,8 @@ func (rs *RoundState) StringIndented(indent string) string {
|
||||
%s ProposalBlock: %v %v
|
||||
%s LockedRound: %v
|
||||
%s LockedBlock: %v %v
|
||||
%s ValidRound: %v
|
||||
%s ValidBlock: %v %v
|
||||
%s TwoThirdPrevoteRound: %v
|
||||
%s TwoThirdPrevoteBlock: %v %v
|
||||
%s Votes: %v
|
||||
%s LastCommit: %v
|
||||
%s LastValidators:%v
|
||||
@@ -200,8 +200,8 @@ func (rs *RoundState) StringIndented(indent string) string {
|
||||
indent, rs.ProposalBlockParts.StringShort(), rs.ProposalBlock.StringShort(),
|
||||
indent, rs.LockedRound,
|
||||
indent, rs.LockedBlockParts.StringShort(), rs.LockedBlock.StringShort(),
|
||||
indent, rs.ValidRound,
|
||||
indent, rs.ValidBlockParts.StringShort(), rs.ValidBlock.StringShort(),
|
||||
indent, rs.TwoThirdPrevoteRound,
|
||||
indent, rs.TwoThirdPrevoteBlockParts.StringShort(), rs.TwoThirdPrevoteBlock.StringShort(),
|
||||
indent, rs.Votes.StringIndented(indent+" "),
|
||||
indent, rs.LastCommit.StringShort(),
|
||||
indent, rs.LastValidators.StringIndented(indent+" "),
|
||||
|
||||
@@ -37,6 +37,7 @@ message Request {
|
||||
RequestLoadSnapshotChunk load_snapshot_chunk = 14;
|
||||
RequestApplySnapshotChunk apply_snapshot_chunk = 15;
|
||||
RequestPrepareProposal prepare_proposal = 16;
|
||||
RequestProcessProposal process_proposal = 17;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +135,11 @@ message RequestPrepareProposal {
|
||||
int64 block_data_size = 2;
|
||||
}
|
||||
|
||||
message RequestProcessProposal {
|
||||
tendermint.types.Header header = 1 [(gogoproto.nullable) = false];
|
||||
repeated bytes txs = 2;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Response types
|
||||
|
||||
@@ -156,7 +162,7 @@ message Response {
|
||||
ResponseLoadSnapshotChunk load_snapshot_chunk = 15;
|
||||
ResponseApplySnapshotChunk apply_snapshot_chunk = 16;
|
||||
ResponsePrepareProposal prepare_proposal = 17;
|
||||
|
||||
ResponseProcessProposal process_proposal = 18;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,6 +304,17 @@ message ResponsePrepareProposal {
|
||||
repeated bytes block_data = 1;
|
||||
}
|
||||
|
||||
message ResponseProcessProposal {
|
||||
Result result = 1;
|
||||
repeated bytes evidence = 2;
|
||||
|
||||
enum Result {
|
||||
UNKNOWN = 0; // Unknown result, invalidate
|
||||
ACCEPT = 1; // proposal verified, vote on the proposal
|
||||
REJECT = 2; // proposal invalidated
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Misc.
|
||||
|
||||
@@ -427,4 +444,5 @@ service ABCIApplication {
|
||||
rpc ApplySnapshotChunk(RequestApplySnapshotChunk)
|
||||
returns (ResponseApplySnapshotChunk);
|
||||
rpc PrepareProposal(RequestPrepareProposal) returns (ResponsePrepareProposal);
|
||||
rpc ProcessProposal(RequestProcessProposal) returns (ResponseProcessProposal);
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ type AppConnConsensus interface {
|
||||
Error() error
|
||||
|
||||
InitChainSync(types.RequestInitChain) (*types.ResponseInitChain, error)
|
||||
|
||||
PrepareProposalSync(types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error)
|
||||
ProcessProposalSync(types.RequestProcessProposal) (*types.ResponseProcessProposal, error)
|
||||
BeginBlockSync(types.RequestBeginBlock) (*types.ResponseBeginBlock, error)
|
||||
DeliverTxAsync(types.RequestDeliverTx) *abcicli.ReqRes
|
||||
EndBlockSync(types.RequestEndBlock) (*types.ResponseEndBlock, error)
|
||||
@@ -85,6 +85,10 @@ func (app *appConnConsensus) PrepareProposalSync(
|
||||
return app.appConn.PrepareProposalSync(req)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) ProcessProposalSync(req types.RequestProcessProposal) (*types.ResponseProcessProposal, error) {
|
||||
return app.appConn.ProcessProposalSync(req)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) BeginBlockSync(req types.RequestBeginBlock) (*types.ResponseBeginBlock, error) {
|
||||
return app.appConn.BeginBlockSync(req)
|
||||
}
|
||||
|
||||
@@ -138,6 +138,23 @@ func (blockExec *BlockExecutor) CreateProposalBlock(
|
||||
return state.MakeBlock(height, modifiedTxs, commit, evidence, proposerAddr)
|
||||
}
|
||||
|
||||
func (blockExec *BlockExecutor) ProcessProposal(
|
||||
block *types.Block,
|
||||
) (bool, error) {
|
||||
ctx := context.Background()
|
||||
req := abci.RequestProcessProposal{
|
||||
Txs: block.Data.Txs.ToSliceOfBytes(),
|
||||
Header: *block.Header.ToProto(),
|
||||
}
|
||||
|
||||
resp, err := blockExec.proxyApp.ProcessProposalSync(ctx, req)
|
||||
if err != nil {
|
||||
return false, ErrInvalidBlock(err)
|
||||
}
|
||||
|
||||
return resp.IsOK(), nil
|
||||
}
|
||||
|
||||
// ValidateBlock validates the given block against the given state.
|
||||
// If the block is invalid, it returns an error.
|
||||
// Validation does not mutate state, but does require historical information from the stateDB,
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
sf "github.com/tendermint/tendermint/internal/test/factory"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
mmock "github.com/tendermint/tendermint/mempool/mock"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
@@ -22,9 +23,11 @@ import (
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/state/mocks"
|
||||
sf "github.com/tendermint/tendermint/state/test/factory"
|
||||
"github.com/tendermint/tendermint/store"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -214,6 +217,38 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
|
||||
assert.Equal(t, abciEv, app.ByzantineValidators)
|
||||
}
|
||||
|
||||
func TestProcessProposal(t *testing.T) {
|
||||
height := 1
|
||||
runTest := func(txs types.Txs, expectAccept bool) {
|
||||
app := &testApp{}
|
||||
cc := proxy.NewLocalClientCreator(app)
|
||||
proxyApp := proxy.NewAppConns(cc)
|
||||
err := proxyApp.Start()
|
||||
require.Nil(t, err)
|
||||
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
|
||||
|
||||
state, stateDB, _ := makeState(1, height)
|
||||
stateStore := sm.NewStore(stateDB)
|
||||
|
||||
blockStore := store.NewBlockStore(dbm.NewMemDB())
|
||||
|
||||
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
|
||||
mmock.Mempool{}, sm.EmptyEvidencePool{}, blockStore)
|
||||
|
||||
block := sf.MakeBlock(state, int64(height), new(types.Commit))
|
||||
block.Txs = txs
|
||||
acceptBlock, err := blockExec.ProcessProposal(block)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, expectAccept, acceptBlock)
|
||||
}
|
||||
goodTxs := sf.MakeTenTxs(int64(height))
|
||||
runTest(goodTxs, true)
|
||||
// testApp has process proposal fail if any tx is 0-len
|
||||
badTxs := sf.MakeTenTxs(int64(height))
|
||||
badTxs[0] = types.Tx{}
|
||||
runTest(badTxs, false)
|
||||
}
|
||||
|
||||
func TestValidateValidatorUpdates(t *testing.T) {
|
||||
pubkey1 := ed25519.GenPrivKey().PubKey()
|
||||
pubkey2 := ed25519.GenPrivKey().PubKey()
|
||||
|
||||
@@ -256,3 +256,12 @@ func (app *testApp) Commit() abci.ResponseCommit {
|
||||
func (app *testApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) {
|
||||
return
|
||||
}
|
||||
|
||||
func (app *testApp) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal {
|
||||
for _, tx := range req.Txs {
|
||||
if len(tx) == 0 {
|
||||
return abci.ResponseProcessProposal{Result: abci.ResponseProcessProposal_REJECT}
|
||||
}
|
||||
}
|
||||
return abci.ResponseProcessProposal{Result: abci.ResponseProcessProposal_ACCEPT}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user