diff --git a/abci/client/grpc_client.go b/abci/client/grpc_client.go index b681b3e5fdf..10e1a79b8f8 100644 --- a/abci/client/grpc_client.go +++ b/abci/client/grpc_client.go @@ -343,13 +343,13 @@ func (cli *grpcClient) VerifyVoteExtensionAsync( } return cli.finishAsyncCall( ctx, - req, + req, &types.Response{ - Value: &types.Response_VerifyVoteExtension{ - VerifyVoteExtension: res, - }, - }, - ) + Value: &types.Response_VerifyVoteExtension{ + VerifyVoteExtension: res, + }, + }, + ) } func (cli *grpcClient) PrepareProposalAsync( @@ -359,14 +359,14 @@ func (cli *grpcClient) PrepareProposalAsync( req := types.ToRequestPrepareProposal(params) res, err := cli.client.PrepareProposal(ctx, req.GetPrepareProposal(), grpc.WaitForReady(true)) - if err != nil { - return nil, err - } - - return cli.finishAsyncCall( - ctx, - req, - &types.Response{ + if err != nil { + return nil, err + } + + return cli.finishAsyncCall( + ctx, + req, + &types.Response{ Value: &types.Response_PrepareProposal{ PrepareProposal: res, }, @@ -584,7 +584,7 @@ func (cli *grpcClient) VerifyVoteExtensionSync( if err != nil { return nil, err } - return cli.finishSyncCall(reqres).GetVerifyVoteExtension(), cli.Error() + return cli.finishSyncCall(reqres).GetVerifyVoteExtension(), cli.Error() } func (cli *grpcClient) PrepareProposalSync( diff --git a/abci/client/local_client.go b/abci/client/local_client.go index c2e13678a4f..baaf5a7a782 100644 --- a/abci/client/local_client.go +++ b/abci/client/local_client.go @@ -236,14 +236,14 @@ func (app *localClient) PrepareProposalAsync( ctx context.Context, req types.RequestPrepareProposal, ) (*ReqRes, error) { - app.mtx.Lock() - defer app.mtx.Unlock() + app.mtx.Lock() + defer app.mtx.Unlock() - res := app.Application.PrepareProposal(req) + res := app.Application.PrepareProposal(req) return app.callback( types.ToRequestPrepareProposal(req), types.ToResponsePrepareProposal(res), - ), nil + ), nil } //------------------------------------------------------- @@ -407,15 +407,15 @@ func (app *localClient) VerifyVoteExtensionSync( defer app.mtx.Unlock() res := app.Application.VerifyVoteExtension(req) - return &res, nil + return &res, nil } func (app *localClient) PrepareProposalSync( ctx context.Context, req types.RequestPrepareProposal, ) (*types.ResponsePrepareProposal, error) { - app.mtx.Lock() - defer app.mtx.Unlock() + app.mtx.Lock() + defer app.mtx.Unlock() res := app.Application.PrepareProposal(req) return &res, nil diff --git a/abci/client/mocks/client.go b/abci/client/mocks/client.go index 405d586f989..41493b9cfbd 100644 --- a/abci/client/mocks/client.go +++ b/abci/client/mocks/client.go @@ -355,6 +355,52 @@ func (_m *Client) Error() error { return r0 } +// ExtendVoteAsync provides a mock function with given fields: _a0, _a1 +func (_m *Client) ExtendVoteAsync(_a0 context.Context, _a1 types.RequestExtendVote) (*abcicli.ReqRes, error) { + ret := _m.Called(_a0, _a1) + + var r0 *abcicli.ReqRes + if rf, ok := ret.Get(0).(func(context.Context, types.RequestExtendVote) *abcicli.ReqRes); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*abcicli.ReqRes) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestExtendVote) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExtendVoteSync provides a mock function with given fields: _a0, _a1 +func (_m *Client) ExtendVoteSync(_a0 context.Context, _a1 types.RequestExtendVote) (*types.ResponseExtendVote, error) { + ret := _m.Called(_a0, _a1) + + var r0 *types.ResponseExtendVote + if rf, ok := ret.Get(0).(func(context.Context, types.RequestExtendVote) *types.ResponseExtendVote); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ResponseExtendVote) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestExtendVote) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // FlushAsync provides a mock function with given fields: _a0 func (_m *Client) FlushAsync(_a0 context.Context) (*abcicli.ReqRes, error) { ret := _m.Called(_a0) @@ -843,6 +889,52 @@ func (_m *Client) String() string { return r0 } +// VerifyVoteExtensionAsync provides a mock function with given fields: _a0, _a1 +func (_m *Client) VerifyVoteExtensionAsync(_a0 context.Context, _a1 types.RequestVerifyVoteExtension) (*abcicli.ReqRes, error) { + ret := _m.Called(_a0, _a1) + + var r0 *abcicli.ReqRes + if rf, ok := ret.Get(0).(func(context.Context, types.RequestVerifyVoteExtension) *abcicli.ReqRes); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*abcicli.ReqRes) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestVerifyVoteExtension) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// VerifyVoteExtensionSync provides a mock function with given fields: _a0, _a1 +func (_m *Client) VerifyVoteExtensionSync(_a0 context.Context, _a1 types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) { + ret := _m.Called(_a0, _a1) + + var r0 *types.ResponseVerifyVoteExtension + if rf, ok := ret.Get(0).(func(context.Context, types.RequestVerifyVoteExtension) *types.ResponseVerifyVoteExtension); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ResponseVerifyVoteExtension) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, types.RequestVerifyVoteExtension) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Wait provides a mock function with given fields: func (_m *Client) Wait() { _m.Called() diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index c8f7a51bce1..d15be8c6751 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -14,6 +14,7 @@ import ( cryptoenc "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/libs/log" pc "github.com/tendermint/tendermint/proto/tendermint/crypto" + ptypes "github.com/tendermint/tendermint/proto/tendermint/types" ) const ( @@ -76,6 +77,10 @@ func (app *PersistentKVStoreApplication) DeliverTx(req types.RequestDeliverTx) t return app.execValidatorTx(req.Tx) } + if isPrepareTx(req.Tx) { + return app.execPrepareTx(req.Tx) + } + // otherwise, update the key-value store return app.app.DeliverTx(req) } @@ -172,21 +177,20 @@ func (app *PersistentKVStoreApplication) ApplySnapshotChunk( func (app *PersistentKVStoreApplication) ExtendVote( req types.RequestExtendVote) types.ResponseExtendVote { - return types.ResponseExtendVote{} + return types.ResponseExtendVote{ + VoteExtension: ConstructVoteExtension(req.Vote.ValidatorAddress), + } } func (app *PersistentKVStoreApplication) VerifyVoteExtension( req types.RequestVerifyVoteExtension) types.ResponseVerifyVoteExtension { - return types.ResponseVerifyVoteExtension{} + return types.RespondVerifyVoteExtension( + app.verifyExtension(req.Vote.ValidatorAddress, req.Vote.VoteExtension)) } func (app *PersistentKVStoreApplication) PrepareProposal( req types.RequestPrepareProposal) types.ResponsePrepareProposal { - if len(req.BlockData) >= 1 { - req.BlockData[1] = []byte("modified tx") - } - - return types.ResponsePrepareProposal{BlockData: req.BlockData} + return types.ResponsePrepareProposal{BlockData: app.substPrepareTx(req.BlockData)} } //--------------------------------------------- @@ -303,3 +307,51 @@ func (app *PersistentKVStoreApplication) updateValidator(v types.ValidatorUpdate return types.ResponseDeliverTx{Code: code.CodeTypeOK} } + +// ----------------------------- + +const PreparePrefix = "prepare" + +func isPrepareTx(tx []byte) bool { + return strings.HasPrefix(string(tx), PreparePrefix) +} + +// execPrepareTx is noop. tx data is considered as placeholder +// and is substitute at the PrepareProposal. +func (app *PersistentKVStoreApplication) execPrepareTx(tx []byte) types.ResponseDeliverTx { + // noop + return types.ResponseDeliverTx{} +} + +// substPrepareTx subst all the preparetx in the blockdata +// to null string(could be any arbitrary string). +func (app *PersistentKVStoreApplication) substPrepareTx(blockData [][]byte) [][]byte { + for i, tx := range blockData { + if isPrepareTx(tx) { + blockData[i] = make([]byte, len(tx)) + } + } + + return blockData +} + +func ConstructVoteExtension(valAddr []byte) *ptypes.VoteExtension { + return &ptypes.VoteExtension{ + AppDataToSign: valAddr, + AppDataSelfAuthenticating: valAddr, + } +} + +func (app *PersistentKVStoreApplication) verifyExtension(valAddr []byte, ext *ptypes.VoteExtension) bool { + if ext == nil { + return false + } + canonical := ConstructVoteExtension(valAddr) + if !bytes.Equal(canonical.AppDataToSign, ext.AppDataToSign) { + return false + } + if !bytes.Equal(canonical.AppDataSelfAuthenticating, ext.AppDataSelfAuthenticating) { + return false + } + return true +} diff --git a/abci/types/application.go b/abci/types/application.go index ca1b47b83c7..dfbe1bf6e09 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -19,12 +19,18 @@ type Application interface { // Consensus Connection InitChain(RequestInitChain) ResponseInitChain // Initialize blockchain w validators/other info from TendermintCore PrepareProposal(RequestPrepareProposal) ResponsePrepareProposal - BeginBlock(RequestBeginBlock) ResponseBeginBlock // Signals the beginning of a block - 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 - ExtendVote(RequestExtendVote) ResponseExtendVote // Create application specific vote extension - VerifyVoteExtension(RequestVerifyVoteExtension) ResponseVerifyVoteExtension // Verify application's vote extension data + // Signals the beginning of a block + BeginBlock(RequestBeginBlock) ResponseBeginBlock + // Deliver a tx for full processing + DeliverTx(RequestDeliverTx) ResponseDeliverTx + // Signals the end of a block, returns changes to the validator set + EndBlock(RequestEndBlock) ResponseEndBlock + // Commit the state and return the application Merkle root hash + Commit() ResponseCommit + // Create application specific vote extension + ExtendVote(RequestExtendVote) ResponseExtendVote + // Verify application's vote extension data + VerifyVoteExtension(RequestVerifyVoteExtension) ResponseVerifyVoteExtension // State Sync Connection ListSnapshots(RequestListSnapshots) ResponseListSnapshots // List available snapshots @@ -197,7 +203,7 @@ func (app *GRPCApplication) ExtendVote( func (app *GRPCApplication) VerifyVoteExtension( ctx context.Context, req *RequestVerifyVoteExtension) (*ResponseVerifyVoteExtension, error) { res := app.app.VerifyVoteExtension(*req) - return &res, nil + return &res, nil } func (app *GRPCApplication) PrepareProposal( diff --git a/abci/types/messages.go b/abci/types/messages.go index f82632982ee..ec2a2d28d80 100644 --- a/abci/types/messages.go +++ b/abci/types/messages.go @@ -119,7 +119,7 @@ func ToRequestExtendVote(req RequestExtendVote) *Request { func ToRequestVerifyVoteExtension(req RequestVerifyVoteExtension) *Request { return &Request{ Value: &Request_VerifyVoteExtension{&req}, - } + } } func ToRequestPrepareProposal(req RequestPrepareProposal) *Request { @@ -228,7 +228,7 @@ func ToResponseExtendVote(res ResponseExtendVote) *Response { func ToResponseVerifyVoteExtension(res ResponseVerifyVoteExtension) *Response { return &Response{ Value: &Response_VerifyVoteExtension{&res}, - } + } } func ToResponsePrepareProposal(res ResponsePrepareProposal) *Response { diff --git a/abci/types/result.go b/abci/types/result.go index dba6bfd159a..a08c3fda574 100644 --- a/abci/types/result.go +++ b/abci/types/result.go @@ -5,6 +5,8 @@ import ( "encoding/json" "github.com/gogo/protobuf/jsonpb" + + types "github.com/tendermint/tendermint/proto/tendermint/types" ) const ( @@ -41,6 +43,16 @@ func (r ResponseQuery) IsErr() bool { return r.Code != CodeTypeOK } +// IsOK returns true if Code is OK +func (r ResponseVerifyVoteExtension) IsOK() bool { + return r.Result <= ResponseVerifyVoteExtension_ACCEPT +} + +// IsErr returns true if Code is something other than OK. +func (r ResponseVerifyVoteExtension) IsErr() bool { + return r.Result > ResponseVerifyVoteExtension_ACCEPT +} + //--------------------------------------------------------------------------- // override JSON marshaling so we emit defaults (ie. disable omitempty) @@ -118,3 +130,25 @@ var _ jsonRoundTripper = (*ResponseDeliverTx)(nil) var _ jsonRoundTripper = (*ResponseCheckTx)(nil) var _ jsonRoundTripper = (*EventAttribute)(nil) + +// ----------------------------------------------- +// construct Result data + +func RespondExtendVote(appDataToSign, appDataSelfAuthenticating []byte) ResponseExtendVote { + return ResponseExtendVote{ + VoteExtension: &types.VoteExtension{ + AppDataToSign: appDataToSign, + AppDataSelfAuthenticating: appDataSelfAuthenticating, + }, + } +} + +func RespondVerifyVoteExtension(ok bool) ResponseVerifyVoteExtension { + result := ResponseVerifyVoteExtension_REJECT + if ok { + result = ResponseVerifyVoteExtension_ACCEPT + } + return ResponseVerifyVoteExtension{ + Result: result, + } +} diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index 17ba1ce2e40..d03ceebfb52 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -120,6 +120,7 @@ func (vs *validatorStub) signVote( Timestamp: tmtime.Now(), Type: voteType, BlockID: types.BlockID{Hash: hash, PartSetHeader: header}, + VoteExtension: types.VoteExtensionFromProto(kvstore.ConstructVoteExtension(pubKey.Address())), } v := vote.ToProto() if err := vs.PrivValidator.SignVote(context.Background(), config.ChainID(), v); err != nil { @@ -151,6 +152,10 @@ func signVote( panic(fmt.Errorf("failed to sign vote: %v", err)) } + // TODO: remove hardcoded vote extension. + // currently set for abci/examples/kvstore/persistent_kvstore.go + v.VoteExtension = types.VoteExtensionFromProto(kvstore.ConstructVoteExtension(v.ValidatorAddress)) + vs.lastVote = v return v diff --git a/internal/consensus/mempool_test.go b/internal/consensus/mempool_test.go index f7d690db330..8cbb3b4c487 100644 --- a/internal/consensus/mempool_test.go +++ b/internal/consensus/mempool_test.go @@ -273,5 +273,5 @@ func (app *CounterApplication) Commit() abci.ResponseCommit { func (app *CounterApplication) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{BlockData: req.BlockData} //nolint:gosimple + return abci.ResponsePrepareProposal{BlockData: req.BlockData} } diff --git a/internal/consensus/state.go b/internal/consensus/state.go index a3761fb2846..c26d8c90b46 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -1960,6 +1960,7 @@ func (cs *State) addProposalBlockPart(msg *BlockPartMessage, peerID types.NodeID // Attempt to add the vote. if its a duplicate signature, dupeout the validator func (cs *State) tryAddVote(vote *types.Vote, peerID types.NodeID) (bool, error) { added, err := cs.addVote(vote, peerID) + if err != nil { // If the vote height is off, we'll just ignore it, // But if it's a conflicting sig, add it to the cs.evpool. @@ -2053,6 +2054,13 @@ func (cs *State) addVote(vote *types.Vote, peerID types.NodeID) (added bool, err return } + // Verify VoteExtension if precommit + if vote.Type == tmproto.PrecommitType { + if err = cs.blockExec.VerifyVoteExtension(vote); err != nil { + return false, err + } + } + height := cs.Height added, err = cs.Votes.AddVote(vote, peerID) if !added { @@ -2209,8 +2217,6 @@ func (cs *State) signVote( BlockID: types.BlockID{Hash: hash, PartSetHeader: header}, } - v := vote.ToProto() - // If the signedMessageType is for precommit, // use our local precommit Timeout as the max wait time for getting a singed commit. The same goes for prevote. var timeout time.Duration @@ -2230,6 +2236,8 @@ func (cs *State) signVote( timeout = time.Second } + v := vote.ToProto() + ctx, cancel := context.WithTimeout(context.TODO(), timeout) defer cancel() @@ -2237,7 +2245,6 @@ func (cs *State) signVote( vote.Signature = v.Signature vote.Timestamp = v.Timestamp - return vote, err } @@ -2267,9 +2274,9 @@ func (cs *State) voteTime() time.Time { // sign the vote and publish on internalMsgQueue func (cs *State) signAddVote( - msgType tmproto.SignedMsgType, - hash []byte, - header types.PartSetHeader, + msgType tmproto.SignedMsgType, + hash []byte, + header types.PartSetHeader, ) *types.Vote { if cs.privValidator == nil { // the node does not have a key return nil diff --git a/privval/msgs_test.go b/privval/msgs_test.go index 0c764830f2e..19e6cd62375 100644 --- a/privval/msgs_test.go +++ b/privval/msgs_test.go @@ -35,8 +35,8 @@ func exampleVote() *types.Vote { }, ValidatorAddress: crypto.AddressHash([]byte("validator_address")), ValidatorIndex: 56789, - VoteExtension: types.VoteExtension { - AppDataToSign: []byte("app_data_to_sign"), + VoteExtension: types.VoteExtension{ + AppDataToSign: []byte("app_data_to_sign"), AppDataSelfAuthenticating: []byte("app_data_self_authenticating"), }, } @@ -88,8 +88,8 @@ func TestPrivvalVectors(t *testing.T) { {"pubKey request", &privproto.PubKeyRequest{}, "0a00"}, {"pubKey response", &privproto.PubKeyResponse{PubKey: ppk, Error: nil}, "12240a220a20556a436f1218d30942efe798420f51dc9b6a311b929c578257457d05c5fcf230"}, {"pubKey response with error", &privproto.PubKeyResponse{PubKey: cryptoproto.PublicKey{}, Error: remoteError}, "12140a0012100801120c697427732061206572726f72"}, - {"Vote Request", &privproto.SignVoteRequest{Vote: votepb}, "1aa8010aa501080110031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0608f49a8ded0532146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb034a2f0a0f6170705f646174615f7369676e6564121c6170705f646174615f73656c665f61757468656e7469636174696e67"}, - {"Vote Response", &privproto.SignedVoteResponse{Vote: *votepb, Error: nil}, "22a8010aa501080110031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0608f49a8ded0532146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb034a2f0a0f6170705f646174615f7369676e6564121c6170705f646174615f73656c665f61757468656e7469636174696e67"}, + {"Vote Request", &privproto.SignVoteRequest{Vote: votepb}, "1aa9010aa601080110031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0608f49a8ded0532146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb034a300a106170705f646174615f746f5f7369676e121c6170705f646174615f73656c665f61757468656e7469636174696e67"}, + {"Vote Response", &privproto.SignedVoteResponse{Vote: *votepb, Error: nil}, "22a9010aa601080110031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0608f49a8ded0532146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb034a300a106170705f646174615f746f5f7369676e121c6170705f646174615f73656c665f61757468656e7469636174696e67"}, {"Vote Response with error", &privproto.SignedVoteResponse{Vote: tmproto.Vote{}, Error: remoteError}, "22250a11220212002a0b088092b8c398feffffff0112100801120c697427732061206572726f72"}, {"Proposal Request", &privproto.SignProposalRequest{Proposal: proposalpb}, "2a700a6e08011003180220022a4a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a320608f49a8ded053a10697427732061207369676e6174757265"}, {"Proposal Response", &privproto.SignedProposalResponse{Proposal: *proposalpb, Error: nil}, "32700a6e08011003180220022a4a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a320608f49a8ded053a10697427732061207369676e6174757265"}, diff --git a/proxy/app_conn.go b/proxy/app_conn.go index 34ca30c24fc..405667e50d7 100644 --- a/proxy/app_conn.go +++ b/proxy/app_conn.go @@ -113,11 +113,15 @@ func (app *appConnConsensus) CommitSync(ctx context.Context) (*types.ResponseCom return app.appConn.CommitSync(ctx) } -func (app *appConnConsensus) ExtendVoteSync(ctx context.Context, req types.RequestExtendVote) (*types.ResponseExtendVote, error) { +func (app *appConnConsensus) ExtendVoteSync( + ctx context.Context, req types.RequestExtendVote, +) (*types.ResponseExtendVote, error) { return app.appConn.ExtendVoteSync(ctx, req) } -func (app *appConnConsensus) VerifyVoteExtensionSync(ctx context.Context, req types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) { +func (app *appConnConsensus) VerifyVoteExtensionSync( + ctx context.Context, req types.RequestVerifyVoteExtension, +) (*types.ResponseVerifyVoteExtension, error) { return app.appConn.VerifyVoteExtensionSync(ctx, req) } diff --git a/rpc/client/helpers.go b/rpc/client/helpers.go index 49598e8149d..afd146043c4 100644 --- a/rpc/client/helpers.go +++ b/rpc/client/helpers.go @@ -71,7 +71,7 @@ func WaitForOneEvent(c EventsClient, eventValue string, timeout time.Duration) ( // make sure to un-register after the test is over defer func() { if deferErr := c.UnsubscribeAll(ctx, subscriber); deferErr != nil { - panic(err) + panic(deferErr) } }() diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index f8962fb3575..7fe6039ef38 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -63,8 +63,8 @@ func GetClients(t *testing.T, ns service.Service, conf *config.Config) []client. require.NoError(t, err) return []client.Client{ - getHTTPClient(t, conf), ncl, + getHTTPClient(t, conf), } } diff --git a/state/execution.go b/state/execution.go index fb784c54924..c70382ea073 100644 --- a/state/execution.go +++ b/state/execution.go @@ -266,17 +266,35 @@ func (blockExec *BlockExecutor) ApplyBlock( } func (blockExec *BlockExecutor) ExtendVote(vote *types.Vote) (types.VoteExtension, error) { - ctx := context.TODO() - req := abci.RequestExtendVote{ - Vote: vote.ToProto(), - } + ctx := context.Background() + req := abci.RequestExtendVote{ + Vote: vote.ToProto(), + } + + resp, err := blockExec.proxyApp.ExtendVoteSync(ctx, req) + if err != nil { + return types.VoteExtension{}, err + } + + return types.VoteExtensionFromProto(resp.VoteExtension), nil +} + +func (blockExec *BlockExecutor) VerifyVoteExtension(vote *types.Vote) error { + ctx := context.Background() + req := abci.RequestVerifyVoteExtension{ + Vote: vote.ToProto(), + } + + resp, err := blockExec.proxyApp.VerifyVoteExtensionSync(ctx, req) + if err != nil { + return err + } - resp, err := blockExec.proxyApp.ExtendVoteSync(ctx, req) - if err != nil { - return types.VoteExtension{}, err - } + if resp.IsErr() { + return types.ErrVoteInvalidExtension + } - return types.VoteExtensionFromProto(resp.VoteExtension), nil + return nil } // Commit locks the mempool, runs the ABCI Commit message, and updates the diff --git a/state/execution_test.go b/state/execution_test.go index 8e29eb27466..c71e463e19d 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -78,14 +78,14 @@ func TestBeginBlockValidators(t *testing.T) { []byte("Signature1"), state.Validators.Validators[0].Address, now, - types.VoteExtensionToSign{}, - ) + types.VoteExtensionToSign{}, + ) commitSig1 = types.NewCommitSigForBlock( []byte("Signature2"), state.Validators.Validators[1].Address, now, - types.VoteExtensionToSign{}, - ) + types.VoteExtensionToSign{}, + ) absentSig = types.NewCommitSigAbsent() ) diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 029f7ba2ae1..2409db408c8 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -206,7 +206,7 @@ func (app *Application) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) a func (app *Application) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{BlockData: req.BlockData} //nolint:gosimple + return abci.ResponsePrepareProposal{BlockData: req.BlockData} } // validatorUpdates generates a validator set update. diff --git a/types/block.go b/types/block.go index 48f60e53f0c..33b6f3d1de2 100644 --- a/types/block.go +++ b/types/block.go @@ -728,6 +728,7 @@ func (cs *CommitSig) ToProto() *tmproto.CommitSig { ValidatorAddress: cs.ValidatorAddress, Timestamp: cs.Timestamp, Signature: cs.Signature, + VoteExtension: cs.VoteExtension.ToProto(), } } @@ -739,6 +740,7 @@ func (cs *CommitSig) FromProto(csp tmproto.CommitSig) error { cs.ValidatorAddress = csp.ValidatorAddress cs.Timestamp = csp.Timestamp cs.Signature = csp.Signature + cs.VoteExtension = VoteExtensionToSignFromProto(csp.VoteExtension) return cs.ValidateBasic() } diff --git a/types/vote.go b/types/vote.go index 9cc8169cf88..8a55695588a 100644 --- a/types/vote.go +++ b/types/vote.go @@ -52,12 +52,34 @@ type VoteExtensionToSign struct { AppDataToSign []byte `json:"app_data_to_sign"` } +func (ext VoteExtensionToSign) ToProto() *tmproto.VoteExtensionToSign { + if ext.IsEmpty() { + return nil + } + return &tmproto.VoteExtensionToSign{ + AppDataToSign: ext.AppDataToSign, + } +} + +func VoteExtensionToSignFromProto(pext *tmproto.VoteExtensionToSign) VoteExtensionToSign { + if pext == nil { + return VoteExtensionToSign{} + } + return VoteExtensionToSign{ + AppDataToSign: pext.AppDataToSign, + } +} + +func (ext VoteExtensionToSign) IsEmpty() bool { + return len(ext.AppDataToSign) == 0 +} + // BytesPacked returns a bytes-packed representation for // debugging and human identification. This function should // not be used for any logical operations. func (ext VoteExtensionToSign) BytesPacked() []byte { - res := make([]byte, len(ext.AppDataToSign)) - copy(res, ext.AppDataToSign) + res := []byte{} + res = append(res, ext.AppDataToSign...) return res } @@ -86,9 +108,9 @@ func (ext VoteExtension) ToSign() VoteExtensionToSign { // debugging and human identification. This function should // not be used for any logical operations. func (ext VoteExtension) BytesPacked() []byte { - res := make([]byte, len(ext.AppDataToSign)+len(ext.AppDataSelfAuthenticating)) - copy(res[:len(ext.AppDataToSign)], ext.AppDataToSign) - copy(res[len(ext.AppDataToSign):], ext.AppDataSelfAuthenticating) + res := []byte{} + res = append(res, ext.AppDataToSign...) + res = append(res, ext.AppDataSelfAuthenticating...) return res } @@ -257,11 +279,9 @@ func (vote *Vote) ValidateBasic() error { func (ext VoteExtension) Copy() VoteExtension { res := VoteExtension{ - AppDataToSign: make([]byte, len(ext.AppDataToSign)), - AppDataSelfAuthenticating: make([]byte, len(ext.AppDataSelfAuthenticating)), + AppDataToSign: ext.AppDataToSign, + AppDataSelfAuthenticating: ext.AppDataSelfAuthenticating, } - copy(res.AppDataToSign, ext.AppDataToSign) - copy(res.AppDataSelfAuthenticating, ext.AppDataSelfAuthenticating) return res } diff --git a/types/vote_set.go b/types/vote_set.go index b064f2c07ca..e67d83eacd3 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -610,6 +610,7 @@ func (voteSet *VoteSet) MakeCommit() *Commit { if commitSig.ForBlock() && !v.BlockID.Equals(*voteSet.maj23) { commitSig = NewCommitSigAbsent() } + commitSigs[i] = commitSig }