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:
mconcat
2021-10-09 04:33:50 +09:00
committed by Sergio Mena
parent 51f3118bd6
commit 5cc5110e9e
18 changed files with 265 additions and 41 deletions

View File

@@ -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)
}
//----------------------------------------

View File

@@ -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()
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
}

View File

@@ -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},
}
}

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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

View File

@@ -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+" "),

View File

@@ -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);
}

View File

@@ -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)
}

View File

@@ -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,

View File

@@ -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()

View File

@@ -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}
}