diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c871571be..ce6958eab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: with: go-version: "1.17" - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.go @@ -45,7 +45,7 @@ jobs: with: go-version: "1.17" - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.go @@ -67,7 +67,7 @@ jobs: with: go-version: "1.17" - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.go diff --git a/.github/workflows/docs-toc.yml b/.github/workflows/docs-toc.yml index 940df7c8c..fbe759877 100644 --- a/.github/workflows/docs-toc.yml +++ b/.github/workflows/docs-toc.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | docs/architecture/** diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 124d06f5a..6666999fc 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -18,7 +18,7 @@ jobs: with: go-version: '1.17' - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.go diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 332f55705..359514426 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/setup-go@v3 with: go-version: '^1.17' - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.go diff --git a/.github/workflows/markdown-links.yml b/.github/workflows/markdown-links.yml index 356eb3f31..7af7e3ce9 100644 --- a/.github/workflows/markdown-links.yml +++ b/.github/workflows/markdown-links.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.md diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1ef5759e5..7ee964d21 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: with: go-version: "1.17" - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.go @@ -42,7 +42,7 @@ jobs: needs: tests steps: - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6 with: PATTERNS: | **/**.go diff --git a/abci/client/grpc_client.go b/abci/client/grpc_client.go index 251939253..5890d5f05 100644 --- a/abci/client/grpc_client.go +++ b/abci/client/grpc_client.go @@ -52,6 +52,9 @@ func dialerFunc(ctx context.Context, addr string) (net.Conn, error) { } func (cli *grpcClient) OnStart(ctx context.Context) error { + timer := time.NewTimer(0) + defer timer.Stop() + RETRY_LOOP: for { conn, err := grpc.Dial(cli.addr, @@ -63,8 +66,13 @@ RETRY_LOOP: return err } cli.logger.Error(fmt.Sprintf("abci.grpcClient failed to connect to %v. Retrying...\n", cli.addr), "err", err) - time.Sleep(time.Second * dialRetryIntervalSeconds) - continue RETRY_LOOP + timer.Reset(time.Second * dialRetryIntervalSeconds) + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + continue RETRY_LOOP + } } cli.logger.Info("Dialed server. Waiting for echo.", "addr", cli.addr) @@ -82,7 +90,13 @@ RETRY_LOOP: } cli.logger.Error("Echo failed", "err", err) - time.Sleep(time.Second * echoRetryIntervalSeconds) + timer.Reset(time.Second * echoRetryIntervalSeconds) + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + continue ENSURE_CONNECTED + } } cli.client = client diff --git a/abci/client/socket_client.go b/abci/client/socket_client.go index dcf5fa519..b06fb6718 100644 --- a/abci/client/socket_client.go +++ b/abci/client/socket_client.go @@ -64,6 +64,8 @@ func (cli *socketClient) OnStart(ctx context.Context) error { err error conn net.Conn ) + timer := time.NewTimer(0) + defer timer.Stop() for { conn, err = tmnet.Connect(cli.addr) @@ -73,8 +75,15 @@ func (cli *socketClient) OnStart(ctx context.Context) error { } cli.logger.Error(fmt.Sprintf("abci.socketClient failed to connect to %v. Retrying after %vs...", cli.addr, dialRetryIntervalSeconds), "err", err) - time.Sleep(time.Second * dialRetryIntervalSeconds) - continue + + timer.Reset(time.Second * dialRetryIntervalSeconds) + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + continue + } + } cli.conn = conn @@ -90,11 +99,7 @@ func (cli *socketClient) OnStop() { if cli.conn != nil { cli.conn.Close() } - - // this timeout is arbitrary. - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - cli.drainQueue(ctx) + cli.drainQueue() } // Error returns an error if the client was stopped abruptly. @@ -113,12 +118,6 @@ func (cli *socketClient) sendRequestsRoutine(ctx context.Context, conn io.Writer case <-ctx.Done(): return case reqres := <-cli.reqQueue: - if ctx.Err() != nil { - return - } - - cli.willSendReq(reqres) - if err := types.WriteMessage(reqres.Request, bw); err != nil { cli.stopForError(fmt.Errorf("write to buffer: %w", err)) return @@ -162,6 +161,11 @@ func (cli *socketClient) recvResponseRoutine(ctx context.Context, conn io.Reader func (cli *socketClient) willSendReq(reqres *requestAndResponse) { cli.mtx.Lock() defer cli.mtx.Unlock() + + if !cli.IsRunning() { + return + } + cli.reqSent.PushBack(reqres) } @@ -189,6 +193,47 @@ func (cli *socketClient) didRecvResponse(res *types.Response) error { //---------------------------------------- +func (cli *socketClient) doRequest(ctx context.Context, req *types.Request) (*types.Response, error) { + if !cli.IsRunning() { + return nil, errors.New("client has stopped") + } + + reqres := makeReqRes(req) + cli.willSendReq(reqres) + + select { + case cli.reqQueue <- reqres: + case <-ctx.Done(): + return nil, fmt.Errorf("can't queue req: %w", ctx.Err()) + } + + select { + case <-reqres.signal: + if err := cli.Error(); err != nil { + return nil, err + } + + return reqres.Response, nil + case <-ctx.Done(): + return nil, ctx.Err() + } +} + +// drainQueue marks as complete and discards all remaining pending requests +// from the queue. +func (cli *socketClient) drainQueue() { + cli.mtx.Lock() + defer cli.mtx.Unlock() + + // mark all in-flight messages as resolved (they will get cli.Error()) + for req := cli.reqSent.Front(); req != nil; req = req.Next() { + reqres := req.Value.(*requestAndResponse) + reqres.markDone() + } +} + +//---------------------------------------- + func (cli *socketClient) Flush(ctx context.Context) error { _, err := cli.doRequest(ctx, types.ToRequestFlush()) if err != nil { @@ -319,58 +364,6 @@ func (cli *socketClient) FinalizeBlock(ctx context.Context, req types.RequestFin //---------------------------------------- -func (cli *socketClient) doRequest(ctx context.Context, req *types.Request) (*types.Response, error) { - reqres := makeReqRes(req) - - select { - case cli.reqQueue <- reqres: - case <-ctx.Done(): - return nil, fmt.Errorf("can't queue req: %w", ctx.Err()) - } - - select { - case <-reqres.signal: - if err := cli.Error(); err != nil { - return nil, err - } - - return reqres.Response, nil - case <-ctx.Done(): - return nil, ctx.Err() - } -} - -// drainQueue marks as complete and discards all remaining pending requests -// from the queue. -func (cli *socketClient) drainQueue(ctx context.Context) { - cli.mtx.Lock() - defer cli.mtx.Unlock() - - // mark all in-flight messages as resolved (they will get cli.Error()) - for req := cli.reqSent.Front(); req != nil; req = req.Next() { - reqres := req.Value.(*requestAndResponse) - reqres.markDone() - } - - // Mark all queued messages as resolved. - // - // TODO(creachadair): We can't simply range the channel, because it is never - // closed, and the writer continues to add work. - // See https://github.com/tendermint/tendermint/issues/6996. - for { - select { - case <-ctx.Done(): - return - case reqres := <-cli.reqQueue: - reqres.markDone() - default: - return - } - } -} - -//---------------------------------------- - func resMatchesReq(req *types.Request, res *types.Response) (ok bool) { switch req.Value.(type) { case *types.Request_Echo: diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index 2a6e8aa19..e908ea98f 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -1,14 +1,11 @@ package kvstore import ( - "bytes" - dbm "github.com/tendermint/tm-db" "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" cryptoproto "github.com/tendermint/tendermint/proto/tendermint/crypto" - ptypes "github.com/tendermint/tendermint/proto/tendermint/types" ) const ( @@ -45,34 +42,3 @@ func (app *PersistentKVStoreApplication) OfferSnapshot(req types.RequestOfferSna func (app *PersistentKVStoreApplication) ApplySnapshotChunk(req types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk { return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_ABORT} } - -func (app *PersistentKVStoreApplication) ExtendVote(req types.RequestExtendVote) types.ResponseExtendVote { - return types.ResponseExtendVote{VoteExtension: ConstructVoteExtension(req.Vote.ValidatorAddress)} -} - -func (app *PersistentKVStoreApplication) VerifyVoteExtension(req types.RequestVerifyVoteExtension) types.ResponseVerifyVoteExtension { - return types.RespondVerifyVoteExtension(app.verifyExtension(req.Vote.ValidatorAddress, req.Vote.VoteExtension)) -} - -// ----------------------------- - -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/types.go b/abci/types/types.go index d74a2289a..d13947d1a 100644 --- a/abci/types/types.go +++ b/abci/types/types.go @@ -5,8 +5,6 @@ import ( "encoding/json" "github.com/gogo/protobuf/jsonpb" - - types "github.com/tendermint/tendermint/proto/tendermint/types" ) const ( @@ -157,15 +155,6 @@ 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 { status := ResponseVerifyVoteExtension_REJECT if ok { diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 9e7955462..04c7ee9a6 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -1521,7 +1521,8 @@ func (m *RequestProcessProposal) GetProposerAddress() []byte { // Extends a vote with application-side injection type RequestExtendVote struct { - Vote *types1.Vote `protobuf:"bytes,1,opt,name=vote,proto3" json:"vote,omitempty"` + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` } func (m *RequestExtendVote) Reset() { *m = RequestExtendVote{} } @@ -1557,16 +1558,26 @@ func (m *RequestExtendVote) XXX_DiscardUnknown() { var xxx_messageInfo_RequestExtendVote proto.InternalMessageInfo -func (m *RequestExtendVote) GetVote() *types1.Vote { +func (m *RequestExtendVote) GetHash() []byte { if m != nil { - return m.Vote + return m.Hash } return nil } +func (m *RequestExtendVote) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + // Verify the vote extension type RequestVerifyVoteExtension struct { - Vote *types1.Vote `protobuf:"bytes,1,opt,name=vote,proto3" json:"vote,omitempty"` + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + ValidatorAddress []byte `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` + Height int64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` + VoteExtension []byte `protobuf:"bytes,4,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` } func (m *RequestVerifyVoteExtension) Reset() { *m = RequestVerifyVoteExtension{} } @@ -1602,9 +1613,30 @@ func (m *RequestVerifyVoteExtension) XXX_DiscardUnknown() { var xxx_messageInfo_RequestVerifyVoteExtension proto.InternalMessageInfo -func (m *RequestVerifyVoteExtension) GetVote() *types1.Vote { +func (m *RequestVerifyVoteExtension) GetHash() []byte { if m != nil { - return m.Vote + return m.Hash + } + return nil +} + +func (m *RequestVerifyVoteExtension) GetValidatorAddress() []byte { + if m != nil { + return m.ValidatorAddress + } + return nil +} + +func (m *RequestVerifyVoteExtension) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *RequestVerifyVoteExtension) GetVoteExtension() []byte { + if m != nil { + return m.VoteExtension } return nil } @@ -3131,7 +3163,7 @@ func (m *ResponseProcessProposal) GetConsensusParamUpdates() *types1.ConsensusPa } type ResponseExtendVote struct { - VoteExtension *types1.VoteExtension `protobuf:"bytes,1,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` + VoteExtension []byte `protobuf:"bytes,1,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` } func (m *ResponseExtendVote) Reset() { *m = ResponseExtendVote{} } @@ -3167,7 +3199,7 @@ func (m *ResponseExtendVote) XXX_DiscardUnknown() { var xxx_messageInfo_ResponseExtendVote proto.InternalMessageInfo -func (m *ResponseExtendVote) GetVoteExtension() *types1.VoteExtension { +func (m *ResponseExtendVote) GetVoteExtension() []byte { if m != nil { return m.VoteExtension } @@ -3354,8 +3386,14 @@ func (m *CommitInfo) GetVotes() []VoteInfo { return nil } +// ExtendedCommitInfo is similar to CommitInfo except that it is only used in +// the PrepareProposal request such that Tendermint can provide vote extensions +// to the application. type ExtendedCommitInfo struct { - Round int32 `protobuf:"varint,1,opt,name=round,proto3" json:"round,omitempty"` + // The round at which the block proposer decided in the previous height. + Round int32 `protobuf:"varint,1,opt,name=round,proto3" json:"round,omitempty"` + // List of validators' addresses in the last validator set with their voting + // information, including vote extensions. Votes []ExtendedVoteInfo `protobuf:"bytes,2,rep,name=votes,proto3" json:"votes"` } @@ -3908,10 +3946,14 @@ func (m *VoteInfo) GetSignedLastBlock() bool { return false } +// ExtendedVoteInfo type ExtendedVoteInfo struct { - Validator Validator `protobuf:"bytes,1,opt,name=validator,proto3" json:"validator"` - SignedLastBlock bool `protobuf:"varint,2,opt,name=signed_last_block,json=signedLastBlock,proto3" json:"signed_last_block,omitempty"` - VoteExtension []byte `protobuf:"bytes,3,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` + // The validator that sent the vote. + Validator Validator `protobuf:"bytes,1,opt,name=validator,proto3" json:"validator"` + // Indicates whether the validator signed the last block, allowing for rewards based on validator availability. + SignedLastBlock bool `protobuf:"varint,2,opt,name=signed_last_block,json=signedLastBlock,proto3" json:"signed_last_block,omitempty"` + // Non-deterministic extension provided by the sending validator's application. + VoteExtension []byte `protobuf:"bytes,3,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` } func (m *ExtendedVoteInfo) Reset() { *m = ExtendedVoteInfo{} } @@ -4193,223 +4235,224 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3451 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0x4b, 0x73, 0x23, 0xd5, - 0xf5, 0xd7, 0xfb, 0x71, 0x64, 0x3d, 0x7c, 0x6d, 0x06, 0x8d, 0x98, 0xb1, 0x87, 0x9e, 0x02, 0x66, - 0x06, 0xf0, 0xf0, 0x9f, 0xf9, 0x0f, 0x0c, 0x01, 0x42, 0xd9, 0xb2, 0x8c, 0x3c, 0xe3, 0xb1, 0x4d, - 0x5b, 0x36, 0x45, 0x42, 0xa6, 0x69, 0xa9, 0xaf, 0xad, 0x66, 0x24, 0x75, 0xd3, 0xdd, 0x32, 0x32, - 0xcb, 0x50, 0x6c, 0xa8, 0x54, 0x85, 0x4d, 0x2a, 0xc9, 0x82, 0x5d, 0x52, 0x95, 0x7c, 0x83, 0xac, - 0xb2, 0xca, 0x82, 0x45, 0x16, 0xac, 0x92, 0x54, 0x16, 0x24, 0x05, 0xbb, 0x7c, 0x81, 0xec, 0x92, - 0xd4, 0x7d, 0xf4, 0x53, 0x6a, 0xa9, 0xc5, 0x00, 0x55, 0xa9, 0xb0, 0xd3, 0x3d, 0x7d, 0xce, 0xe9, - 0xbe, 0xf7, 0x9e, 0x7b, 0x1e, 0xbf, 0x73, 0x05, 0x8f, 0x59, 0x78, 0xa0, 0x60, 0xa3, 0xaf, 0x0e, - 0xac, 0xeb, 0x72, 0xbb, 0xa3, 0x5e, 0xb7, 0xce, 0x74, 0x6c, 0xae, 0xe9, 0x86, 0x66, 0x69, 0xa8, - 0xec, 0x3e, 0x5c, 0x23, 0x0f, 0x6b, 0x17, 0x3d, 0xdc, 0x1d, 0xe3, 0x4c, 0xb7, 0xb4, 0xeb, 0xba, - 0xa1, 0x69, 0xc7, 0x8c, 0xbf, 0x76, 0xc1, 0xf3, 0x98, 0xea, 0xf1, 0x6a, 0xf3, 0x3d, 0xe5, 0xc2, - 0x0f, 0xf0, 0x99, 0xfd, 0xf4, 0xe2, 0x98, 0xac, 0x2e, 0x1b, 0x72, 0xdf, 0x7e, 0xbc, 0x7a, 0xa2, - 0x69, 0x27, 0x3d, 0x7c, 0x9d, 0x8e, 0xda, 0xc3, 0xe3, 0xeb, 0x96, 0xda, 0xc7, 0xa6, 0x25, 0xf7, - 0x75, 0xce, 0xb0, 0x7c, 0xa2, 0x9d, 0x68, 0xf4, 0xe7, 0x75, 0xf2, 0x8b, 0x51, 0x85, 0x7f, 0x03, - 0x64, 0x45, 0xfc, 0xee, 0x10, 0x9b, 0x16, 0xba, 0x01, 0x29, 0xdc, 0xe9, 0x6a, 0xd5, 0xf8, 0xa5, - 0xf8, 0x95, 0xc2, 0x8d, 0x0b, 0x6b, 0x81, 0xc9, 0xad, 0x71, 0xbe, 0x46, 0xa7, 0xab, 0x35, 0x63, - 0x22, 0xe5, 0x45, 0xb7, 0x20, 0x7d, 0xdc, 0x1b, 0x9a, 0xdd, 0x6a, 0x82, 0x0a, 0x5d, 0x0c, 0x13, - 0xda, 0x22, 0x4c, 0xcd, 0x98, 0xc8, 0xb8, 0xc9, 0xab, 0xd4, 0xc1, 0xb1, 0x56, 0x4d, 0x4e, 0x7f, - 0xd5, 0xf6, 0xe0, 0x98, 0xbe, 0x8a, 0xf0, 0xa2, 0x0d, 0x00, 0x75, 0xa0, 0x5a, 0x52, 0xa7, 0x2b, - 0xab, 0x83, 0x6a, 0x8a, 0x4a, 0x3e, 0x1e, 0x2e, 0xa9, 0x5a, 0x75, 0xc2, 0xd8, 0x8c, 0x89, 0x79, - 0xd5, 0x1e, 0x90, 0xcf, 0x7d, 0x77, 0x88, 0x8d, 0xb3, 0x6a, 0x7a, 0xfa, 0xe7, 0xbe, 0x4e, 0x98, - 0xc8, 0xe7, 0x52, 0x6e, 0xb4, 0x0d, 0x85, 0x36, 0x3e, 0x51, 0x07, 0x52, 0xbb, 0xa7, 0x75, 0x1e, - 0x54, 0x33, 0x54, 0x58, 0x08, 0x13, 0xde, 0x20, 0xac, 0x1b, 0x84, 0x73, 0x23, 0x51, 0x8d, 0x37, - 0x63, 0x22, 0xb4, 0x1d, 0x0a, 0x7a, 0x19, 0x72, 0x9d, 0x2e, 0xee, 0x3c, 0x90, 0xac, 0x51, 0x35, - 0x4b, 0xf5, 0xac, 0x86, 0xe9, 0xa9, 0x13, 0xbe, 0xd6, 0xa8, 0x19, 0x13, 0xb3, 0x1d, 0xf6, 0x13, - 0x6d, 0x01, 0x28, 0xb8, 0xa7, 0x9e, 0x62, 0x83, 0xc8, 0xe7, 0xa6, 0xaf, 0xc1, 0x26, 0xe3, 0x6c, - 0x8d, 0xf8, 0x67, 0xe4, 0x15, 0x9b, 0x80, 0xea, 0x90, 0xc7, 0x03, 0x85, 0x4f, 0x27, 0x4f, 0xd5, - 0x5c, 0x0a, 0xdd, 0xef, 0x81, 0xe2, 0x9d, 0x4c, 0x0e, 0xf3, 0x31, 0xba, 0x0d, 0x99, 0x8e, 0xd6, - 0xef, 0xab, 0x56, 0x15, 0xa8, 0x86, 0x95, 0xd0, 0x89, 0x50, 0xae, 0x66, 0x4c, 0xe4, 0xfc, 0x68, - 0x17, 0x4a, 0x3d, 0xd5, 0xb4, 0x24, 0x73, 0x20, 0xeb, 0x66, 0x57, 0xb3, 0xcc, 0x6a, 0x81, 0x6a, - 0x78, 0x22, 0x4c, 0xc3, 0x8e, 0x6a, 0x5a, 0x07, 0x36, 0x73, 0x33, 0x26, 0x16, 0x7b, 0x5e, 0x02, - 0xd1, 0xa7, 0x1d, 0x1f, 0x63, 0xc3, 0x51, 0x58, 0x5d, 0x98, 0xae, 0x6f, 0x8f, 0x70, 0xdb, 0xf2, - 0x44, 0x9f, 0xe6, 0x25, 0xa0, 0x1f, 0xc2, 0x52, 0x4f, 0x93, 0x15, 0x47, 0x9d, 0xd4, 0xe9, 0x0e, - 0x07, 0x0f, 0xaa, 0x45, 0xaa, 0xf4, 0x6a, 0xe8, 0x47, 0x6a, 0xb2, 0x62, 0xab, 0xa8, 0x13, 0x81, - 0x66, 0x4c, 0x5c, 0xec, 0x05, 0x89, 0xe8, 0x3e, 0x2c, 0xcb, 0xba, 0xde, 0x3b, 0x0b, 0x6a, 0x2f, - 0x51, 0xed, 0xd7, 0xc2, 0xb4, 0xaf, 0x13, 0x99, 0xa0, 0x7a, 0x24, 0x8f, 0x51, 0x51, 0x0b, 0x2a, - 0xba, 0x81, 0x75, 0xd9, 0xc0, 0x92, 0x6e, 0x68, 0xba, 0x66, 0xca, 0xbd, 0x6a, 0x99, 0xea, 0x7e, - 0x2a, 0x4c, 0xf7, 0x3e, 0xe3, 0xdf, 0xe7, 0xec, 0xcd, 0x98, 0x58, 0xd6, 0xfd, 0x24, 0xa6, 0x55, - 0xeb, 0x60, 0xd3, 0x74, 0xb5, 0x56, 0x66, 0x69, 0xa5, 0xfc, 0x7e, 0xad, 0x3e, 0x12, 0x6a, 0x40, - 0x01, 0x8f, 0x88, 0xb8, 0x74, 0xaa, 0x59, 0xb8, 0xba, 0x38, 0xfd, 0x60, 0x35, 0x28, 0xeb, 0x91, - 0x66, 0x61, 0x72, 0xa8, 0xb0, 0x33, 0x42, 0x32, 0x3c, 0x72, 0x8a, 0x0d, 0xf5, 0xf8, 0x8c, 0xaa, - 0x91, 0xe8, 0x13, 0x53, 0xd5, 0x06, 0x55, 0x44, 0x15, 0x3e, 0x1d, 0xa6, 0xf0, 0x88, 0x0a, 0x11, - 0x15, 0x0d, 0x5b, 0xa4, 0x19, 0x13, 0x97, 0x4e, 0xc7, 0xc9, 0xc4, 0xc4, 0x8e, 0xd5, 0x81, 0xdc, - 0x53, 0xdf, 0xc7, 0xfc, 0xd8, 0x2c, 0x4d, 0x37, 0xb1, 0x2d, 0xce, 0x4d, 0xcf, 0x0a, 0x31, 0xb1, - 0x63, 0x2f, 0x61, 0x23, 0x0b, 0xe9, 0x53, 0xb9, 0x37, 0xc4, 0xc2, 0x53, 0x50, 0xf0, 0x38, 0x56, - 0x54, 0x85, 0x6c, 0x1f, 0x9b, 0xa6, 0x7c, 0x82, 0xa9, 0x1f, 0xce, 0x8b, 0xf6, 0x50, 0x28, 0xc1, - 0x82, 0xd7, 0x99, 0x0a, 0x1f, 0xc7, 0x1d, 0x49, 0xe2, 0x27, 0x89, 0xe4, 0x29, 0x36, 0xe8, 0xb4, - 0xb9, 0x24, 0x1f, 0xa2, 0xcb, 0x50, 0xa4, 0x9f, 0x2c, 0xd9, 0xcf, 0x89, 0xb3, 0x4e, 0x89, 0x0b, - 0x94, 0x78, 0xc4, 0x99, 0x56, 0xa1, 0xa0, 0xdf, 0xd0, 0x1d, 0x96, 0x24, 0x65, 0x01, 0xfd, 0x86, - 0x6e, 0x33, 0x3c, 0x0e, 0x0b, 0x64, 0x7e, 0x0e, 0x47, 0x8a, 0xbe, 0xa4, 0x40, 0x68, 0x9c, 0x45, - 0xf8, 0x63, 0x02, 0x2a, 0x41, 0x07, 0x8c, 0x6e, 0x43, 0x8a, 0xc4, 0x22, 0x1e, 0x56, 0x6a, 0x6b, - 0x2c, 0x50, 0xad, 0xd9, 0x81, 0x6a, 0xad, 0x65, 0x07, 0xaa, 0x8d, 0xdc, 0xa7, 0x9f, 0xaf, 0xc6, - 0x3e, 0xfe, 0xdb, 0x6a, 0x5c, 0xa4, 0x12, 0xe8, 0x3c, 0xf1, 0x95, 0xb2, 0x3a, 0x90, 0x54, 0x85, - 0x7e, 0x72, 0x9e, 0x38, 0x42, 0x59, 0x1d, 0x6c, 0x2b, 0x68, 0x07, 0x2a, 0x1d, 0x6d, 0x60, 0xe2, - 0x81, 0x39, 0x34, 0x25, 0x16, 0x08, 0x79, 0x30, 0xf1, 0xb9, 0x43, 0x16, 0x5e, 0xeb, 0x36, 0xe7, - 0x3e, 0x65, 0x14, 0xcb, 0x1d, 0x3f, 0x81, 0xb8, 0xd5, 0x53, 0xb9, 0xa7, 0x2a, 0xb2, 0xa5, 0x19, - 0x66, 0x35, 0x75, 0x29, 0x39, 0xd1, 0x1f, 0x1e, 0xd9, 0x2c, 0x87, 0xba, 0x22, 0x5b, 0x78, 0x23, - 0x45, 0x3e, 0x57, 0xf4, 0x48, 0xa2, 0x27, 0xa1, 0x2c, 0xeb, 0xba, 0x64, 0x5a, 0xb2, 0x85, 0xa5, - 0xf6, 0x99, 0x85, 0x4d, 0x1a, 0x68, 0x16, 0xc4, 0xa2, 0xac, 0xeb, 0x07, 0x84, 0xba, 0x41, 0x88, - 0xe8, 0x09, 0x28, 0x91, 0x98, 0xa4, 0xca, 0x3d, 0xa9, 0x8b, 0xd5, 0x93, 0xae, 0x45, 0x43, 0x4a, - 0x52, 0x2c, 0x72, 0x6a, 0x93, 0x12, 0x05, 0xc5, 0xd9, 0x71, 0x1a, 0x8f, 0x10, 0x82, 0x94, 0x22, - 0x5b, 0x32, 0x5d, 0xc9, 0x05, 0x91, 0xfe, 0x26, 0x34, 0x5d, 0xb6, 0xba, 0x7c, 0x7d, 0xe8, 0x6f, - 0x74, 0x0e, 0x32, 0x5c, 0x6d, 0x92, 0xaa, 0xe5, 0x23, 0xb4, 0x0c, 0x69, 0xdd, 0xd0, 0x4e, 0x31, - 0xdd, 0xba, 0x9c, 0xc8, 0x06, 0xc2, 0x07, 0x09, 0x58, 0x1c, 0x8b, 0x5c, 0x44, 0x6f, 0x57, 0x36, - 0xbb, 0xf6, 0xbb, 0xc8, 0x6f, 0xf4, 0x3c, 0xd1, 0x2b, 0x2b, 0xd8, 0xe0, 0xd1, 0xbe, 0x3a, 0xbe, - 0xd4, 0x4d, 0xfa, 0x9c, 0x2f, 0x0d, 0xe7, 0x46, 0x77, 0xa1, 0xd2, 0x93, 0x4d, 0x4b, 0x62, 0xde, - 0x5f, 0xf2, 0x44, 0xfe, 0xc7, 0xc6, 0x16, 0x99, 0xc5, 0x0a, 0x62, 0xd0, 0x5c, 0x49, 0x89, 0x88, - 0xba, 0x54, 0x74, 0x08, 0xcb, 0xed, 0xb3, 0xf7, 0xe5, 0x81, 0xa5, 0x0e, 0xb0, 0x34, 0xb6, 0x6b, - 0xe3, 0xa9, 0xc4, 0x3d, 0xd5, 0x6c, 0xe3, 0xae, 0x7c, 0xaa, 0x6a, 0xf6, 0x67, 0x2d, 0x39, 0xf2, - 0xce, 0x8e, 0x9a, 0x82, 0x08, 0x25, 0x7f, 0xd8, 0x45, 0x25, 0x48, 0x58, 0x23, 0x3e, 0xff, 0x84, - 0x35, 0x42, 0xcf, 0x41, 0x8a, 0xcc, 0x91, 0xce, 0xbd, 0x34, 0xe1, 0x45, 0x5c, 0xae, 0x75, 0xa6, - 0x63, 0x91, 0x72, 0x0a, 0x82, 0x73, 0x1a, 0x9c, 0x50, 0x1c, 0xd4, 0x2a, 0x5c, 0x85, 0x72, 0x20, - 0xce, 0x7a, 0xb6, 0x2f, 0xee, 0xdd, 0x3e, 0xa1, 0x0c, 0x45, 0x5f, 0x40, 0x15, 0xce, 0xc1, 0xf2, - 0xa4, 0xf8, 0x28, 0x74, 0x1d, 0xba, 0x2f, 0xce, 0xa1, 0x5b, 0x90, 0x73, 0x02, 0x24, 0x3b, 0x8d, - 0xe7, 0xc7, 0x66, 0x61, 0x33, 0x8b, 0x0e, 0x2b, 0x39, 0x86, 0xc4, 0xaa, 0xa9, 0x39, 0x24, 0xe8, - 0x87, 0x67, 0x65, 0x5d, 0x6f, 0xca, 0x66, 0x57, 0x78, 0x1b, 0xaa, 0x61, 0xc1, 0x2f, 0x30, 0x8d, - 0x94, 0x63, 0x85, 0xe7, 0x20, 0x73, 0xac, 0x19, 0x7d, 0xd9, 0xa2, 0xca, 0x8a, 0x22, 0x1f, 0x11, - 0xeb, 0x64, 0x81, 0x30, 0x49, 0xc9, 0x6c, 0x20, 0x48, 0x70, 0x3e, 0x34, 0x00, 0x12, 0x11, 0x75, - 0xa0, 0x60, 0xb6, 0x9e, 0x45, 0x91, 0x0d, 0x5c, 0x45, 0xec, 0x63, 0xd9, 0x80, 0xbc, 0xd6, 0xa4, - 0x73, 0xa5, 0xfa, 0xf3, 0x22, 0x1f, 0x09, 0xbf, 0x4d, 0xc2, 0xb9, 0xc9, 0x61, 0x10, 0x5d, 0x82, - 0x85, 0xbe, 0x3c, 0x92, 0xac, 0x11, 0x3f, 0xcb, 0x6c, 0x3b, 0xa0, 0x2f, 0x8f, 0x5a, 0x23, 0x76, - 0x90, 0x2b, 0x90, 0xb4, 0x46, 0x66, 0x35, 0x71, 0x29, 0x79, 0x65, 0x41, 0x24, 0x3f, 0xd1, 0x21, - 0x2c, 0xf6, 0xb4, 0x8e, 0xdc, 0x93, 0x3c, 0x16, 0xcf, 0x8d, 0xfd, 0xf2, 0xd8, 0x62, 0xb3, 0x80, - 0x86, 0x95, 0x31, 0xa3, 0x2f, 0x53, 0x1d, 0x3b, 0x8e, 0xe5, 0x7f, 0x43, 0x56, 0xef, 0xd9, 0xa3, - 0xb4, 0xcf, 0x53, 0xd8, 0x3e, 0x3b, 0x33, 0xb7, 0xcf, 0x7e, 0x0e, 0x96, 0x07, 0x78, 0x64, 0x79, - 0xbe, 0x91, 0x19, 0x4e, 0x96, 0xee, 0x05, 0x22, 0xcf, 0xdc, 0xf7, 0x13, 0x1b, 0x42, 0x57, 0x69, - 0x66, 0xa1, 0x6b, 0x26, 0x36, 0x24, 0x59, 0x51, 0x0c, 0x6c, 0x9a, 0x34, 0xb3, 0x5d, 0xa0, 0xe9, - 0x02, 0xa5, 0xaf, 0x33, 0xb2, 0xf0, 0x4b, 0xef, 0x5e, 0xf9, 0x33, 0x09, 0xbe, 0x13, 0x71, 0x77, - 0x27, 0x0e, 0x60, 0x99, 0xcb, 0x2b, 0xbe, 0xcd, 0x48, 0x44, 0xf5, 0x3c, 0xc8, 0x16, 0x8f, 0xb0, - 0x0f, 0xc9, 0x87, 0xdb, 0x07, 0xdb, 0xdb, 0xa6, 0x3c, 0xde, 0xf6, 0xbf, 0x6c, 0x6f, 0x5e, 0x75, - 0xa2, 0x88, 0x9b, 0xa6, 0xa1, 0x6b, 0x90, 0xa2, 0x89, 0x1d, 0xf3, 0x36, 0xe7, 0xc6, 0xe3, 0x05, - 0xe1, 0x12, 0x29, 0x8f, 0xd0, 0x84, 0x5a, 0x78, 0x5a, 0x36, 0x97, 0xa6, 0x9f, 0x25, 0x1d, 0x07, - 0xe8, 0xcb, 0xc2, 0x26, 0x18, 0xc9, 0xeb, 0xb0, 0xa4, 0xe0, 0x8e, 0xaa, 0x7c, 0x55, 0x1b, 0x59, - 0xe4, 0xd2, 0xdf, 0x99, 0x48, 0x04, 0x13, 0xf9, 0x73, 0x01, 0x72, 0x22, 0x36, 0x75, 0x92, 0x7d, - 0xa1, 0x0d, 0xc8, 0xe3, 0x51, 0x07, 0xeb, 0x96, 0x9d, 0xb0, 0x4e, 0x4e, 0xfc, 0x19, 0x77, 0xc3, - 0xe6, 0x24, 0x65, 0xac, 0x23, 0x86, 0x6e, 0x72, 0xc4, 0x22, 0x1c, 0x7c, 0xe0, 0xe2, 0x5e, 0xc8, - 0xe2, 0x79, 0x1b, 0xb2, 0x48, 0x86, 0x56, 0xad, 0x4c, 0x2a, 0x80, 0x59, 0xdc, 0xe4, 0x98, 0x45, - 0x6a, 0xc6, 0xcb, 0x7c, 0xa0, 0x45, 0xdd, 0x07, 0x5a, 0xa4, 0x67, 0x4c, 0x33, 0x04, 0xb5, 0x78, - 0xde, 0x46, 0x2d, 0x32, 0x33, 0xbe, 0x38, 0x00, 0x5b, 0xdc, 0xf1, 0xc3, 0x16, 0xd9, 0x90, 0x28, - 0x64, 0x4b, 0x4f, 0xc5, 0x2d, 0x5e, 0xf1, 0xe0, 0x16, 0xb9, 0x50, 0xc0, 0x80, 0x29, 0x9a, 0x00, - 0x5c, 0xbc, 0xe6, 0x03, 0x2e, 0xf2, 0x33, 0xd6, 0x61, 0x0a, 0x72, 0xb1, 0xe9, 0x45, 0x2e, 0x20, - 0x14, 0x00, 0xe1, 0xfb, 0x1e, 0x06, 0x5d, 0xbc, 0xe8, 0x40, 0x17, 0x85, 0x50, 0x0c, 0x86, 0xcf, - 0x25, 0x88, 0x5d, 0xec, 0x8d, 0x61, 0x17, 0x0c, 0x6b, 0x78, 0x32, 0x54, 0xc5, 0x0c, 0xf0, 0x62, - 0x6f, 0x0c, 0xbc, 0x28, 0xce, 0x50, 0x38, 0x03, 0xbd, 0x78, 0x6b, 0x32, 0x7a, 0x11, 0x8e, 0x2f, - 0xf0, 0xcf, 0x8c, 0x06, 0x5f, 0x48, 0x21, 0xf0, 0x45, 0x39, 0xb4, 0xd4, 0x66, 0xea, 0x23, 0xe3, - 0x17, 0x87, 0x13, 0xf0, 0x0b, 0x86, 0x34, 0x5c, 0x09, 0x55, 0x1e, 0x01, 0xc0, 0x38, 0x9c, 0x00, - 0x60, 0x2c, 0xce, 0x54, 0x3b, 0x13, 0xc1, 0xd8, 0xf2, 0x23, 0x18, 0x68, 0xc6, 0x19, 0x0b, 0x85, - 0x30, 0xda, 0x61, 0x10, 0x06, 0x83, 0x19, 0x9e, 0x09, 0xd5, 0x38, 0x07, 0x86, 0xb1, 0x37, 0x86, - 0x61, 0x2c, 0xcf, 0xb0, 0xb4, 0xa8, 0x20, 0xc6, 0x55, 0x12, 0xfc, 0x03, 0xae, 0x9a, 0xe4, 0xe1, - 0xd8, 0x30, 0x34, 0x83, 0xc3, 0x11, 0x6c, 0x20, 0x5c, 0x21, 0x45, 0xad, 0xeb, 0x96, 0xa7, 0x00, - 0x1e, 0xb4, 0xde, 0xf1, 0xb8, 0x62, 0xe1, 0x77, 0x71, 0x57, 0x96, 0xd6, 0x82, 0xde, 0x82, 0x38, - 0xcf, 0x0b, 0x62, 0x0f, 0x0c, 0x92, 0xf0, 0xc3, 0x20, 0xab, 0x50, 0x20, 0x75, 0x4c, 0x00, 0xe1, - 0x90, 0x75, 0x07, 0xe1, 0xb8, 0x06, 0x8b, 0x34, 0x09, 0x60, 0x60, 0x09, 0x8f, 0xac, 0x29, 0x1a, - 0x59, 0xcb, 0xe4, 0x01, 0x5b, 0x05, 0x16, 0x62, 0x9f, 0x85, 0x25, 0x0f, 0xaf, 0x53, 0x1f, 0xb1, - 0x72, 0xbf, 0xe2, 0x70, 0xaf, 0xf3, 0x42, 0xe9, 0x0f, 0x71, 0x77, 0x85, 0x5c, 0x68, 0x64, 0x12, - 0x8a, 0x11, 0xff, 0x9a, 0x50, 0x8c, 0xc4, 0x57, 0x46, 0x31, 0xbc, 0xf5, 0x5e, 0xd2, 0x5f, 0xef, - 0xfd, 0x33, 0xee, 0xee, 0x89, 0x83, 0x49, 0x74, 0x34, 0x05, 0xf3, 0x0a, 0x8c, 0xfe, 0x26, 0x69, - 0x56, 0x4f, 0x3b, 0xe1, 0x75, 0x16, 0xf9, 0x49, 0xb8, 0x9c, 0xd8, 0x99, 0xe7, 0xa1, 0xd1, 0x29, - 0xde, 0x58, 0xee, 0xc2, 0x8b, 0xb7, 0x0a, 0x24, 0x1f, 0x60, 0x16, 0xe9, 0x16, 0x44, 0xf2, 0x93, - 0xf0, 0x51, 0x23, 0xe3, 0x39, 0x08, 0x1b, 0xa0, 0xdb, 0x90, 0xa7, 0x9d, 0x15, 0x49, 0xd3, 0x4d, - 0x1e, 0x90, 0x7c, 0xe9, 0x1a, 0x6b, 0xa0, 0xac, 0xed, 0x13, 0x9e, 0x3d, 0xdd, 0x14, 0x73, 0x3a, - 0xff, 0xe5, 0x49, 0x9a, 0xf2, 0xbe, 0xa4, 0xe9, 0x02, 0xe4, 0xc9, 0xd7, 0x9b, 0xba, 0xdc, 0xc1, - 0x34, 0xb2, 0xe4, 0x45, 0x97, 0x20, 0xdc, 0x07, 0x34, 0x1e, 0x27, 0x51, 0x13, 0x32, 0xf8, 0x14, - 0x0f, 0x2c, 0x96, 0x53, 0x06, 0xf2, 0x52, 0x56, 0xe2, 0x91, 0xc7, 0x1b, 0x55, 0xb2, 0xc8, 0xff, - 0xf8, 0x7c, 0xb5, 0xc2, 0xb8, 0x9f, 0xd1, 0xfa, 0xaa, 0x85, 0xfb, 0xba, 0x75, 0x26, 0x72, 0x79, - 0xe1, 0xaf, 0x09, 0x28, 0x07, 0xe2, 0xe7, 0xc4, 0xb5, 0xb5, 0x4d, 0x3e, 0xe1, 0xc1, 0x80, 0xa2, - 0xad, 0xf7, 0x45, 0x80, 0x13, 0xd9, 0x94, 0xde, 0x93, 0x07, 0x16, 0x56, 0xf8, 0xa2, 0xe7, 0x4f, - 0x64, 0xf3, 0x0d, 0x4a, 0x20, 0xbb, 0x4e, 0x1e, 0x0f, 0x4d, 0xac, 0x70, 0x34, 0x2a, 0x7b, 0x22, - 0x9b, 0x87, 0x26, 0x56, 0x3c, 0xb3, 0xcc, 0x3e, 0xdc, 0x2c, 0xfd, 0x6b, 0x9c, 0x0b, 0xac, 0xb1, - 0xa7, 0x44, 0xcf, 0x7b, 0x4b, 0x74, 0x54, 0x83, 0x9c, 0x6e, 0xa8, 0x9a, 0xa1, 0x5a, 0x67, 0x74, - 0x63, 0x92, 0xa2, 0x33, 0x46, 0x97, 0xa1, 0xd8, 0xc7, 0x7d, 0x5d, 0xd3, 0x7a, 0x12, 0x73, 0x36, - 0x05, 0x2a, 0xba, 0xc0, 0x89, 0x0d, 0xea, 0x73, 0x3e, 0x4c, 0xb8, 0xa7, 0xcf, 0x85, 0x62, 0xbe, - 0xde, 0xe5, 0x5d, 0x99, 0xb0, 0xbc, 0x1e, 0x0a, 0x99, 0x44, 0x60, 0x7d, 0x9d, 0xf1, 0xb7, 0xb5, - 0xc0, 0xc2, 0x4f, 0x28, 0x3e, 0xeb, 0xcf, 0x8d, 0xd0, 0x01, 0x2c, 0x3a, 0x87, 0x5f, 0x1a, 0x52, - 0xa7, 0x60, 0x9b, 0x73, 0x54, 0xef, 0x51, 0x39, 0xf5, 0x93, 0x4d, 0xf4, 0x26, 0x3c, 0x1a, 0xf0, - 0x6c, 0x8e, 0xea, 0x44, 0x54, 0x07, 0xf7, 0x88, 0xdf, 0xc1, 0xd9, 0xaa, 0xdd, 0xc5, 0x4a, 0x3e, - 0xe4, 0x99, 0xdb, 0x86, 0x92, 0x3f, 0xcd, 0x9b, 0xb8, 0xfd, 0x97, 0xa1, 0x68, 0x60, 0x4b, 0x56, - 0x07, 0x92, 0x0f, 0x54, 0x5d, 0x60, 0x44, 0x0e, 0xd5, 0xee, 0xc3, 0x23, 0x13, 0xd3, 0x3d, 0xf4, - 0x02, 0xe4, 0xdd, 0x4c, 0x91, 0xad, 0xea, 0x14, 0xd0, 0xcd, 0xe5, 0x15, 0x7e, 0x1f, 0x77, 0x55, - 0xfa, 0x61, 0xbc, 0x06, 0x64, 0x0c, 0x6c, 0x0e, 0x7b, 0x0c, 0x58, 0x2b, 0xdd, 0x78, 0x36, 0x5a, - 0xa2, 0x48, 0xa8, 0xc3, 0x9e, 0x25, 0x72, 0x61, 0xe1, 0x3e, 0x64, 0x18, 0x05, 0x15, 0x20, 0x7b, - 0xb8, 0x7b, 0x77, 0x77, 0xef, 0x8d, 0xdd, 0x4a, 0x0c, 0x01, 0x64, 0xd6, 0xeb, 0xf5, 0xc6, 0x7e, - 0xab, 0x12, 0x47, 0x79, 0x48, 0xaf, 0x6f, 0xec, 0x89, 0xad, 0x4a, 0x82, 0x90, 0xc5, 0xc6, 0x9d, - 0x46, 0xbd, 0x55, 0x49, 0xa2, 0x45, 0x28, 0xb2, 0xdf, 0xd2, 0xd6, 0x9e, 0x78, 0x6f, 0xbd, 0x55, - 0x49, 0x79, 0x48, 0x07, 0x8d, 0xdd, 0xcd, 0x86, 0x58, 0x49, 0x0b, 0xff, 0x07, 0xe7, 0x43, 0x53, - 0x4b, 0x17, 0xa3, 0x8b, 0x7b, 0x30, 0x3a, 0xe1, 0x17, 0x09, 0xa8, 0x85, 0xe7, 0x8b, 0xe8, 0x4e, - 0x60, 0xe2, 0x37, 0xe6, 0x48, 0x36, 0x03, 0xb3, 0x47, 0x4f, 0x40, 0xc9, 0xc0, 0xc7, 0xd8, 0xea, - 0x74, 0x59, 0xfe, 0xca, 0x02, 0x66, 0x51, 0x2c, 0x72, 0x2a, 0x15, 0x32, 0x19, 0xdb, 0x3b, 0xb8, - 0x63, 0x49, 0xcc, 0x17, 0x31, 0xa3, 0xcb, 0x13, 0x36, 0x42, 0x3d, 0x60, 0x44, 0xe1, 0xed, 0xb9, - 0xd6, 0x32, 0x0f, 0x69, 0xb1, 0xd1, 0x12, 0xdf, 0xac, 0x24, 0x11, 0x82, 0x12, 0xfd, 0x29, 0x1d, - 0xec, 0xae, 0xef, 0x1f, 0x34, 0xf7, 0xc8, 0x5a, 0x2e, 0x41, 0xd9, 0x5e, 0x4b, 0x9b, 0x98, 0x16, - 0xfe, 0x94, 0x80, 0x47, 0x43, 0xb2, 0x5d, 0x74, 0x1b, 0xc0, 0x1a, 0x49, 0x06, 0xee, 0x68, 0x86, - 0x12, 0x6e, 0x64, 0xad, 0x91, 0x48, 0x39, 0xc4, 0xbc, 0xc5, 0x7f, 0x99, 0x53, 0xa0, 0x5d, 0xf4, - 0x32, 0x57, 0x4a, 0x66, 0x65, 0x1f, 0xb5, 0x8b, 0x13, 0x10, 0x4c, 0xdc, 0x21, 0x8a, 0xe9, 0xda, - 0x52, 0xc5, 0x94, 0x1f, 0xdd, 0x9b, 0xe4, 0x54, 0x22, 0x36, 0x56, 0xe6, 0x73, 0x27, 0xe9, 0x87, - 0x73, 0x27, 0xc2, 0xaf, 0x92, 0xde, 0x85, 0xf5, 0x27, 0xf7, 0x7b, 0x90, 0x31, 0x2d, 0xd9, 0x1a, - 0x9a, 0xdc, 0xe0, 0x5e, 0x88, 0x5a, 0x29, 0xac, 0xd9, 0x3f, 0x0e, 0xa8, 0xb8, 0xc8, 0xd5, 0x7c, - 0xb7, 0xde, 0xa6, 0x70, 0x0b, 0x4a, 0xfe, 0xc5, 0x09, 0x3f, 0x32, 0xae, 0xcf, 0x49, 0x08, 0x6f, - 0xb9, 0xf9, 0x97, 0x07, 0x5f, 0xdc, 0x82, 0x52, 0xa0, 0x5c, 0x8a, 0x8f, 0xd7, 0xf3, 0x2e, 0x3e, - 0xe8, 0x94, 0x42, 0x62, 0xf1, 0xd4, 0x3b, 0x14, 0x7e, 0x1d, 0x87, 0xc7, 0xa6, 0x14, 0x54, 0xe8, - 0xf5, 0x80, 0x21, 0xbc, 0x38, 0x4f, 0x39, 0xb6, 0xc6, 0x68, 0x7e, 0x53, 0x10, 0x6e, 0xc2, 0x82, - 0x97, 0x1e, 0x6d, 0x15, 0x7e, 0x9a, 0x74, 0x83, 0x82, 0x1f, 0xda, 0xfc, 0xda, 0x32, 0xd1, 0x80, - 0x21, 0x26, 0xe6, 0x34, 0xc4, 0x89, 0xd9, 0x44, 0xf2, 0x9b, 0xcb, 0x26, 0x52, 0x0f, 0x99, 0x4d, - 0x78, 0x4f, 0x64, 0xda, 0x7f, 0x22, 0xc7, 0x02, 0x7f, 0x66, 0x42, 0xe0, 0x7f, 0x13, 0xc0, 0xd3, - 0x9c, 0x5c, 0x86, 0xb4, 0xa1, 0x0d, 0x07, 0x0a, 0x35, 0x93, 0xb4, 0xc8, 0x06, 0xe8, 0x16, 0xa4, - 0x89, 0xb9, 0xd9, 0x8b, 0x39, 0xee, 0x9a, 0x89, 0xb9, 0x78, 0x40, 0x65, 0xc6, 0x2d, 0xa8, 0x80, - 0xc6, 0x1b, 0x44, 0x21, 0xaf, 0x78, 0xc5, 0xff, 0x8a, 0xc7, 0x43, 0x5b, 0x4d, 0x93, 0x5f, 0xf5, - 0x3e, 0xa4, 0xa9, 0x79, 0x90, 0x04, 0x88, 0x36, 0x39, 0x79, 0x45, 0x4d, 0x7e, 0xa3, 0x1f, 0x01, - 0xc8, 0x96, 0x65, 0xa8, 0xed, 0xa1, 0xfb, 0x82, 0xd5, 0xc9, 0xe6, 0xb5, 0x6e, 0xf3, 0x6d, 0x5c, - 0xe0, 0x76, 0xb6, 0xec, 0x8a, 0x7a, 0x6c, 0xcd, 0xa3, 0x50, 0xd8, 0x85, 0x92, 0x5f, 0xd6, 0xae, - 0x01, 0xd9, 0x37, 0xf8, 0x6b, 0x40, 0x56, 0xd2, 0xf3, 0x1a, 0xd0, 0xa9, 0x20, 0x93, 0xac, 0x9f, - 0x4d, 0x07, 0xc2, 0xbf, 0xe2, 0xb0, 0xe0, 0xb5, 0xce, 0xff, 0xb5, 0x32, 0x4a, 0xf8, 0x30, 0x0e, - 0x39, 0x67, 0xf2, 0x21, 0xcd, 0x64, 0x77, 0xed, 0x12, 0xde, 0xd6, 0x29, 0xeb, 0x4e, 0x27, 0x9d, - 0x9e, 0xf7, 0x4b, 0x4e, 0xc6, 0x15, 0x86, 0x7a, 0x7b, 0x57, 0xda, 0x6e, 0xfb, 0xf3, 0x04, 0xf3, - 0xe7, 0xfc, 0x3b, 0x48, 0xaa, 0x81, 0xbe, 0x07, 0x19, 0xb9, 0xe3, 0x60, 0xfd, 0xa5, 0x09, 0xe0, - 0xaf, 0xcd, 0xba, 0xd6, 0x1a, 0xad, 0x53, 0x4e, 0x91, 0x4b, 0xf0, 0xaf, 0x4a, 0x38, 0x3d, 0xf3, - 0x57, 0x89, 0x5e, 0xc6, 0xe3, 0x77, 0x9b, 0x25, 0x80, 0xc3, 0xdd, 0x7b, 0x7b, 0x9b, 0xdb, 0x5b, - 0xdb, 0x8d, 0x4d, 0x9e, 0x73, 0x6d, 0x6e, 0x36, 0x36, 0x2b, 0x09, 0xc2, 0x27, 0x36, 0xee, 0xed, - 0x1d, 0x35, 0x36, 0x2b, 0x49, 0xe1, 0x25, 0xc8, 0x3b, 0xae, 0x07, 0x55, 0x21, 0x6b, 0xf7, 0x2d, - 0xe2, 0xdc, 0x01, 0xb0, 0x21, 0xbd, 0x2f, 0xa1, 0xbd, 0xc7, 0x3b, 0xc6, 0x49, 0x91, 0x0d, 0x04, - 0x05, 0xca, 0x01, 0xbf, 0x85, 0x5e, 0x82, 0xac, 0x3e, 0x6c, 0x4b, 0xb6, 0xd1, 0x06, 0xba, 0x3c, - 0x36, 0x14, 0x31, 0x6c, 0xf7, 0xd4, 0xce, 0x5d, 0x7c, 0x66, 0x2f, 0x93, 0x3e, 0x6c, 0xdf, 0x65, - 0xb6, 0xcd, 0xde, 0x92, 0xf0, 0xbe, 0xe5, 0xc7, 0x71, 0xc8, 0xd9, 0x67, 0x15, 0x7d, 0x1f, 0xf2, - 0x8e, 0x4f, 0x74, 0xee, 0xd1, 0x84, 0x3a, 0x53, 0xae, 0xdf, 0x15, 0x41, 0xd7, 0x60, 0xd1, 0x54, - 0x4f, 0x06, 0x76, 0x93, 0x8b, 0x61, 0x7f, 0x09, 0x7a, 0x68, 0xca, 0xec, 0xc1, 0x8e, 0x0d, 0x58, - 0xdd, 0x49, 0xe5, 0x92, 0x95, 0xd4, 0x9d, 0x54, 0x2e, 0x55, 0x49, 0x93, 0xb0, 0x58, 0x09, 0x3a, - 0x8e, 0x6f, 0xf3, 0x63, 0x48, 0xfa, 0x1d, 0x88, 0xef, 0xcc, 0x36, 0x03, 0xe1, 0xfb, 0x83, 0x04, - 0x14, 0x3c, 0x6d, 0x34, 0xf4, 0xff, 0x1e, 0x2f, 0x56, 0x9a, 0x10, 0x77, 0x3c, 0xbc, 0xee, 0x75, - 0x0d, 0xff, 0xc4, 0x12, 0xf3, 0x4f, 0x2c, 0xec, 0xda, 0x8d, 0xdd, 0x8d, 0x4b, 0xcd, 0xdd, 0x8d, - 0x7b, 0x06, 0x90, 0xa5, 0x59, 0x72, 0x4f, 0x3a, 0xd5, 0x2c, 0x75, 0x70, 0x22, 0x31, 0x3b, 0x61, - 0x3e, 0xa7, 0x42, 0x9f, 0x1c, 0xd1, 0x07, 0xfb, 0x8e, 0xc9, 0x38, 0x45, 0xe2, 0xbc, 0xb7, 0x2f, - 0xce, 0x41, 0x86, 0xd7, 0x41, 0xec, 0xfa, 0x05, 0x1f, 0x4d, 0x6c, 0x3b, 0xd6, 0x20, 0xd7, 0xc7, - 0x96, 0x4c, 0x1d, 0x28, 0x8b, 0x99, 0xce, 0xf8, 0xda, 0x8b, 0x50, 0xf0, 0x5c, 0x84, 0x21, 0x3e, - 0x75, 0xb7, 0xf1, 0x46, 0x25, 0x56, 0xcb, 0x7e, 0xf4, 0xc9, 0xa5, 0xe4, 0x2e, 0x7e, 0x8f, 0x1c, - 0x37, 0xb1, 0x51, 0x6f, 0x36, 0xea, 0x77, 0x2b, 0xf1, 0x5a, 0xe1, 0xa3, 0x4f, 0x2e, 0x65, 0x45, - 0x4c, 0xbb, 0x44, 0xd7, 0xee, 0x42, 0x39, 0xb0, 0x31, 0xfe, 0xd3, 0x8d, 0xa0, 0xb4, 0x79, 0xb8, - 0xbf, 0xb3, 0x5d, 0x5f, 0x6f, 0x35, 0xa4, 0xa3, 0xbd, 0x56, 0xa3, 0x12, 0x47, 0x8f, 0xc2, 0xd2, - 0xce, 0xf6, 0x6b, 0xcd, 0x96, 0x54, 0xdf, 0xd9, 0x6e, 0xec, 0xb6, 0xa4, 0xf5, 0x56, 0x6b, 0xbd, - 0x7e, 0xb7, 0x92, 0xb8, 0xf1, 0x9b, 0x02, 0x94, 0xd7, 0x37, 0xea, 0xdb, 0xa4, 0x12, 0x54, 0x3b, - 0x32, 0xf5, 0x15, 0x75, 0x48, 0x51, 0xc8, 0x79, 0xea, 0xd5, 0xe6, 0xda, 0xf4, 0x36, 0x22, 0xda, - 0x82, 0x34, 0x45, 0xa3, 0xd1, 0xf4, 0xbb, 0xce, 0xb5, 0x19, 0x7d, 0x45, 0xf2, 0x31, 0xf4, 0x38, - 0x4d, 0xbd, 0xfc, 0x5c, 0x9b, 0xde, 0x66, 0x44, 0x3b, 0x90, 0xb5, 0xc1, 0xc2, 0x59, 0xd7, 0x88, - 0x6b, 0x33, 0xfb, 0x75, 0x64, 0x6a, 0x0c, 0xd4, 0x9d, 0x7e, 0x2f, 0xba, 0x36, 0xa3, 0x01, 0x89, - 0xb6, 0x21, 0xc3, 0xf1, 0x94, 0x19, 0x57, 0x82, 0x6b, 0xb3, 0xfa, 0x6e, 0x48, 0x84, 0xbc, 0x0b, - 0x97, 0xcf, 0xbe, 0xed, 0x5d, 0x8b, 0xd0, 0x5b, 0x45, 0xf7, 0xa1, 0xe8, 0xc7, 0x68, 0xa2, 0x5d, - 0x3b, 0xae, 0x45, 0xec, 0xf0, 0x11, 0xfd, 0x7e, 0xc0, 0x26, 0xda, 0x35, 0xe4, 0x5a, 0xc4, 0x86, - 0x1f, 0x7a, 0x07, 0x16, 0xc7, 0x01, 0x95, 0xe8, 0xb7, 0x92, 0x6b, 0x73, 0xb4, 0x00, 0x51, 0x1f, - 0xd0, 0x04, 0x20, 0x66, 0x8e, 0x4b, 0xca, 0xb5, 0x79, 0x3a, 0x82, 0x48, 0x81, 0x72, 0x10, 0xdc, - 0x88, 0x7a, 0x69, 0xb9, 0x16, 0xb9, 0x3b, 0xc8, 0xde, 0xe2, 0xaf, 0xf4, 0xa3, 0x5e, 0x62, 0xae, - 0x45, 0x6e, 0x16, 0xa2, 0x43, 0x00, 0x4f, 0xa5, 0x1a, 0xe1, 0x52, 0x73, 0x2d, 0x4a, 0xdb, 0x10, - 0xe9, 0xb0, 0x34, 0xa9, 0x42, 0x9d, 0xe7, 0x8e, 0x73, 0x6d, 0xae, 0x6e, 0x22, 0xb1, 0x67, 0x7f, - 0xad, 0x19, 0xed, 0xce, 0x73, 0x2d, 0x62, 0x5b, 0x71, 0xa3, 0xf1, 0xe9, 0x17, 0x2b, 0xf1, 0xcf, - 0xbe, 0x58, 0x89, 0xff, 0xfd, 0x8b, 0x95, 0xf8, 0xc7, 0x5f, 0xae, 0xc4, 0x3e, 0xfb, 0x72, 0x25, - 0xf6, 0x97, 0x2f, 0x57, 0x62, 0x3f, 0x78, 0xfa, 0x44, 0xb5, 0xba, 0xc3, 0xf6, 0x5a, 0x47, 0xeb, - 0x5f, 0xf7, 0xfe, 0xfd, 0x65, 0xd2, 0x5f, 0x72, 0xda, 0x19, 0x1a, 0x50, 0x6f, 0xfe, 0x27, 0x00, - 0x00, 0xff, 0xff, 0xc7, 0x45, 0xe7, 0x5f, 0xb2, 0x33, 0x00, 0x00, + // 3459 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0x4b, 0x93, 0x1b, 0xd5, + 0xf5, 0x97, 0x5a, 0xef, 0xa3, 0xd1, 0x63, 0xee, 0x0c, 0x46, 0x16, 0xf6, 0x8c, 0x69, 0x97, 0xc1, + 0x36, 0x30, 0xe6, 0x3f, 0xfe, 0x1b, 0x4c, 0x0c, 0xa1, 0x66, 0x34, 0x32, 0x1a, 0x7b, 0x3c, 0x33, + 0xf4, 0x68, 0x4c, 0x91, 0x87, 0x9b, 0x96, 0xfa, 0xce, 0xa8, 0xb1, 0xa4, 0x6e, 0xba, 0x5b, 0x83, + 0x86, 0x65, 0x28, 0x36, 0x54, 0xaa, 0xc2, 0x26, 0x95, 0xa4, 0x2a, 0xec, 0x92, 0xaa, 0xe4, 0x1b, + 0x64, 0x95, 0x55, 0x16, 0x2c, 0xb2, 0x60, 0x95, 0xa4, 0xb2, 0x20, 0x29, 0xd8, 0xe5, 0x0b, 0x64, + 0x97, 0xa4, 0xee, 0xa3, 0x5f, 0x52, 0xb7, 0x1e, 0x18, 0xa8, 0x4a, 0x85, 0x9d, 0xfa, 0xf4, 0x39, + 0xa7, 0xef, 0xe3, 0xdc, 0xf3, 0xf8, 0x9d, 0x2b, 0x78, 0xc2, 0xc6, 0x7d, 0x15, 0x9b, 0x3d, 0xad, + 0x6f, 0x5f, 0x53, 0x5a, 0x6d, 0xed, 0x9a, 0x7d, 0x6a, 0x60, 0x6b, 0xcd, 0x30, 0x75, 0x5b, 0x47, + 0x25, 0xef, 0xe5, 0x1a, 0x79, 0x59, 0x3d, 0xef, 0xe3, 0x6e, 0x9b, 0xa7, 0x86, 0xad, 0x5f, 0x33, + 0x4c, 0x5d, 0x3f, 0x62, 0xfc, 0xd5, 0x73, 0xbe, 0xd7, 0x54, 0x8f, 0x5f, 0x5b, 0xe0, 0x2d, 0x17, + 0x7e, 0x88, 0x4f, 0x9d, 0xb7, 0xe7, 0xc7, 0x64, 0x0d, 0xc5, 0x54, 0x7a, 0xce, 0xeb, 0xd5, 0x63, + 0x5d, 0x3f, 0xee, 0xe2, 0x6b, 0xf4, 0xa9, 0x35, 0x38, 0xba, 0x66, 0x6b, 0x3d, 0x6c, 0xd9, 0x4a, + 0xcf, 0xe0, 0x0c, 0xcb, 0xc7, 0xfa, 0xb1, 0x4e, 0x7f, 0x5e, 0x23, 0xbf, 0x18, 0x55, 0xfc, 0x37, + 0x40, 0x46, 0xc2, 0xef, 0x0c, 0xb0, 0x65, 0xa3, 0x75, 0x48, 0xe2, 0x76, 0x47, 0xaf, 0xc4, 0x2f, + 0xc4, 0x2f, 0xe7, 0xd7, 0xcf, 0xad, 0x8d, 0x4c, 0x6e, 0x8d, 0xf3, 0xd5, 0xdb, 0x1d, 0xbd, 0x11, + 0x93, 0x28, 0x2f, 0xba, 0x01, 0xa9, 0xa3, 0xee, 0xc0, 0xea, 0x54, 0x04, 0x2a, 0x74, 0x3e, 0x4a, + 0xe8, 0x36, 0x61, 0x6a, 0xc4, 0x24, 0xc6, 0x4d, 0x3e, 0xa5, 0xf5, 0x8f, 0xf4, 0x4a, 0x62, 0xf2, + 0xa7, 0xb6, 0xfb, 0x47, 0xf4, 0x53, 0x84, 0x17, 0x6d, 0x02, 0x68, 0x7d, 0xcd, 0x96, 0xdb, 0x1d, + 0x45, 0xeb, 0x57, 0x92, 0x54, 0xf2, 0xc9, 0x68, 0x49, 0xcd, 0xae, 0x11, 0xc6, 0x46, 0x4c, 0xca, + 0x69, 0xce, 0x03, 0x19, 0xee, 0x3b, 0x03, 0x6c, 0x9e, 0x56, 0x52, 0x93, 0x87, 0xfb, 0x3a, 0x61, + 0x22, 0xc3, 0xa5, 0xdc, 0x68, 0x1b, 0xf2, 0x2d, 0x7c, 0xac, 0xf5, 0xe5, 0x56, 0x57, 0x6f, 0x3f, + 0xac, 0xa4, 0xa9, 0xb0, 0x18, 0x25, 0xbc, 0x49, 0x58, 0x37, 0x09, 0xe7, 0xa6, 0x50, 0x89, 0x37, + 0x62, 0x12, 0xb4, 0x5c, 0x0a, 0x7a, 0x19, 0xb2, 0xed, 0x0e, 0x6e, 0x3f, 0x94, 0xed, 0x61, 0x25, + 0x43, 0xf5, 0xac, 0x46, 0xe9, 0xa9, 0x11, 0xbe, 0xe6, 0xb0, 0x11, 0x93, 0x32, 0x6d, 0xf6, 0x13, + 0xdd, 0x06, 0x50, 0x71, 0x57, 0x3b, 0xc1, 0x26, 0x91, 0xcf, 0x4e, 0x5e, 0x83, 0x2d, 0xc6, 0xd9, + 0x1c, 0xf2, 0x61, 0xe4, 0x54, 0x87, 0x80, 0x6a, 0x90, 0xc3, 0x7d, 0x95, 0x4f, 0x27, 0x47, 0xd5, + 0x5c, 0x88, 0xdc, 0xef, 0xbe, 0xea, 0x9f, 0x4c, 0x16, 0xf3, 0x67, 0x74, 0x13, 0xd2, 0x6d, 0xbd, + 0xd7, 0xd3, 0xec, 0x0a, 0x50, 0x0d, 0x2b, 0x91, 0x13, 0xa1, 0x5c, 0x8d, 0x98, 0xc4, 0xf9, 0xd1, + 0x2e, 0x14, 0xbb, 0x9a, 0x65, 0xcb, 0x56, 0x5f, 0x31, 0xac, 0x8e, 0x6e, 0x5b, 0x95, 0x3c, 0xd5, + 0x70, 0x29, 0x4a, 0xc3, 0x8e, 0x66, 0xd9, 0x07, 0x0e, 0x73, 0x23, 0x26, 0x15, 0xba, 0x7e, 0x02, + 0xd1, 0xa7, 0x1f, 0x1d, 0x61, 0xd3, 0x55, 0x58, 0x59, 0x98, 0xac, 0x6f, 0x8f, 0x70, 0x3b, 0xf2, + 0x44, 0x9f, 0xee, 0x27, 0xa0, 0xef, 0xc3, 0x52, 0x57, 0x57, 0x54, 0x57, 0x9d, 0xdc, 0xee, 0x0c, + 0xfa, 0x0f, 0x2b, 0x05, 0xaa, 0xf4, 0x4a, 0xe4, 0x20, 0x75, 0x45, 0x75, 0x54, 0xd4, 0x88, 0x40, + 0x23, 0x26, 0x2d, 0x76, 0x47, 0x89, 0xe8, 0x01, 0x2c, 0x2b, 0x86, 0xd1, 0x3d, 0x1d, 0xd5, 0x5e, + 0xa4, 0xda, 0xaf, 0x46, 0x69, 0xdf, 0x20, 0x32, 0xa3, 0xea, 0x91, 0x32, 0x46, 0x45, 0x4d, 0x28, + 0x1b, 0x26, 0x36, 0x14, 0x13, 0xcb, 0x86, 0xa9, 0x1b, 0xba, 0xa5, 0x74, 0x2b, 0x25, 0xaa, 0xfb, + 0xe9, 0x28, 0xdd, 0xfb, 0x8c, 0x7f, 0x9f, 0xb3, 0x37, 0x62, 0x52, 0xc9, 0x08, 0x92, 0x98, 0x56, + 0xbd, 0x8d, 0x2d, 0xcb, 0xd3, 0x5a, 0x9e, 0xa6, 0x95, 0xf2, 0x07, 0xb5, 0x06, 0x48, 0xa8, 0x0e, + 0x79, 0x3c, 0x24, 0xe2, 0xf2, 0x89, 0x6e, 0xe3, 0xca, 0xe2, 0xe4, 0x83, 0x55, 0xa7, 0xac, 0xf7, + 0x75, 0x1b, 0x93, 0x43, 0x85, 0xdd, 0x27, 0xa4, 0xc0, 0x63, 0x27, 0xd8, 0xd4, 0x8e, 0x4e, 0xa9, + 0x1a, 0x99, 0xbe, 0xb1, 0x34, 0xbd, 0x5f, 0x41, 0x54, 0xe1, 0x33, 0x51, 0x0a, 0xef, 0x53, 0x21, + 0xa2, 0xa2, 0xee, 0x88, 0x34, 0x62, 0xd2, 0xd2, 0xc9, 0x38, 0x99, 0x98, 0xd8, 0x91, 0xd6, 0x57, + 0xba, 0xda, 0x7b, 0x98, 0x1f, 0x9b, 0xa5, 0xc9, 0x26, 0x76, 0x9b, 0x73, 0xd3, 0xb3, 0x42, 0x4c, + 0xec, 0xc8, 0x4f, 0xd8, 0xcc, 0x40, 0xea, 0x44, 0xe9, 0x0e, 0xb0, 0xf8, 0x34, 0xe4, 0x7d, 0x8e, + 0x15, 0x55, 0x20, 0xd3, 0xc3, 0x96, 0xa5, 0x1c, 0x63, 0xea, 0x87, 0x73, 0x92, 0xf3, 0x28, 0x16, + 0x61, 0xc1, 0xef, 0x4c, 0xc5, 0x8f, 0xe2, 0xae, 0x24, 0xf1, 0x93, 0x44, 0xf2, 0x04, 0x9b, 0x74, + 0xda, 0x5c, 0x92, 0x3f, 0xa2, 0x8b, 0x50, 0xa0, 0x43, 0x96, 0x9d, 0xf7, 0xc4, 0x59, 0x27, 0xa5, + 0x05, 0x4a, 0xbc, 0xcf, 0x99, 0x56, 0x21, 0x6f, 0xac, 0x1b, 0x2e, 0x4b, 0x82, 0xb2, 0x80, 0xb1, + 0x6e, 0x38, 0x0c, 0x4f, 0xc2, 0x02, 0x99, 0x9f, 0xcb, 0x91, 0xa4, 0x1f, 0xc9, 0x13, 0x1a, 0x67, + 0x11, 0xff, 0x28, 0x40, 0x79, 0xd4, 0x01, 0xa3, 0x9b, 0x90, 0x24, 0xb1, 0x88, 0x87, 0x95, 0xea, + 0x1a, 0x0b, 0x54, 0x6b, 0x4e, 0xa0, 0x5a, 0x6b, 0x3a, 0x81, 0x6a, 0x33, 0xfb, 0xc9, 0x67, 0xab, + 0xb1, 0x8f, 0xfe, 0xb6, 0x1a, 0x97, 0xa8, 0x04, 0x3a, 0x4b, 0x7c, 0xa5, 0xa2, 0xf5, 0x65, 0x4d, + 0xa5, 0x43, 0xce, 0x11, 0x47, 0xa8, 0x68, 0xfd, 0x6d, 0x15, 0xed, 0x40, 0xb9, 0xad, 0xf7, 0x2d, + 0xdc, 0xb7, 0x06, 0x96, 0xcc, 0x02, 0x21, 0x0f, 0x26, 0x01, 0x77, 0xc8, 0xc2, 0x6b, 0xcd, 0xe1, + 0xdc, 0xa7, 0x8c, 0x52, 0xa9, 0x1d, 0x24, 0x10, 0xb7, 0x7a, 0xa2, 0x74, 0x35, 0x55, 0xb1, 0x75, + 0xd3, 0xaa, 0x24, 0x2f, 0x24, 0x42, 0xfd, 0xe1, 0x7d, 0x87, 0xe5, 0xd0, 0x50, 0x15, 0x1b, 0x6f, + 0x26, 0xc9, 0x70, 0x25, 0x9f, 0x24, 0x7a, 0x0a, 0x4a, 0x8a, 0x61, 0xc8, 0x96, 0xad, 0xd8, 0x58, + 0x6e, 0x9d, 0xda, 0xd8, 0xa2, 0x81, 0x66, 0x41, 0x2a, 0x28, 0x86, 0x71, 0x40, 0xa8, 0x9b, 0x84, + 0x88, 0x2e, 0x41, 0x91, 0xc4, 0x24, 0x4d, 0xe9, 0xca, 0x1d, 0xac, 0x1d, 0x77, 0x6c, 0x1a, 0x52, + 0x12, 0x52, 0x81, 0x53, 0x1b, 0x94, 0x28, 0xaa, 0xee, 0x8e, 0xd3, 0x78, 0x84, 0x10, 0x24, 0x55, + 0xc5, 0x56, 0xe8, 0x4a, 0x2e, 0x48, 0xf4, 0x37, 0xa1, 0x19, 0x8a, 0xdd, 0xe1, 0xeb, 0x43, 0x7f, + 0xa3, 0x33, 0x90, 0xe6, 0x6a, 0x13, 0x54, 0x2d, 0x7f, 0x42, 0xcb, 0x90, 0x32, 0x4c, 0xfd, 0x04, + 0xd3, 0xad, 0xcb, 0x4a, 0xec, 0x41, 0x7c, 0x5f, 0x80, 0xc5, 0xb1, 0xc8, 0x45, 0xf4, 0x76, 0x14, + 0xab, 0xe3, 0x7c, 0x8b, 0xfc, 0x46, 0x2f, 0x10, 0xbd, 0x8a, 0x8a, 0x4d, 0x1e, 0xed, 0x2b, 0xe3, + 0x4b, 0xdd, 0xa0, 0xef, 0xf9, 0xd2, 0x70, 0x6e, 0x74, 0x17, 0xca, 0x5d, 0xc5, 0xb2, 0x65, 0xe6, + 0xfd, 0x65, 0x5f, 0xe4, 0x7f, 0x62, 0x6c, 0x91, 0x59, 0xac, 0x20, 0x06, 0xcd, 0x95, 0x14, 0x89, + 0xa8, 0x47, 0x45, 0x87, 0xb0, 0xdc, 0x3a, 0x7d, 0x4f, 0xe9, 0xdb, 0x5a, 0x1f, 0xcb, 0x63, 0xbb, + 0x36, 0x9e, 0x4a, 0xdc, 0xd3, 0xac, 0x16, 0xee, 0x28, 0x27, 0x9a, 0xee, 0x0c, 0x6b, 0xc9, 0x95, + 0x77, 0x77, 0xd4, 0x12, 0x25, 0x28, 0x06, 0xc3, 0x2e, 0x2a, 0x82, 0x60, 0x0f, 0xf9, 0xfc, 0x05, + 0x7b, 0x88, 0x9e, 0x87, 0x24, 0x99, 0x23, 0x9d, 0x7b, 0x31, 0xe4, 0x43, 0x5c, 0xae, 0x79, 0x6a, + 0x60, 0x89, 0x72, 0x8a, 0xa2, 0x7b, 0x1a, 0xdc, 0x50, 0x3c, 0xaa, 0x55, 0xbc, 0x02, 0xa5, 0x91, + 0x38, 0xeb, 0xdb, 0xbe, 0xb8, 0x7f, 0xfb, 0xc4, 0x12, 0x14, 0x02, 0x01, 0x55, 0x3c, 0x03, 0xcb, + 0x61, 0xf1, 0x51, 0xec, 0xb8, 0xf4, 0x40, 0x9c, 0x43, 0x37, 0x20, 0xeb, 0x06, 0x48, 0x76, 0x1a, + 0xcf, 0x8e, 0xcd, 0xc2, 0x61, 0x96, 0x5c, 0x56, 0x72, 0x0c, 0x89, 0x55, 0x53, 0x73, 0x10, 0xe8, + 0xc0, 0x33, 0x8a, 0x61, 0x34, 0x14, 0xab, 0x23, 0xbe, 0x05, 0x95, 0xa8, 0xe0, 0x37, 0x32, 0x8d, + 0xa4, 0x6b, 0x85, 0x67, 0x20, 0x7d, 0xa4, 0x9b, 0x3d, 0xc5, 0xa6, 0xca, 0x0a, 0x12, 0x7f, 0x22, + 0xd6, 0xc9, 0x02, 0x61, 0x82, 0x92, 0xd9, 0x83, 0x28, 0xc3, 0xd9, 0xc8, 0x00, 0x48, 0x44, 0xb4, + 0xbe, 0x8a, 0xd9, 0x7a, 0x16, 0x24, 0xf6, 0xe0, 0x29, 0x62, 0x83, 0x65, 0x0f, 0xe4, 0xb3, 0x16, + 0x9d, 0x2b, 0xd5, 0x9f, 0x93, 0xf8, 0x93, 0xf8, 0xdb, 0x04, 0x9c, 0x09, 0x0f, 0x83, 0xe8, 0x02, + 0x2c, 0xf4, 0x94, 0xa1, 0x6c, 0x0f, 0xf9, 0x59, 0x66, 0xdb, 0x01, 0x3d, 0x65, 0xd8, 0x1c, 0xb2, + 0x83, 0x5c, 0x86, 0x84, 0x3d, 0xb4, 0x2a, 0xc2, 0x85, 0xc4, 0xe5, 0x05, 0x89, 0xfc, 0x44, 0x87, + 0xb0, 0xd8, 0xd5, 0xdb, 0x4a, 0x57, 0xf6, 0x59, 0x3c, 0x37, 0xf6, 0x8b, 0x63, 0x8b, 0xcd, 0x02, + 0x1a, 0x56, 0xc7, 0x8c, 0xbe, 0x44, 0x75, 0xec, 0xb8, 0x96, 0xff, 0x35, 0x59, 0xbd, 0x6f, 0x8f, + 0x52, 0x01, 0x4f, 0xe1, 0xf8, 0xec, 0xf4, 0xdc, 0x3e, 0xfb, 0x79, 0x58, 0xee, 0xe3, 0xa1, 0xed, + 0x1b, 0x23, 0x33, 0x9c, 0x0c, 0xdd, 0x0b, 0x44, 0xde, 0x79, 0xdf, 0x27, 0x36, 0x84, 0xae, 0xd0, + 0xcc, 0xc2, 0xd0, 0x2d, 0x6c, 0xca, 0x8a, 0xaa, 0x9a, 0xd8, 0xb2, 0x68, 0x66, 0xbb, 0x40, 0xd3, + 0x05, 0x4a, 0xdf, 0x60, 0x64, 0xf1, 0x17, 0xfe, 0xbd, 0x0a, 0x66, 0x12, 0x7c, 0x27, 0xe2, 0xde, + 0x4e, 0x1c, 0xc0, 0x32, 0x97, 0x57, 0x03, 0x9b, 0x21, 0xcc, 0xea, 0x79, 0x90, 0x23, 0x3e, 0xc3, + 0x3e, 0x24, 0x1e, 0x6d, 0x1f, 0x1c, 0x6f, 0x9b, 0xf4, 0x79, 0xdb, 0xff, 0xb2, 0xbd, 0x79, 0xd5, + 0x8d, 0x22, 0x5e, 0x9a, 0x16, 0x1a, 0x45, 0xbc, 0x79, 0x09, 0x01, 0xf7, 0xf6, 0xcb, 0x38, 0x54, + 0xa3, 0xf3, 0xb2, 0x50, 0x55, 0xcf, 0xc0, 0xa2, 0x3b, 0x17, 0x77, 0x7c, 0xec, 0xd4, 0x97, 0xdd, + 0x17, 0x7c, 0x80, 0x91, 0x51, 0xf1, 0x12, 0x14, 0x47, 0xb2, 0x46, 0xb6, 0x0b, 0x85, 0x13, 0xff, + 0xf7, 0xc5, 0x9f, 0x26, 0x5c, 0xaf, 0x1a, 0x48, 0xed, 0x42, 0x2c, 0xef, 0x75, 0x58, 0x52, 0x71, + 0x5b, 0x53, 0xbf, 0xac, 0xe1, 0x2d, 0x72, 0xe9, 0x6f, 0xed, 0x6e, 0x06, 0xbb, 0xfb, 0x73, 0x1e, + 0xb2, 0x12, 0xb6, 0x0c, 0x92, 0xd2, 0xa1, 0x4d, 0xc8, 0xe1, 0x61, 0x1b, 0x1b, 0xb6, 0x93, 0x05, + 0x87, 0x57, 0x13, 0x8c, 0xbb, 0xee, 0x70, 0x92, 0xda, 0xd8, 0x15, 0x43, 0xd7, 0x39, 0x0c, 0x12, + 0x8d, 0x68, 0x70, 0x71, 0x3f, 0x0e, 0xf2, 0x82, 0x83, 0x83, 0x24, 0x22, 0x4b, 0x61, 0x26, 0x35, + 0x02, 0x84, 0x5c, 0xe7, 0x40, 0x48, 0x72, 0xca, 0xc7, 0x02, 0x48, 0x48, 0x2d, 0x80, 0x84, 0xa4, + 0xa6, 0x4c, 0x33, 0x02, 0x0a, 0x79, 0xc1, 0x81, 0x42, 0xd2, 0x53, 0x46, 0x3c, 0x82, 0x85, 0xdc, + 0x09, 0x62, 0x21, 0x99, 0x88, 0xd0, 0xe6, 0x48, 0x4f, 0x04, 0x43, 0x5e, 0xf1, 0x81, 0x21, 0xd9, + 0x48, 0x14, 0x82, 0x29, 0x0a, 0x41, 0x43, 0x5e, 0x0b, 0xa0, 0x21, 0xb9, 0x29, 0xeb, 0x30, 0x01, + 0x0e, 0xd9, 0xf2, 0xc3, 0x21, 0x10, 0x89, 0xaa, 0xf0, 0x7d, 0x8f, 0xc2, 0x43, 0x5e, 0x72, 0xf1, + 0x90, 0x7c, 0x24, 0xb0, 0xc3, 0xe7, 0x32, 0x0a, 0x88, 0xec, 0x8d, 0x01, 0x22, 0x0c, 0xc0, 0x78, + 0x2a, 0x52, 0xc5, 0x14, 0x44, 0x64, 0x6f, 0x0c, 0x11, 0x29, 0x4c, 0x51, 0x38, 0x05, 0x12, 0xf9, + 0x41, 0x38, 0x24, 0x12, 0x0d, 0x5a, 0xf0, 0x61, 0xce, 0x86, 0x89, 0xc8, 0x11, 0x98, 0x48, 0x29, + 0xb2, 0x7e, 0x67, 0xea, 0x67, 0x06, 0x45, 0x0e, 0x43, 0x40, 0x11, 0x06, 0x5f, 0x5c, 0x8e, 0x54, + 0x3e, 0x03, 0x2a, 0x72, 0x18, 0x82, 0x8a, 0x2c, 0x4e, 0x55, 0x3b, 0x15, 0x16, 0xb9, 0x1d, 0x84, + 0x45, 0xd0, 0x94, 0x33, 0x16, 0x89, 0x8b, 0xb4, 0xa2, 0x70, 0x11, 0x86, 0x5d, 0x3c, 0x1b, 0xa9, + 0x71, 0x0e, 0x60, 0x64, 0x6f, 0x0c, 0x18, 0x59, 0x9e, 0x62, 0x69, 0xb3, 0x22, 0x23, 0x57, 0x48, + 0x46, 0x31, 0xe2, 0xaa, 0x49, 0x72, 0x8f, 0x4d, 0x53, 0x37, 0x39, 0xc6, 0xc1, 0x1e, 0xc4, 0xcb, + 0xa4, 0x52, 0xf6, 0xdc, 0xf2, 0x04, 0x14, 0x85, 0x16, 0x51, 0x3e, 0x57, 0x2c, 0xfe, 0x2e, 0xee, + 0xc9, 0xd2, 0x02, 0xd3, 0x5f, 0x65, 0xe7, 0x78, 0x95, 0xed, 0xc3, 0x56, 0x84, 0x20, 0xb6, 0xb2, + 0x0a, 0x79, 0x52, 0x1c, 0x8d, 0xc0, 0x26, 0x8a, 0xe1, 0xc2, 0x26, 0x57, 0x61, 0x91, 0x26, 0x01, + 0x0c, 0x81, 0xe1, 0x91, 0x35, 0x49, 0x23, 0x6b, 0x89, 0xbc, 0x60, 0xab, 0xc0, 0x42, 0xec, 0x73, + 0xb0, 0xe4, 0xe3, 0x75, 0x8b, 0x2e, 0x86, 0x21, 0x94, 0x5d, 0xee, 0x0d, 0x5e, 0x7d, 0xfd, 0x21, + 0xee, 0xad, 0x90, 0x87, 0xb7, 0x84, 0x41, 0x23, 0xf1, 0xaf, 0x08, 0x1a, 0x11, 0xbe, 0x34, 0x34, + 0xe2, 0x2f, 0x22, 0x13, 0xc1, 0x22, 0xf2, 0x9f, 0x71, 0x6f, 0x4f, 0x5c, 0xa0, 0xa3, 0xad, 0xab, + 0x98, 0x97, 0x75, 0xf4, 0x37, 0x49, 0xb3, 0xba, 0xfa, 0x31, 0x2f, 0xde, 0xc8, 0x4f, 0xc2, 0xe5, + 0xc6, 0xce, 0x1c, 0x0f, 0x8d, 0x6e, 0x45, 0xc8, 0x72, 0x17, 0x5e, 0x11, 0x96, 0x21, 0xf1, 0x10, + 0xb3, 0x48, 0xb7, 0x20, 0x91, 0x9f, 0x84, 0x8f, 0x1a, 0x19, 0xcf, 0x41, 0xd8, 0x03, 0xba, 0x09, + 0x39, 0xda, 0xae, 0x91, 0x75, 0xc3, 0xe2, 0x01, 0x29, 0x90, 0xae, 0xb1, 0xae, 0xcc, 0xda, 0x3e, + 0xe1, 0xd9, 0x33, 0x2c, 0x29, 0x6b, 0xf0, 0x5f, 0xbe, 0xa4, 0x29, 0x17, 0x48, 0x9a, 0xce, 0x41, + 0x8e, 0x8c, 0xde, 0x32, 0x94, 0x36, 0xa6, 0x91, 0x25, 0x27, 0x79, 0x04, 0xf1, 0x01, 0xa0, 0xf1, + 0x38, 0x89, 0x1a, 0x90, 0xc6, 0x27, 0xb8, 0x6f, 0xb3, 0x9c, 0x32, 0xbf, 0x7e, 0x66, 0xbc, 0x6e, + 0x24, 0xaf, 0x37, 0x2b, 0x64, 0x91, 0xff, 0xf1, 0xd9, 0x6a, 0x99, 0x71, 0x3f, 0xab, 0xf7, 0x34, + 0x1b, 0xf7, 0x0c, 0xfb, 0x54, 0xe2, 0xf2, 0xe2, 0x5f, 0x05, 0x28, 0x8d, 0xc4, 0xcf, 0xd0, 0xb5, + 0x75, 0x4c, 0x5e, 0xf0, 0x01, 0x4b, 0xb3, 0xad, 0xf7, 0x79, 0x80, 0x63, 0xc5, 0x92, 0xdf, 0x55, + 0xfa, 0x36, 0x56, 0xf9, 0xa2, 0xe7, 0x8e, 0x15, 0xeb, 0x0d, 0x4a, 0x20, 0xbb, 0x4e, 0x5e, 0x0f, + 0x2c, 0xac, 0x72, 0x88, 0x2b, 0x73, 0xac, 0x58, 0x87, 0x16, 0x56, 0x7d, 0xb3, 0xcc, 0x3c, 0xda, + 0x2c, 0x83, 0x6b, 0x9c, 0x1d, 0x59, 0x63, 0x5f, 0xdd, 0x9f, 0xf3, 0xd7, 0xfd, 0xa8, 0x0a, 0x59, + 0xc3, 0xd4, 0x74, 0x53, 0xb3, 0x4f, 0xe9, 0xc6, 0x24, 0x24, 0xf7, 0x19, 0x5d, 0x84, 0x42, 0x0f, + 0xf7, 0x0c, 0x5d, 0xef, 0xca, 0xcc, 0xd9, 0xe4, 0xa9, 0xe8, 0x02, 0x27, 0xd6, 0xa9, 0xcf, 0xf9, + 0x40, 0xf0, 0x4e, 0x9f, 0x87, 0xef, 0x7c, 0xb5, 0xcb, 0xbb, 0x12, 0xb2, 0xbc, 0x3e, 0x0a, 0x99, + 0xc4, 0xc8, 0xfa, 0xba, 0xcf, 0xdf, 0xd4, 0x02, 0x8b, 0x3f, 0xa6, 0xa0, 0x6f, 0x30, 0x37, 0x42, + 0x07, 0xfe, 0xca, 0x6c, 0x40, 0x9d, 0x82, 0x63, 0xce, 0xb3, 0x7a, 0x0f, 0xaf, 0x82, 0x63, 0x64, + 0x0b, 0xbd, 0x09, 0x8f, 0x8f, 0x78, 0x36, 0x57, 0xb5, 0x30, 0xab, 0x83, 0x7b, 0x2c, 0xe8, 0xe0, + 0x1c, 0xd5, 0xde, 0x62, 0x25, 0x1e, 0xf1, 0xcc, 0x6d, 0x43, 0x31, 0x98, 0xe6, 0x85, 0x6e, 0xff, + 0x45, 0x28, 0x98, 0xd8, 0x56, 0xb4, 0xbe, 0x1c, 0xa8, 0x49, 0x17, 0x18, 0x91, 0xe3, 0xbf, 0xfb, + 0xf0, 0x58, 0x68, 0xba, 0x87, 0x5e, 0x84, 0x9c, 0x97, 0x29, 0xb2, 0x55, 0x9d, 0x80, 0xe4, 0x79, + 0xbc, 0xe2, 0xef, 0xe3, 0x9e, 0xca, 0x20, 0x36, 0x58, 0x87, 0xb4, 0x89, 0xad, 0x41, 0x97, 0xa1, + 0x75, 0xc5, 0xf5, 0xe7, 0x66, 0x4b, 0x14, 0x09, 0x75, 0xd0, 0xb5, 0x25, 0x2e, 0x2c, 0x3e, 0x80, + 0x34, 0xa3, 0xa0, 0x3c, 0x64, 0x0e, 0x77, 0xef, 0xee, 0xee, 0xbd, 0xb1, 0x5b, 0x8e, 0x21, 0x80, + 0xf4, 0x46, 0xad, 0x56, 0xdf, 0x6f, 0x96, 0xe3, 0x28, 0x07, 0xa9, 0x8d, 0xcd, 0x3d, 0xa9, 0x59, + 0x16, 0x08, 0x59, 0xaa, 0xdf, 0xa9, 0xd7, 0x9a, 0xe5, 0x04, 0x5a, 0x84, 0x02, 0xfb, 0x2d, 0xdf, + 0xde, 0x93, 0xee, 0x6d, 0x34, 0xcb, 0x49, 0x1f, 0xe9, 0xa0, 0xbe, 0xbb, 0x55, 0x97, 0xca, 0x29, + 0xf1, 0xff, 0xe0, 0x6c, 0x64, 0x6a, 0xe9, 0x01, 0x7f, 0x71, 0x1f, 0xf0, 0x27, 0xfe, 0x5c, 0x80, + 0x6a, 0x74, 0xbe, 0x88, 0xee, 0x8c, 0x4c, 0x7c, 0x7d, 0x8e, 0x64, 0x73, 0x64, 0xf6, 0xe8, 0x12, + 0x14, 0x4d, 0x7c, 0x84, 0xed, 0x76, 0x87, 0xe5, 0xaf, 0x2c, 0x60, 0x16, 0xa4, 0x02, 0xa7, 0x52, + 0x21, 0x8b, 0xb1, 0xbd, 0x8d, 0xdb, 0xb6, 0xcc, 0x7c, 0x11, 0x33, 0xba, 0x1c, 0x61, 0x23, 0xd4, + 0x03, 0x46, 0x14, 0xdf, 0x9a, 0x6b, 0x2d, 0x73, 0x90, 0x92, 0xea, 0x4d, 0xe9, 0xcd, 0x72, 0x02, + 0x21, 0x28, 0xd2, 0x9f, 0xf2, 0xc1, 0xee, 0xc6, 0xfe, 0x41, 0x63, 0x8f, 0xac, 0xe5, 0x12, 0x94, + 0x9c, 0xb5, 0x74, 0x88, 0x29, 0xf1, 0x4f, 0x02, 0x3c, 0x1e, 0x91, 0xed, 0xa2, 0x9b, 0x00, 0xf6, + 0x50, 0x36, 0x71, 0x5b, 0x37, 0xd5, 0x68, 0x23, 0x6b, 0x0e, 0x25, 0xca, 0x21, 0xe5, 0x6c, 0xfe, + 0xcb, 0x9a, 0x80, 0x17, 0xa3, 0x97, 0xb9, 0x52, 0x32, 0x2b, 0xe7, 0xa8, 0x9d, 0x0f, 0x81, 0x45, + 0x71, 0x9b, 0x28, 0xa6, 0x6b, 0x4b, 0x15, 0x53, 0x7e, 0x74, 0x2f, 0xcc, 0xa9, 0xcc, 0xd8, 0xad, + 0x99, 0xcf, 0x9d, 0xa4, 0x1e, 0xcd, 0x9d, 0x88, 0xbf, 0x4a, 0xf8, 0x17, 0x36, 0x98, 0xdc, 0xef, + 0x41, 0xda, 0xb2, 0x15, 0x7b, 0x60, 0x71, 0x83, 0x7b, 0x71, 0xd6, 0x4a, 0x61, 0xcd, 0xf9, 0x71, + 0x40, 0xc5, 0x25, 0xae, 0xe6, 0xdb, 0xf5, 0xb6, 0xc4, 0x1b, 0x50, 0x0c, 0x2e, 0x4e, 0xf4, 0x91, + 0xf1, 0x7c, 0x8e, 0x20, 0xde, 0xf2, 0xf2, 0x2f, 0x1f, 0x68, 0x39, 0x0e, 0x08, 0xc6, 0xc3, 0x00, + 0xc1, 0x5f, 0xc7, 0xe1, 0x89, 0x09, 0xf5, 0x12, 0x7a, 0x7d, 0x64, 0x9f, 0x5f, 0x9a, 0xa7, 0xda, + 0x5a, 0x63, 0xb4, 0xe0, 0x4e, 0x8b, 0xd7, 0x61, 0xc1, 0x4f, 0x9f, 0x6d, 0x92, 0x3f, 0x49, 0x78, + 0x3e, 0x3f, 0x88, 0x5c, 0x7e, 0x65, 0x89, 0xe6, 0x88, 0x9d, 0x09, 0x73, 0xda, 0x59, 0x68, 0xb2, + 0x90, 0xf8, 0xfa, 0x92, 0x85, 0xe4, 0x23, 0x26, 0x0b, 0xfe, 0x03, 0x97, 0x0a, 0x1e, 0xb8, 0xb1, + 0xb8, 0x9e, 0x0e, 0x89, 0xeb, 0x6f, 0x02, 0xf8, 0x1a, 0x9a, 0xcb, 0x90, 0x32, 0xf5, 0x41, 0x5f, + 0xa5, 0x66, 0x92, 0x92, 0xd8, 0x03, 0xba, 0x01, 0x29, 0x62, 0x6e, 0xce, 0x62, 0x8e, 0x7b, 0x5e, + 0x62, 0x2e, 0x3e, 0xcc, 0x98, 0x71, 0x8b, 0x1a, 0xa0, 0xf1, 0xa6, 0x52, 0xc4, 0x27, 0x5e, 0x09, + 0x7e, 0xe2, 0xc9, 0xc8, 0xf6, 0x54, 0xf8, 0xa7, 0xde, 0x83, 0x14, 0x35, 0x0f, 0x92, 0xdf, 0xd0, + 0xc6, 0x28, 0x2f, 0x98, 0xc9, 0x6f, 0xf4, 0x43, 0x00, 0xc5, 0xb6, 0x4d, 0xad, 0x35, 0xf0, 0x3e, + 0xb0, 0x1a, 0x6e, 0x5e, 0x1b, 0x0e, 0xdf, 0xe6, 0x39, 0x6e, 0x67, 0xcb, 0x9e, 0xa8, 0xcf, 0xd6, + 0x7c, 0x0a, 0xc5, 0x5d, 0x28, 0x06, 0x65, 0x9d, 0x12, 0x8f, 0x8d, 0x21, 0x58, 0xe2, 0xb1, 0x8a, + 0x9d, 0x97, 0x78, 0x6e, 0x81, 0x98, 0x60, 0x3d, 0x70, 0xfa, 0x20, 0xfe, 0x2b, 0x0e, 0x0b, 0x7e, + 0xeb, 0xfc, 0x5f, 0xab, 0x92, 0xc4, 0x0f, 0xe2, 0x90, 0x75, 0x27, 0x1f, 0xd1, 0x80, 0xf6, 0xd6, + 0x4e, 0xf0, 0xb7, 0x5b, 0x59, 0x47, 0x3b, 0xe1, 0xf6, 0xc9, 0x6f, 0xb9, 0x09, 0x55, 0x14, 0xa8, + 0xed, 0x5f, 0x69, 0xe7, 0xaa, 0x00, 0xcf, 0x1f, 0x7f, 0xc6, 0xc7, 0x41, 0x32, 0x09, 0xf4, 0x1d, + 0x48, 0x2b, 0x6d, 0x17, 0xca, 0x2f, 0x86, 0x60, 0xbb, 0x0e, 0xeb, 0x5a, 0x73, 0xb8, 0x41, 0x39, + 0x25, 0x2e, 0xc1, 0x47, 0x25, 0xb8, 0x7d, 0xf6, 0x57, 0x89, 0x5e, 0xc6, 0x13, 0x74, 0x9b, 0x45, + 0x80, 0xc3, 0xdd, 0x7b, 0x7b, 0x5b, 0xdb, 0xb7, 0xb7, 0xeb, 0x5b, 0x3c, 0xa5, 0xda, 0xda, 0xaa, + 0x6f, 0x95, 0x05, 0xc2, 0x27, 0xd5, 0xef, 0xed, 0xdd, 0xaf, 0x6f, 0x95, 0x13, 0xe2, 0x2d, 0xc8, + 0xb9, 0xae, 0x07, 0x55, 0x20, 0xe3, 0xb4, 0x25, 0xe2, 0xdc, 0x01, 0xf0, 0x2e, 0xd3, 0x32, 0xa4, + 0x0c, 0xfd, 0x5d, 0xde, 0x65, 0x4e, 0x48, 0xec, 0x41, 0x54, 0xa1, 0x34, 0xe2, 0xb7, 0xd0, 0x2d, + 0xc8, 0x18, 0x83, 0x96, 0xec, 0x18, 0xed, 0x48, 0x13, 0xc7, 0x41, 0x1a, 0x06, 0xad, 0xae, 0xd6, + 0xbe, 0x8b, 0x4f, 0x9d, 0x65, 0x32, 0x06, 0xad, 0xbb, 0xcc, 0xb6, 0xd9, 0x57, 0x04, 0xff, 0x57, + 0x7e, 0x14, 0x87, 0xac, 0x73, 0x56, 0xd1, 0x77, 0x21, 0xe7, 0xfa, 0x44, 0xf7, 0xee, 0x4d, 0xa4, + 0x33, 0xe5, 0xfa, 0x3d, 0x11, 0x74, 0x15, 0x16, 0x2d, 0xed, 0xb8, 0xef, 0xf4, 0xb0, 0x18, 0xb4, + 0x27, 0xd0, 0x43, 0x53, 0x62, 0x2f, 0x76, 0x1c, 0x3c, 0xea, 0x4e, 0x32, 0x9b, 0x28, 0x27, 0xef, + 0x24, 0xb3, 0xc9, 0x72, 0x8a, 0x84, 0xc5, 0xf2, 0xa8, 0xe3, 0xf8, 0x26, 0x07, 0x13, 0x12, 0xbe, + 0x13, 0x61, 0xe1, 0xfb, 0x7d, 0x01, 0xf2, 0xbe, 0x2e, 0x19, 0xfa, 0x7f, 0x9f, 0x17, 0x2b, 0x86, + 0xc4, 0x1d, 0x1f, 0xaf, 0x77, 0xc5, 0x23, 0x38, 0x31, 0x61, 0xfe, 0x89, 0x45, 0x35, 0x25, 0x9d, + 0x66, 0x5b, 0x72, 0xee, 0x66, 0xdb, 0xb3, 0x80, 0x6c, 0xdd, 0x56, 0xba, 0xf2, 0x89, 0x6e, 0x6b, + 0xfd, 0x63, 0x99, 0xd9, 0x09, 0xf3, 0x39, 0x65, 0xfa, 0xe6, 0x3e, 0x7d, 0xb1, 0xef, 0x9a, 0x8c, + 0x5b, 0x03, 0xce, 0x7b, 0x63, 0xe3, 0x0c, 0xa4, 0x79, 0x99, 0xc3, 0xae, 0x6c, 0xf0, 0xa7, 0xd0, + 0xae, 0x62, 0x15, 0xb2, 0x3d, 0x6c, 0x2b, 0xd4, 0x81, 0xb2, 0x98, 0xe9, 0x3e, 0x5f, 0x7d, 0x09, + 0xf2, 0xbe, 0xcb, 0x33, 0xc4, 0xa7, 0xee, 0xd6, 0xdf, 0x28, 0xc7, 0xaa, 0x99, 0x0f, 0x3f, 0xbe, + 0x90, 0xd8, 0xc5, 0xef, 0x92, 0xe3, 0x26, 0xd5, 0x6b, 0x8d, 0x7a, 0xed, 0x6e, 0x39, 0x5e, 0xcd, + 0x7f, 0xf8, 0xf1, 0x85, 0x8c, 0x84, 0x69, 0x13, 0xe8, 0xea, 0x5d, 0x28, 0x8d, 0x6c, 0x4c, 0xf0, + 0x74, 0x23, 0x28, 0x6e, 0x1d, 0xee, 0xef, 0x6c, 0xd7, 0x36, 0x9a, 0x75, 0xf9, 0xfe, 0x5e, 0xb3, + 0x5e, 0x8e, 0xa3, 0xc7, 0x61, 0x69, 0x67, 0xfb, 0xb5, 0x46, 0x53, 0xae, 0xed, 0x6c, 0xd7, 0x77, + 0x9b, 0xf2, 0x46, 0xb3, 0xb9, 0x51, 0xbb, 0x5b, 0x16, 0xd6, 0x7f, 0x93, 0x87, 0xd2, 0xc6, 0x66, + 0x6d, 0x9b, 0x14, 0x7a, 0x5a, 0x5b, 0xa1, 0xbe, 0xa2, 0x06, 0x49, 0x8a, 0x28, 0x4f, 0xbc, 0x0e, + 0x5d, 0x9d, 0xdc, 0x25, 0x44, 0xb7, 0x21, 0x45, 0xc1, 0x66, 0x34, 0xf9, 0x7e, 0x74, 0x75, 0x4a, + 0xdb, 0x90, 0x0c, 0x86, 0x1e, 0xa7, 0x89, 0x17, 0xa6, 0xab, 0x93, 0xbb, 0x88, 0x68, 0x07, 0x32, + 0x0e, 0x16, 0x38, 0xed, 0xea, 0x71, 0x75, 0x6a, 0x3b, 0x8e, 0x4c, 0x8d, 0x61, 0xb6, 0x93, 0xef, + 0x52, 0x57, 0xa7, 0xf4, 0x17, 0xd1, 0x36, 0xa4, 0x39, 0x5c, 0x32, 0xe5, 0x1a, 0x71, 0x75, 0x5a, + 0x5b, 0x0d, 0x49, 0x90, 0xf3, 0xd0, 0xf0, 0xe9, 0x37, 0xc4, 0xab, 0x33, 0xb4, 0x4e, 0xd1, 0x03, + 0x28, 0x04, 0x21, 0x98, 0xd9, 0xae, 0x2a, 0x57, 0x67, 0x6c, 0xe0, 0x11, 0xfd, 0x41, 0x3c, 0x66, + 0xb6, 0xab, 0xcb, 0xd5, 0x19, 0xfb, 0x79, 0xe8, 0x6d, 0x58, 0x1c, 0xc7, 0x4b, 0x66, 0xbf, 0xc9, + 0x5c, 0x9d, 0xa3, 0xc3, 0x87, 0x7a, 0x80, 0x42, 0x70, 0x96, 0x39, 0x2e, 0x36, 0x57, 0xe7, 0x69, + 0xf8, 0x21, 0x15, 0x4a, 0xa3, 0xd8, 0xc5, 0xac, 0x17, 0x9d, 0xab, 0x33, 0x37, 0xff, 0xd8, 0x57, + 0x82, 0x85, 0xfc, 0xac, 0x17, 0x9f, 0xab, 0x33, 0xf7, 0x02, 0xd1, 0x21, 0x80, 0xaf, 0x10, 0x9d, + 0xe1, 0x22, 0x74, 0x75, 0x96, 0xae, 0x20, 0x32, 0x60, 0x29, 0xac, 0x42, 0x9d, 0xe7, 0x5e, 0x74, + 0x75, 0xae, 0x66, 0x21, 0xb1, 0xe7, 0x60, 0xad, 0x39, 0xdb, 0x3d, 0xe9, 0xea, 0x8c, 0x5d, 0xc3, + 0xcd, 0xfa, 0x27, 0x9f, 0xaf, 0xc4, 0x3f, 0xfd, 0x7c, 0x25, 0xfe, 0xf7, 0xcf, 0x57, 0xe2, 0x1f, + 0x7d, 0xb1, 0x12, 0xfb, 0xf4, 0x8b, 0x95, 0xd8, 0x5f, 0xbe, 0x58, 0x89, 0x7d, 0xef, 0x99, 0x63, + 0xcd, 0xee, 0x0c, 0x5a, 0x6b, 0x6d, 0xbd, 0x77, 0xcd, 0xff, 0x97, 0x99, 0xb0, 0xbf, 0xf1, 0xb4, + 0xd2, 0x34, 0xa0, 0x5e, 0xff, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x97, 0x52, 0xf8, 0x77, 0xe6, + 0x33, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -6222,15 +6265,15 @@ func (m *RequestExtendVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Vote != nil { - { - size, err := m.Vote.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } + if m.Height != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x10 + } + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Hash))) i-- dAtA[i] = 0xa } @@ -6257,15 +6300,29 @@ func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l - if m.Vote != nil { - { - size, err := m.Vote.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } + if len(m.VoteExtension) > 0 { + i -= len(m.VoteExtension) + copy(dAtA[i:], m.VoteExtension) + i = encodeVarintTypes(dAtA, i, uint64(len(m.VoteExtension))) + i-- + dAtA[i] = 0x22 + } + if m.Height != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x18 + } + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Hash))) i-- dAtA[i] = 0xa } @@ -6306,12 +6363,12 @@ func (m *RequestFinalizeBlock) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x3a } - n31, err31 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err31 != nil { - return 0, err31 + n29, err29 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err29 != nil { + return 0, err29 } - i -= n31 - i = encodeVarintTypes(dAtA, i, uint64(n31)) + i -= n29 + i = encodeVarintTypes(dAtA, i, uint64(n29)) i-- dAtA[i] = 0x32 if m.Height != 0 { @@ -7541,20 +7598,20 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } } if len(m.RefetchChunks) > 0 { - dAtA57 := make([]byte, len(m.RefetchChunks)*10) - var j56 int + dAtA55 := make([]byte, len(m.RefetchChunks)*10) + var j54 int for _, num := range m.RefetchChunks { for num >= 1<<7 { - dAtA57[j56] = uint8(uint64(num)&0x7f | 0x80) + dAtA55[j54] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j56++ + j54++ } - dAtA57[j56] = uint8(num) - j56++ + dAtA55[j54] = uint8(num) + j54++ } - i -= j56 - copy(dAtA[i:], dAtA57[:j56]) - i = encodeVarintTypes(dAtA, i, uint64(j56)) + i -= j54 + copy(dAtA[i:], dAtA55[:j54]) + i = encodeVarintTypes(dAtA, i, uint64(j54)) i-- dAtA[i] = 0x12 } @@ -7745,15 +7802,10 @@ func (m *ResponseExtendVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.VoteExtension != nil { - { - size, err := m.VoteExtension.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } + if len(m.VoteExtension) > 0 { + i -= len(m.VoteExtension) + copy(dAtA[i:], m.VoteExtension) + i = encodeVarintTypes(dAtA, i, uint64(len(m.VoteExtension))) i-- dAtA[i] = 0xa } @@ -8408,12 +8460,12 @@ func (m *Misbehavior) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n66, err66 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err66 != nil { - return 0, err66 + n63, err63 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err63 != nil { + return 0, err63 } - i -= n66 - i = encodeVarintTypes(dAtA, i, uint64(n66)) + i -= n63 + i = encodeVarintTypes(dAtA, i, uint64(n63)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -9064,10 +9116,13 @@ func (m *RequestExtendVote) Size() (n int) { } var l int _ = l - if m.Vote != nil { - l = m.Vote.Size() + l = len(m.Hash) + if l > 0 { n += 1 + l + sovTypes(uint64(l)) } + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } return n } @@ -9077,8 +9132,19 @@ func (m *RequestVerifyVoteExtension) Size() (n int) { } var l int _ = l - if m.Vote != nil { - l = m.Vote.Size() + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.Height != 0 { + n += 1 + sovTypes(uint64(m.Height)) + } + l = len(m.VoteExtension) + if l > 0 { n += 1 + l + sovTypes(uint64(l)) } return n @@ -9788,8 +9854,8 @@ func (m *ResponseExtendVote) Size() (n int) { } var l int _ = l - if m.VoteExtension != nil { - l = m.VoteExtension.Size() + l = len(m.VoteExtension) + if l > 0 { n += 1 + l + sovTypes(uint64(l)) } return n @@ -13029,9 +13095,9 @@ func (m *RequestExtendVote) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Vote", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -13041,28 +13107,45 @@ func (m *RequestExtendVote) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - if m.Vote == nil { - m.Vote = &types1.Vote{} - } - if err := m.Vote.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} } iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -13115,9 +13198,9 @@ func (m *RequestVerifyVoteExtension) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Vote", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -13127,26 +13210,111 @@ func (m *RequestVerifyVoteExtension) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - if m.Vote == nil { - m.Vote = &types1.Vote{} + m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} } - if err := m.Vote.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorAddress = append(m.ValidatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.ValidatorAddress == nil { + m.ValidatorAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.VoteExtension = append(m.VoteExtension[:0], dAtA[iNdEx:postIndex]...) + if m.VoteExtension == nil { + m.VoteExtension = []byte{} } iNdEx = postIndex default: @@ -16926,7 +17094,7 @@ func (m *ResponseExtendVote) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -16936,26 +17104,24 @@ func (m *ResponseExtendVote) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } + m.VoteExtension = append(m.VoteExtension[:0], dAtA[iNdEx:postIndex]...) if m.VoteExtension == nil { - m.VoteExtension = &types1.VoteExtension{} - } - if err := m.VoteExtension.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.VoteExtension = []byte{} } iNdEx = postIndex default: diff --git a/go.mod b/go.mod index 92c54d106..4dba71354 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/creachadair/taskgroup v0.3.2 github.com/golangci/golangci-lint v1.45.2 github.com/google/go-cmp v0.5.7 - github.com/vektra/mockery/v2 v2.10.6 + github.com/vektra/mockery/v2 v2.11.0 gotest.tools v2.2.0+incompatible ) diff --git a/go.sum b/go.sum index 60f26f779..718795458 100644 --- a/go.sum +++ b/go.sum @@ -1055,8 +1055,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vektra/mockery/v2 v2.10.6 h1:iLVqC9FozavYx27ZwfXipuizLBN8YzXlh9x5fufk48w= -github.com/vektra/mockery/v2 v2.10.6/go.mod h1:8vf4KDDUptfkyypzdHLuE7OE2xA7Gdt60WgIS8PgD+U= +github.com/vektra/mockery/v2 v2.11.0 h1:9NkC3urGvJS9B0ve5aTbFjksbO9f/u5cZFgCTVJ30jg= +github.com/vektra/mockery/v2 v2.11.0/go.mod h1:8vf4KDDUptfkyypzdHLuE7OE2xA7Gdt60WgIS8PgD+U= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= diff --git a/internal/blocksync/reactor.go b/internal/blocksync/reactor.go index 6f3743e62..fd9bf4d7a 100644 --- a/internal/blocksync/reactor.go +++ b/internal/blocksync/reactor.go @@ -359,7 +359,7 @@ func (r *Reactor) SwitchToBlockSync(ctx context.Context, state sm.State) error { go r.requestRoutine(ctx, bsCh) go r.poolRoutine(ctx, true, bsCh) - if err := r.PublishStatus(ctx, types.EventDataBlockSyncStatus{ + if err := r.PublishStatus(types.EventDataBlockSyncStatus{ Complete: false, Height: state.LastBlockHeight, }); err != nil { @@ -609,11 +609,11 @@ func (r *Reactor) GetRemainingSyncTime() time.Duration { return time.Duration(int64(remain * float64(time.Second))) } -func (r *Reactor) PublishStatus(ctx context.Context, event types.EventDataBlockSyncStatus) error { +func (r *Reactor) PublishStatus(event types.EventDataBlockSyncStatus) error { if r.eventBus == nil { return errors.New("event bus is not configured") } - return r.eventBus.PublishEventBlockSyncStatus(ctx, event) + return r.eventBus.PublishEventBlockSyncStatus(event) } // atomicBool is an atomic Boolean, safe for concurrent use by multiple diff --git a/internal/blocksync/reactor_test.go b/internal/blocksync/reactor_test.go index 065d75301..857b0a519 100644 --- a/internal/blocksync/reactor_test.go +++ b/internal/blocksync/reactor_test.go @@ -50,7 +50,6 @@ func setup( genDoc *types.GenesisDoc, privVal types.PrivValidator, maxBlockHeights []int64, - chBuf uint, ) *reactorTestSuite { t.Helper() @@ -228,7 +227,7 @@ func TestReactor_AbruptDisconnect(t *testing.T) { genDoc := factory.GenesisDoc(cfg, time.Now(), valSet.Validators, factory.ConsensusParams()) maxBlockHeight := int64(64) - rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0) + rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}) require.Equal(t, maxBlockHeight, rts.reactors[rts.nodes[0]].store.Height()) @@ -268,7 +267,7 @@ func TestReactor_SyncTime(t *testing.T) { genDoc := factory.GenesisDoc(cfg, time.Now(), valSet.Validators, factory.ConsensusParams()) maxBlockHeight := int64(101) - rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0) + rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}) require.Equal(t, maxBlockHeight, rts.reactors[rts.nodes[0]].store.Height()) rts.start(ctx, t) @@ -296,7 +295,7 @@ func TestReactor_NoBlockResponse(t *testing.T) { genDoc := factory.GenesisDoc(cfg, time.Now(), valSet.Validators, factory.ConsensusParams()) maxBlockHeight := int64(65) - rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0) + rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}) require.Equal(t, maxBlockHeight, rts.reactors[rts.nodes[0]].store.Height()) @@ -348,7 +347,7 @@ func TestReactor_BadBlockStopsPeer(t *testing.T) { valSet, privVals := factory.ValidatorSet(ctx, t, 1, 30) genDoc := factory.GenesisDoc(cfg, time.Now(), valSet.Validators, factory.ConsensusParams()) - rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0, 0, 0, 0}, 1000) + rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0, 0, 0, 0}) require.Equal(t, maxBlockHeight, rts.reactors[rts.nodes[0]].store.Height()) diff --git a/internal/consensus/byzantine_test.go b/internal/consensus/byzantine_test.go index cfcf8b04f..2093a4aec 100644 --- a/internal/consensus/byzantine_test.go +++ b/internal/consensus/byzantine_test.go @@ -96,7 +96,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { // Make State blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyAppConnCon, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) - cs, err := NewState(ctx, logger, thisConfig.Consensus, stateStore, blockExec, blockStore, mempool, evpool, eventBus) + cs, err := NewState(logger, thisConfig.Consensus, stateStore, blockExec, blockStore, mempool, evpool, eventBus) require.NoError(t, err) // set private validator pv := privVals[i] @@ -203,7 +203,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { proposerAddr := lazyNodeState.privValidatorPubKey.Address() block, err := lazyNodeState.blockExec.CreateProposalBlock( - ctx, lazyNodeState.Height, lazyNodeState.state, commit, proposerAddr, nil) + ctx, lazyNodeState.Height, lazyNodeState.state, commit, proposerAddr, lazyNodeState.LastCommit.GetVotes()) require.NoError(t, err) blockParts, err := block.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index a69fc1240..8a19ef85a 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -112,7 +112,8 @@ func (vs *validatorStub) signVote( ctx context.Context, voteType tmproto.SignedMsgType, chainID string, - blockID types.BlockID) (*types.Vote, error) { + blockID types.BlockID, + voteExtension []byte) (*types.Vote, error) { pubKey, err := vs.PrivValidator.GetPubKey(ctx) if err != nil { @@ -120,28 +121,30 @@ func (vs *validatorStub) signVote( } vote := &types.Vote{ - ValidatorIndex: vs.Index, - ValidatorAddress: pubKey.Address(), + Type: voteType, Height: vs.Height, Round: vs.Round, - Timestamp: vs.clock.Now(), - Type: voteType, BlockID: blockID, - VoteExtension: types.VoteExtensionFromProto(kvstore.ConstructVoteExtension(pubKey.Address())), + Timestamp: vs.clock.Now(), + ValidatorAddress: pubKey.Address(), + ValidatorIndex: vs.Index, + Extension: voteExtension, } v := vote.ToProto() - if err := vs.PrivValidator.SignVote(ctx, chainID, v); err != nil { + if err = vs.PrivValidator.SignVote(ctx, chainID, v); err != nil { return nil, fmt.Errorf("sign vote failed: %w", err) } - // ref: signVote in FilePV, the vote should use the privious vote info when the sign data is the same. + // ref: signVote in FilePV, the vote should use the previous vote info when the sign data is the same. if signDataIsEqual(vs.lastVote, v) { v.Signature = vs.lastVote.Signature v.Timestamp = vs.lastVote.Timestamp + v.ExtensionSignature = vs.lastVote.ExtensionSignature } vote.Signature = v.Signature vote.Timestamp = v.Timestamp + vote.ExtensionSignature = v.ExtensionSignature return vote, err } @@ -155,13 +158,9 @@ func signVote( chainID string, blockID types.BlockID) *types.Vote { - v, err := vs.signVote(ctx, voteType, chainID, blockID) + v, err := vs.signVote(ctx, voteType, chainID, blockID, []byte("extension")) require.NoError(t, err, "failed to sign vote") - // 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 @@ -351,18 +350,19 @@ func validatePrecommit( require.True(t, bytes.Equal(vote.BlockID.Hash, votedBlockHash), "Expected precommit to be for proposal block") } + rs := cs.GetRoundState() if lockedBlockHash == nil { - require.False(t, cs.LockedRound != lockRound || cs.LockedBlock != nil, + require.False(t, rs.LockedRound != lockRound || rs.LockedBlock != nil, "Expected to be locked on nil at round %d. Got locked at round %d with block %v", lockRound, - cs.LockedRound, - cs.LockedBlock) + rs.LockedRound, + rs.LockedBlock) } else { - require.False(t, cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash), + require.False(t, rs.LockedRound != lockRound || !bytes.Equal(rs.LockedBlock.Hash(), lockedBlockHash), "Expected block to be locked on round %d, got %d. Got locked block %X, expected %X", lockRound, - cs.LockedRound, - cs.LockedBlock.Hash(), + rs.LockedRound, + rs.LockedBlock.Hash(), lockedBlockHash) } } @@ -491,8 +491,7 @@ func newStateWithConfigAndBlockStore( require.NoError(t, eventBus.Start(ctx)) blockExec := sm.NewBlockExecutor(stateStore, logger, proxyAppConnCon, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) - cs, err := NewState(ctx, - logger.With("module", "consensus"), + cs, err := NewState(logger.With("module", "consensus"), thisConfig.Consensus, stateStore, blockExec, @@ -731,10 +730,9 @@ func ensureVoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, msg.Data()) vote := voteEvent.Vote - require.Equal(t, height, vote.Height) - require.Equal(t, round, vote.Round) - - require.Equal(t, voteType, vote.Type) + require.Equal(t, height, vote.Height, "expected height %d, but got %d", height, vote.Height) + require.Equal(t, round, vote.Round, "expected round %d, but got %d", round, vote.Round) + require.Equal(t, voteType, vote.Type, "expected type %s, but got %s", voteType, vote.Type) if hash == nil { require.Nil(t, vote.BlockID.Hash, "Expected prevote to be for nil, got %X", vote.BlockID.Hash) } else { @@ -742,6 +740,7 @@ func ensureVoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, } } } + func ensureVote(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, voteType tmproto.SignedMsgType) { t.Helper() msg := ensureMessageBeforeTimeout(t, voteCh, ensureTimeout) @@ -750,10 +749,9 @@ func ensureVote(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, roun msg.Data()) vote := voteEvent.Vote - require.Equal(t, height, vote.Height) - require.Equal(t, round, vote.Round) - - require.Equal(t, voteType, vote.Type) + require.Equal(t, height, vote.Height, "expected height %d, but got %d", height, vote.Height) + require.Equal(t, round, vote.Round, "expected round %d, but got %d", round, vote.Round) + require.Equal(t, voteType, vote.Type, "expected type %s, but got %s", voteType, vote.Type) } func ensureNewEventOnChannel(t *testing.T, ch <-chan tmpubsub.Message) { @@ -987,5 +985,6 @@ func signDataIsEqual(v1 *types.Vote, v2 *tmproto.Vote) bool { v1.Height == v2.GetHeight() && v1.Round == v2.Round && bytes.Equal(v1.ValidatorAddress.Bytes(), v2.GetValidatorAddress()) && - v1.ValidatorIndex == v2.GetValidatorIndex() + v1.ValidatorIndex == v2.GetValidatorIndex() && + bytes.Equal(v1.Extension, v2.Extension) } diff --git a/internal/consensus/msgs_test.go b/internal/consensus/msgs_test.go index e85936820..cfbd53ff7 100644 --- a/internal/consensus/msgs_test.go +++ b/internal/consensus/msgs_test.go @@ -357,11 +357,6 @@ func TestConsMsgsVectors(t *testing.T) { } pbProposal := proposal.ToProto() - ext := types.VoteExtension{ - AppDataToSign: []byte("signed"), - AppDataSelfAuthenticating: []byte("auth"), - } - v := &types.Vote{ ValidatorAddress: []byte("add_more_exclamation"), ValidatorIndex: 1, @@ -370,7 +365,7 @@ func TestConsMsgsVectors(t *testing.T) { Timestamp: date, Type: tmproto.PrecommitType, BlockID: bi, - VoteExtension: ext, + Extension: []byte("extension"), } vpb := v.ToProto() @@ -407,7 +402,7 @@ func TestConsMsgsVectors(t *testing.T) { "2a36080110011a3008011204746573741a26080110011a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d"}, {"Vote", &tmcons.Message{Sum: &tmcons.Message_Vote{ Vote: &tmcons.Vote{Vote: vpb}}}, - "3280010a7e0802100122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a0608c0b89fdc0532146164645f6d6f72655f6578636c616d6174696f6e38014a0e0a067369676e6564120461757468"}, + "327b0a790802100122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a0608c0b89fdc0532146164645f6d6f72655f6578636c616d6174696f6e38014a09657874656e73696f6e"}, {"HasVote", &tmcons.Message{Sum: &tmcons.Message_HasVote{ HasVote: &tmcons.HasVote{Height: 1, Round: 1, Type: tmproto.PrevoteType, Index: 1}}}, "3a080801100118012001"}, diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go index 18589c93a..53e0b540d 100644 --- a/internal/consensus/reactor.go +++ b/internal/consensus/reactor.go @@ -210,7 +210,7 @@ func (r *Reactor) OnStart(ctx context.Context) error { // leak the goroutine when stopping the reactor. go r.peerStatsRoutine(ctx, peerUpdates) - r.subscribeToBroadcastEvents(chBundle.state) + r.subscribeToBroadcastEvents(ctx, chBundle.state) if !r.WaitSync() { if err := r.state.Start(ctx); err != nil { @@ -260,7 +260,7 @@ func (r *Reactor) SwitchToConsensus(ctx context.Context, state sm.State, skipWAL // NOTE: The line below causes broadcastNewRoundStepRoutine() to broadcast a // NewRoundStepMessage. - r.state.updateToState(ctx, state) + r.state.updateToState(state) if err := r.state.Start(ctx); err != nil { panic(fmt.Sprintf(`failed to start consensus state: %v @@ -284,7 +284,7 @@ conR: } d := types.EventDataBlockSyncStatus{Complete: true, Height: state.LastBlockHeight} - if err := r.eventBus.PublishEventBlockSyncStatus(ctx, d); err != nil { + if err := r.eventBus.PublishEventBlockSyncStatus(d); err != nil { r.logger.Error("failed to emit the blocksync complete event", "err", err) } } @@ -344,13 +344,13 @@ func (r *Reactor) broadcastHasVoteMessage(ctx context.Context, vote *types.Vote, // subscribeToBroadcastEvents subscribes for new round steps and votes using the // internal pubsub defined in the consensus state to broadcast them to peers // upon receiving. -func (r *Reactor) subscribeToBroadcastEvents(stateCh *p2p.Channel) { +func (r *Reactor) subscribeToBroadcastEvents(ctx context.Context, stateCh *p2p.Channel) { onStopCh := r.state.getOnStopCh() err := r.state.evsw.AddListenerForEvent( listenerIDConsensus, types.EventNewRoundStepValue, - func(ctx context.Context, data tmevents.EventData) error { + func(data tmevents.EventData) error { if err := r.broadcastNewRoundStepMessage(ctx, data.(*cstypes.RoundState), stateCh); err != nil { return err } @@ -371,7 +371,7 @@ func (r *Reactor) subscribeToBroadcastEvents(stateCh *p2p.Channel) { err = r.state.evsw.AddListenerForEvent( listenerIDConsensus, types.EventValidBlockValue, - func(ctx context.Context, data tmevents.EventData) error { + func(data tmevents.EventData) error { return r.broadcastNewValidBlockMessage(ctx, data.(*cstypes.RoundState), stateCh) }, ) @@ -382,7 +382,7 @@ func (r *Reactor) subscribeToBroadcastEvents(stateCh *p2p.Channel) { err = r.state.evsw.AddListenerForEvent( listenerIDConsensus, types.EventVoteValue, - func(ctx context.Context, data tmevents.EventData) error { + func(data tmevents.EventData) error { return r.broadcastHasVoteMessage(ctx, data.(*types.Vote), stateCh) }, ) diff --git a/internal/consensus/reactor_test.go b/internal/consensus/reactor_test.go index 9c6af5c5b..6a92b984f 100644 --- a/internal/consensus/reactor_test.go +++ b/internal/consensus/reactor_test.go @@ -505,7 +505,7 @@ func TestReactorWithEvidence(t *testing.T) { blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyAppConnCon, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) - cs, err := NewState(ctx, logger.With("validator", i, "module", "consensus"), + cs, err := NewState(logger.With("validator", i, "module", "consensus"), thisConfig.Consensus, stateStore, blockExec, blockStore, mempool, evpool2, eventBus) require.NoError(t, err) cs.SetPrivValidator(ctx, pv) diff --git a/internal/consensus/replay.go b/internal/consensus/replay.go index 3b2dea930..17435d273 100644 --- a/internal/consensus/replay.go +++ b/internal/consensus/replay.go @@ -429,7 +429,7 @@ func (h *Handshaker) ReplayBlocks( if err != nil { return nil, err } - mockApp, err := newMockProxyApp(ctx, h.logger, appHash, abciResponses) + mockApp, err := newMockProxyApp(h.logger, appHash, abciResponses) if err != nil { return nil, err } diff --git a/internal/consensus/replay_file.go b/internal/consensus/replay_file.go index e88a06454..cd6d4b831 100644 --- a/internal/consensus/replay_file.go +++ b/internal/consensus/replay_file.go @@ -145,7 +145,7 @@ func (pb *playback) replayReset(ctx context.Context, count int, newStepSub event pb.cs.Stop() pb.cs.Wait() - newCS, err := NewState(ctx, pb.cs.logger, pb.cs.config, pb.stateStore, pb.cs.blockExec, + newCS, err := NewState(pb.cs.logger, pb.cs.config, pb.stateStore, pb.cs.blockExec, pb.cs.blockStore, pb.cs.txNotifier, pb.cs.evpool, pb.cs.eventBus) if err != nil { return err @@ -350,7 +350,7 @@ func newConsensusStateForReplay( mempool, evpool := emptyMempool{}, sm.EmptyEvidencePool{} blockExec := sm.NewBlockExecutor(stateStore, logger, proxyApp, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) - consensusState, err := NewState(ctx, logger, csConfig, stateStore, blockExec, + consensusState, err := NewState(logger, csConfig, stateStore, blockExec, blockStore, mempool, evpool, eventBus) if err != nil { return nil, err diff --git a/internal/consensus/replay_stubs.go b/internal/consensus/replay_stubs.go index e479d344e..e8f5cbc4b 100644 --- a/internal/consensus/replay_stubs.go +++ b/internal/consensus/replay_stubs.go @@ -57,7 +57,6 @@ func (emptyMempool) CloseWAL() {} // the real app. func newMockProxyApp( - ctx context.Context, logger log.Logger, appHash []byte, abciResponses *tmstate.ABCIResponses, diff --git a/internal/consensus/state.go b/internal/consensus/state.go index 2f27afc81..490801ad2 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -194,7 +194,6 @@ func SkipStateStoreBootstrap(sm *State) { // NewState returns a new State. func NewState( - ctx context.Context, logger log.Logger, cfg *config.ConsensusConfig, store sm.Store, @@ -240,7 +239,7 @@ func NewState( // node-fragments gracefully while letting the nodes // themselves avoid this. if !cs.skipBootstrapping { - if err := cs.updateStateFromStore(ctx); err != nil { + if err := cs.updateStateFromStore(); err != nil { return nil, err } } @@ -248,7 +247,7 @@ func NewState( return cs, nil } -func (cs *State) updateStateFromStore(ctx context.Context) error { +func (cs *State) updateStateFromStore() error { if cs.initialStatePopulated { return nil } @@ -265,7 +264,7 @@ func (cs *State) updateStateFromStore(ctx context.Context) error { cs.reconstructLastCommit(state) } - cs.updateToState(ctx, state) + cs.updateToState(state) cs.initialStatePopulated = true return nil @@ -393,7 +392,7 @@ func (cs *State) LoadCommit(height int64) *types.Commit { // OnStart loads the latest state via the WAL, and starts the timeout and // receive routines. func (cs *State) OnStart(ctx context.Context) error { - if err := cs.updateStateFromStore(ctx); err != nil { + if err := cs.updateStateFromStore(); err != nil { return err } @@ -718,7 +717,7 @@ func (cs *State) reconstructLastCommit(state sm.State) { // Updates State and increments height to match that of state. // The round becomes 0 and cs.Step becomes cstypes.RoundStepNewHeight. -func (cs *State) updateToState(ctx context.Context, state sm.State) { +func (cs *State) updateToState(state sm.State) { if cs.CommitRound > -1 && 0 < cs.Height && cs.Height != state.LastBlockHeight { panic(fmt.Sprintf( "updateToState() expected state height of %v but found %v", @@ -753,7 +752,7 @@ func (cs *State) updateToState(ctx context.Context, state sm.State) { "new_height", state.LastBlockHeight+1, "old_height", cs.state.LastBlockHeight+1, ) - cs.newStep(ctx) + cs.newStep() return } } @@ -823,10 +822,10 @@ func (cs *State) updateToState(ctx context.Context, state sm.State) { cs.state = state // Finally, broadcast RoundState - cs.newStep(ctx) + cs.newStep() } -func (cs *State) newStep(ctx context.Context) { +func (cs *State) newStep() { rs := cs.RoundStateEvent() if err := cs.wal.Write(rs); err != nil { cs.logger.Error("failed writing to WAL", "err", err) @@ -836,11 +835,11 @@ func (cs *State) newStep(ctx context.Context) { // newStep is called by updateToState in NewState before the eventBus is set! if cs.eventBus != nil { - if err := cs.eventBus.PublishEventNewRoundStep(ctx, rs); err != nil { + if err := cs.eventBus.PublishEventNewRoundStep(rs); err != nil { cs.logger.Error("failed publishing new round step", "err", err) } - cs.evsw.FireEvent(ctx, types.EventNewRoundStepValue, &cs.RoundState) + cs.evsw.FireEvent(types.EventNewRoundStepValue, &cs.RoundState) } } @@ -923,7 +922,6 @@ func (cs *State) receiveRoutine(ctx context.Context, maxSteps int) { if err := cs.wal.Write(mi); err != nil { cs.logger.Error("failed writing to WAL", "err", err) } - // handles proposals, block parts, votes // may generate internal events (votes, complete proposals, 2/3 majorities) cs.handleMsg(ctx, mi) @@ -977,7 +975,7 @@ func (cs *State) handleMsg(ctx context.Context, mi msgInfo) { case *BlockPartMessage: // if the proposal is complete, we'll enterPrevote or tryFinalizeCommit - added, err = cs.addProposalBlockPart(ctx, msg, peerID) + added, err = cs.addProposalBlockPart(msg, peerID) // We unlock here to yield to any routines that need to read the the RoundState. // Previously, this code held the lock from the point at which the final block @@ -1083,21 +1081,21 @@ func (cs *State) handleTimeout( cs.enterPropose(ctx, ti.Height, 0) case cstypes.RoundStepPropose: - if err := cs.eventBus.PublishEventTimeoutPropose(ctx, cs.RoundStateEvent()); err != nil { + if err := cs.eventBus.PublishEventTimeoutPropose(cs.RoundStateEvent()); err != nil { cs.logger.Error("failed publishing timeout propose", "err", err) } cs.enterPrevote(ctx, ti.Height, ti.Round) case cstypes.RoundStepPrevoteWait: - if err := cs.eventBus.PublishEventTimeoutWait(ctx, cs.RoundStateEvent()); err != nil { + if err := cs.eventBus.PublishEventTimeoutWait(cs.RoundStateEvent()); err != nil { cs.logger.Error("failed publishing timeout wait", "err", err) } cs.enterPrecommit(ctx, ti.Height, ti.Round) case cstypes.RoundStepPrecommitWait: - if err := cs.eventBus.PublishEventTimeoutWait(ctx, cs.RoundStateEvent()); err != nil { + if err := cs.eventBus.PublishEventTimeoutWait(cs.RoundStateEvent()); err != nil { cs.logger.Error("failed publishing timeout wait", "err", err) } @@ -1200,7 +1198,7 @@ func (cs *State) enterNewRound(ctx context.Context, height int64, round int32) { cs.Votes.SetRound(r) // also track next round (round+1) to allow round-skipping cs.TriggeredTimeoutPrecommit = false - if err := cs.eventBus.PublishEventNewRound(ctx, cs.NewRoundEvent()); err != nil { + if err := cs.eventBus.PublishEventNewRound(cs.NewRoundEvent()); err != nil { cs.logger.Error("failed publishing new round", "err", err) } // Wait for txs to be available in the mempool @@ -1263,7 +1261,7 @@ func (cs *State) enterPropose(ctx context.Context, height int64, round int32) { defer func() { // Done enterPropose: cs.updateRoundStep(round, cstypes.RoundStepPropose) - cs.newStep(ctx) + cs.newStep() // If we have the whole proposal + POL, then goto Prevote now. // else, we'll enterPrevote when the rest of the proposal is received (in AddProposalBlockPart), @@ -1455,7 +1453,7 @@ func (cs *State) enterPrevote(ctx context.Context, height int64, round int32) { defer func() { // Done enterPrevote: cs.updateRoundStep(round, cstypes.RoundStepPrevote) - cs.newStep(ctx) + cs.newStep() }() logger.Debug("entering prevote step", "current", fmt.Sprintf("%v/%v/%v", cs.Height, cs.Round, cs.Step)) @@ -1606,7 +1604,7 @@ func (cs *State) defaultDoPrevote(ctx context.Context, height int64, round int32 } // Enter: any +2/3 prevotes at next round. -func (cs *State) enterPrevoteWait(ctx context.Context, height int64, round int32) { +func (cs *State) enterPrevoteWait(height int64, round int32) { logger := cs.logger.With("height", height, "round", round) if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrevoteWait <= cs.Step) { @@ -1629,7 +1627,7 @@ func (cs *State) enterPrevoteWait(ctx context.Context, height int64, round int32 defer func() { // Done enterPrevoteWait: cs.updateRoundStep(round, cstypes.RoundStepPrevoteWait) - cs.newStep(ctx) + cs.newStep() }() // Wait for some more prevotes; enterPrecommit @@ -1657,7 +1655,7 @@ func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32) defer func() { // Done enterPrecommit: cs.updateRoundStep(round, cstypes.RoundStepPrecommit) - cs.newStep(ctx) + cs.newStep() }() // check for a polka @@ -1676,7 +1674,7 @@ func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32) } // At this point +2/3 prevoted for a particular block or nil. - if err := cs.eventBus.PublishEventPolka(ctx, cs.RoundStateEvent()); err != nil { + if err := cs.eventBus.PublishEventPolka(cs.RoundStateEvent()); err != nil { logger.Error("failed publishing polka", "err", err) } @@ -1713,7 +1711,7 @@ func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32) logger.Debug("precommit step: +2/3 prevoted locked block; relocking") cs.LockedRound = round - if err := cs.eventBus.PublishEventRelock(ctx, cs.RoundStateEvent()); err != nil { + if err := cs.eventBus.PublishEventRelock(cs.RoundStateEvent()); err != nil { logger.Error("precommit step: failed publishing event relock", "err", err) } @@ -1736,7 +1734,7 @@ func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32) cs.LockedBlock = cs.ProposalBlock cs.LockedBlockParts = cs.ProposalBlockParts - if err := cs.eventBus.PublishEventLock(ctx, cs.RoundStateEvent()); err != nil { + if err := cs.eventBus.PublishEventLock(cs.RoundStateEvent()); err != nil { logger.Error("precommit step: failed publishing event lock", "err", err) } @@ -1758,7 +1756,7 @@ func (cs *State) enterPrecommit(ctx context.Context, height int64, round int32) } // Enter: any +2/3 precommits for next round. -func (cs *State) enterPrecommitWait(ctx context.Context, height int64, round int32) { +func (cs *State) enterPrecommitWait(height int64, round int32) { logger := cs.logger.With("height", height, "round", round) if cs.Height != height || round < cs.Round || (cs.Round == round && cs.TriggeredTimeoutPrecommit) { @@ -1782,7 +1780,7 @@ func (cs *State) enterPrecommitWait(ctx context.Context, height int64, round int defer func() { // Done enterPrecommitWait: cs.TriggeredTimeoutPrecommit = true - cs.newStep(ctx) + cs.newStep() }() // wait for some more precommits; enterNewRound @@ -1809,7 +1807,7 @@ func (cs *State) enterCommit(ctx context.Context, height int64, commitRound int3 cs.updateRoundStep(cs.Round, cstypes.RoundStepCommit) cs.CommitRound = commitRound cs.CommitTime = tmtime.Now() - cs.newStep(ctx) + cs.newStep() // Maybe finalize immediately. cs.tryFinalizeCommit(ctx, height) @@ -1844,11 +1842,11 @@ func (cs *State) enterCommit(ctx context.Context, height int64, commitRound int3 cs.metrics.MarkBlockGossipStarted() cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartSetHeader) - if err := cs.eventBus.PublishEventValidBlock(ctx, cs.RoundStateEvent()); err != nil { + if err := cs.eventBus.PublishEventValidBlock(cs.RoundStateEvent()); err != nil { logger.Error("failed publishing valid block", "err", err) } - cs.evsw.FireEvent(ctx, types.EventValidBlockValue, &cs.RoundState) + cs.evsw.FireEvent(types.EventValidBlockValue, &cs.RoundState) } } } @@ -1975,7 +1973,7 @@ func (cs *State) finalizeCommit(ctx context.Context, height int64) { cs.RecordMetrics(height, block) // NewHeightStep! - cs.updateToState(ctx, stateCopy) + cs.updateToState(stateCopy) // Private validator might have changed it's key pair => refetch pubkey. if err := cs.updatePrivValidatorPubKey(ctx); err != nil { @@ -2130,7 +2128,6 @@ func (cs *State) defaultSetProposal(proposal *types.Proposal, recvTime time.Time // Asynchronously triggers either enterPrevote (before we timeout of propose) or tryFinalizeCommit, // once we have the full block. func (cs *State) addProposalBlockPart( - ctx context.Context, msg *BlockPartMessage, peerID types.NodeID, ) (added bool, err error) { @@ -2196,7 +2193,7 @@ func (cs *State) addProposalBlockPart( // NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal cs.logger.Info("received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash()) - if err := cs.eventBus.PublishEventCompleteProposal(ctx, cs.CompleteProposalEvent()); err != nil { + if err := cs.eventBus.PublishEventCompleteProposal(cs.CompleteProposalEvent()); err != nil { cs.logger.Error("failed publishing event complete proposal", "err", err) } } @@ -2315,11 +2312,11 @@ func (cs *State) addVote( } cs.logger.Debug("added vote to last precommits", "last_commit", cs.LastCommit.StringShort()) - if err := cs.eventBus.PublishEventVote(ctx, types.EventDataVote{Vote: vote}); err != nil { + if err := cs.eventBus.PublishEventVote(types.EventDataVote{Vote: vote}); err != nil { return added, err } - cs.evsw.FireEvent(ctx, types.EventVoteValue, vote) + cs.evsw.FireEvent(types.EventVoteValue, vote) // if we can skip timeoutCommit and have all the votes now, if cs.bypassCommitTimeout() && cs.LastCommit.HasAll() { @@ -2352,10 +2349,10 @@ func (cs *State) addVote( return } - if err := cs.eventBus.PublishEventVote(ctx, types.EventDataVote{Vote: vote}); err != nil { + if err := cs.eventBus.PublishEventVote(types.EventDataVote{Vote: vote}); err != nil { return added, err } - cs.evsw.FireEvent(ctx, types.EventVoteValue, vote) + cs.evsw.FireEvent(types.EventVoteValue, vote) switch vote.Type { case tmproto.PrevoteType: @@ -2390,8 +2387,8 @@ func (cs *State) addVote( cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartSetHeader) } - cs.evsw.FireEvent(ctx, types.EventValidBlockValue, &cs.RoundState) - if err := cs.eventBus.PublishEventValidBlock(ctx, cs.RoundStateEvent()); err != nil { + cs.evsw.FireEvent(types.EventValidBlockValue, &cs.RoundState) + if err := cs.eventBus.PublishEventValidBlock(cs.RoundStateEvent()); err != nil { return added, err } } @@ -2408,7 +2405,7 @@ func (cs *State) addVote( if ok && (cs.isProposalComplete() || blockID.IsNil()) { cs.enterPrecommit(ctx, height, vote.Round) } else if prevotes.HasTwoThirdsAny() { - cs.enterPrevoteWait(ctx, height, vote.Round) + cs.enterPrevoteWait(height, vote.Round) } case cs.Proposal != nil && 0 <= cs.Proposal.POLRound && cs.Proposal.POLRound == vote.Round: @@ -2439,11 +2436,11 @@ func (cs *State) addVote( cs.enterNewRound(ctx, cs.Height, 0) } } else { - cs.enterPrecommitWait(ctx, height, vote.Round) + cs.enterPrecommitWait(height, vote.Round) } } else if cs.Round <= vote.Round && precommits.HasTwoThirdsAny() { cs.enterNewRound(ctx, height, vote.Round) - cs.enterPrecommitWait(ctx, height, vote.Round) + cs.enterPrecommitWait(height, vote.Round) } default: @@ -2494,7 +2491,7 @@ func (cs *State) signVote( if err != nil { return nil, err } - vote.VoteExtension = ext + vote.Extension = ext default: timeout = time.Second } @@ -2506,6 +2503,7 @@ func (cs *State) signVote( err := cs.privValidator.SignVote(ctxto, cs.state.ChainID, v) vote.Signature = v.Signature + vote.ExtensionSignature = v.ExtensionSignature vote.Timestamp = v.Timestamp return vote, err diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index 03bb85cf2..345b65f56 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -2015,6 +2015,235 @@ func TestFinalizeBlockCalled(t *testing.T) { } } +// TestExtendVoteCalled tests that the vote extension methods are called at the +// correct point in the consensus algorithm. +func TestExtendVoteCalled(t *testing.T) { + config := configSetup(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + m := abcimocks.NewBaseMock() + m.On("ProcessProposal", mock.Anything).Return(abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}) + m.On("ExtendVote", mock.Anything).Return(abci.ResponseExtendVote{ + VoteExtension: []byte("extension"), + }) + m.On("VerifyVoteExtension", mock.Anything).Return(abci.ResponseVerifyVoteExtension{ + Status: abci.ResponseVerifyVoteExtension_ACCEPT, + }) + m.On("FinalizeBlock", mock.Anything).Return(abci.ResponseFinalizeBlock{}).Maybe() + cs1, vss := makeState(ctx, t, makeStateArgs{config: config, application: m}) + height, round := cs1.Height, cs1.Round + + proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal) + newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound) + pv1, err := cs1.privValidator.GetPubKey(ctx) + require.NoError(t, err) + addr := pv1.Address() + voteCh := subscribeToVoter(ctx, t, cs1, addr) + + startTestRound(ctx, cs1, cs1.Height, round) + ensureNewRound(t, newRoundCh, height, round) + ensureNewProposal(t, proposalCh, height, round) + + m.AssertNotCalled(t, "ExtendVote", mock.Anything) + + rs := cs1.GetRoundState() + + blockID := types.BlockID{ + Hash: rs.ProposalBlock.Hash(), + PartSetHeader: rs.ProposalBlockParts.Header(), + } + signAddVotes(ctx, t, cs1, tmproto.PrevoteType, config.ChainID(), blockID, vss[1:]...) + ensurePrevoteMatch(t, voteCh, height, round, blockID.Hash) + + ensurePrecommit(t, voteCh, height, round) + + m.AssertCalled(t, "ExtendVote", abci.RequestExtendVote{ + Height: height, + Hash: blockID.Hash, + }) + + m.AssertCalled(t, "VerifyVoteExtension", abci.RequestVerifyVoteExtension{ + Hash: blockID.Hash, + ValidatorAddress: addr, + Height: height, + VoteExtension: []byte("extension"), + }) + + signAddVotes(ctx, t, cs1, tmproto.PrecommitType, config.ChainID(), blockID, vss[1:]...) + ensureNewRound(t, newRoundCh, height+1, 0) + m.AssertExpectations(t) + + // Only 3 of the vote extensions are seen, as consensus proceeds as soon as the +2/3 threshold + // is observed by the consensus engine. + for _, pv := range vss[:3] { + pv, err := pv.GetPubKey(ctx) + require.NoError(t, err) + addr := pv.Address() + m.AssertCalled(t, "VerifyVoteExtension", abci.RequestVerifyVoteExtension{ + Hash: blockID.Hash, + ValidatorAddress: addr, + Height: height, + VoteExtension: []byte("extension"), + }) + } + +} + +// TestVerifyVoteExtensionNotCalledOnAbsentPrecommit tests that the VerifyVoteExtension +// method is not called for a validator's vote that is never delivered. +func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { + config := configSetup(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + m := abcimocks.NewBaseMock() + m.On("ProcessProposal", mock.Anything).Return(abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}) + m.On("ExtendVote", mock.Anything).Return(abci.ResponseExtendVote{ + VoteExtension: []byte("extension"), + }) + m.On("VerifyVoteExtension", mock.Anything).Return(abci.ResponseVerifyVoteExtension{ + Status: abci.ResponseVerifyVoteExtension_ACCEPT, + }) + m.On("FinalizeBlock", mock.Anything).Return(abci.ResponseFinalizeBlock{}).Maybe() + cs1, vss := makeState(ctx, t, makeStateArgs{config: config, application: m}) + height, round := cs1.Height, cs1.Round + + proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal) + newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound) + pv1, err := cs1.privValidator.GetPubKey(ctx) + require.NoError(t, err) + addr := pv1.Address() + voteCh := subscribeToVoter(ctx, t, cs1, addr) + + startTestRound(ctx, cs1, cs1.Height, round) + ensureNewRound(t, newRoundCh, height, round) + ensureNewProposal(t, proposalCh, height, round) + rs := cs1.GetRoundState() + + blockID := types.BlockID{ + Hash: rs.ProposalBlock.Hash(), + PartSetHeader: rs.ProposalBlockParts.Header(), + } + signAddVotes(ctx, t, cs1, tmproto.PrevoteType, config.ChainID(), blockID, vss[2:]...) + ensurePrevoteMatch(t, voteCh, height, round, blockID.Hash) + + ensurePrecommit(t, voteCh, height, round) + + m.AssertCalled(t, "ExtendVote", abci.RequestExtendVote{ + Height: height, + Hash: blockID.Hash, + }) + + m.AssertCalled(t, "VerifyVoteExtension", abci.RequestVerifyVoteExtension{ + Hash: blockID.Hash, + ValidatorAddress: addr, + Height: height, + VoteExtension: []byte("extension"), + }) + + signAddVotes(ctx, t, cs1, tmproto.PrecommitType, config.ChainID(), blockID, vss[2:]...) + ensureNewRound(t, newRoundCh, height+1, 0) + m.AssertExpectations(t) + + // vss[1] did not issue a precommit for the block, ensure that a vote extension + // for its address was not sent to the application. + pv, err := vss[1].GetPubKey(ctx) + require.NoError(t, err) + addr = pv.Address() + + m.AssertNotCalled(t, "VerifyVoteExtension", abci.RequestVerifyVoteExtension{ + Hash: blockID.Hash, + ValidatorAddress: addr, + Height: height, + VoteExtension: []byte("extension"), + }) + +} + +// TestPrepareProposalReceivesVoteExtensions tests that the PrepareProposal method +// is called with the vote extensions from the previous height. The test functions +// be completing a consensus height with a mock application as the proposer. The +// test then proceeds to fail sever rounds of consensus until the mock application +// is the proposer again and ensures that the mock application receives the set of +// vote extensions from the previous consensus instance. +func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { + config := configSetup(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // create a list of vote extensions, one for each validator. + voteExtensions := [][]byte{ + []byte("extension 0"), + []byte("extension 1"), + []byte("extension 2"), + []byte("extension 3"), + } + + m := abcimocks.NewBaseMock() + m.On("ExtendVote", mock.Anything).Return(abci.ResponseExtendVote{ + VoteExtension: voteExtensions[0], + }) + m.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{}).Once() + + cs1, vss := makeState(ctx, t, makeStateArgs{config: config, application: m}) + height, round := cs1.Height, cs1.Round + + newRoundCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryNewRound) + proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal) + pv1, err := cs1.privValidator.GetPubKey(ctx) + require.NoError(t, err) + addr := pv1.Address() + voteCh := subscribeToVoter(ctx, t, cs1, addr) + + startTestRound(ctx, cs1, height, round) + ensureNewRound(t, newRoundCh, height, round) + ensureNewProposal(t, proposalCh, height, round) + + rs := cs1.GetRoundState() + blockID := types.BlockID{ + Hash: rs.ProposalBlock.Hash(), + PartSetHeader: rs.ProposalBlockParts.Header(), + } + signAddVotes(ctx, t, cs1, tmproto.PrevoteType, config.ChainID(), blockID, vss[1:]...) + + // create a precommit for each validator with the associated vote extension. + for i, vs := range vss[1:] { + signAddPrecommitWithExtension(ctx, t, cs1, config.ChainID(), blockID, voteExtensions[i+1], vs) + } + + ensurePrevote(t, voteCh, height, round) + + // ensure that the height is committed. + ensurePrecommitMatch(t, voteCh, height, round, blockID.Hash) + incrementHeight(vss[1:]...) + + height++ + round = 0 + ensureNewRound(t, newRoundCh, height, round) + incrementRound(vss[1:]...) + incrementRound(vss[1:]...) + incrementRound(vss[1:]...) + round = 3 + + // capture the prepare proposal request. + rpp := abci.RequestPrepareProposal{} + m.On("PrepareProposal", mock.MatchedBy(func(r abci.RequestPrepareProposal) bool { + rpp = r + return true + })).Return(abci.ResponsePrepareProposal{}) + + signAddVotes(ctx, t, cs1, tmproto.PrecommitType, config.ChainID(), types.BlockID{}, vss[1:]...) + ensureNewRound(t, newRoundCh, height, round) + ensureNewProposal(t, proposalCh, height, round) + + // ensure that the proposer received the list of vote extensions from the + // previous height. + for i := range vss { + require.Equal(t, rpp.LocalLastCommit.Votes[i].VoteExtension, voteExtensions[i]) + } +} + // 4 vals, 3 Nil Precommits at P0 // What we want: // P0 waits for timeoutPrecommit before starting next round @@ -2719,3 +2948,15 @@ func subscribe( }() return ch } + +func signAddPrecommitWithExtension(ctx context.Context, + t *testing.T, + cs *State, + chainID string, + blockID types.BlockID, + extension []byte, + stub *validatorStub) { + v, err := stub.signVote(ctx, tmproto.PrecommitType, chainID, blockID, extension) + require.NoError(t, err, "failed to sign vote") + addVotes(cs, v) +} diff --git a/internal/consensus/types/height_vote_set_test.go b/internal/consensus/types/height_vote_set_test.go index 671c5f214..8bafc7a90 100644 --- a/internal/consensus/types/height_vote_set_test.go +++ b/internal/consensus/types/height_vote_set_test.go @@ -88,6 +88,7 @@ func makeVoteHR( require.NoError(t, err, "Error signing vote") vote.Signature = v.Signature + vote.ExtensionSignature = v.ExtensionSignature return vote } diff --git a/internal/consensus/wal_generator.go b/internal/consensus/wal_generator.go index 8c61c1203..0e678db3a 100644 --- a/internal/consensus/wal_generator.go +++ b/internal/consensus/wal_generator.go @@ -81,7 +81,7 @@ func WALGenerateNBlocks(ctx context.Context, t *testing.T, logger log.Logger, wr mempool := emptyMempool{} evpool := sm.EmptyEvidencePool{} blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyApp, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) - consensusState, err := NewState(ctx, logger, cfg.Consensus, stateStore, blockExec, blockStore, mempool, evpool, eventBus) + consensusState, err := NewState(logger, cfg.Consensus, stateStore, blockExec, blockStore, mempool, evpool, eventBus) if err != nil { t.Fatal(err) } diff --git a/internal/eventbus/event_bus.go b/internal/eventbus/event_bus.go index 5a64c5f1c..c01c37de7 100644 --- a/internal/eventbus/event_bus.go +++ b/internal/eventbus/event_bus.go @@ -66,7 +66,7 @@ func (b *EventBus) Observe(ctx context.Context, observe func(tmpubsub.Message) e return b.pubsub.Observe(ctx, observe, queries...) } -func (b *EventBus) Publish(ctx context.Context, eventValue string, eventData types.EventData) error { +func (b *EventBus) Publish(eventValue string, eventData types.EventData) error { tokens := strings.Split(types.EventTypeKey, ".") event := abci.Event{ Type: tokens[0], @@ -78,19 +78,19 @@ func (b *EventBus) Publish(ctx context.Context, eventValue string, eventData typ }, } - return b.pubsub.PublishWithEvents(ctx, eventData, []abci.Event{event}) + return b.pubsub.PublishWithEvents(eventData, []abci.Event{event}) } -func (b *EventBus) PublishEventNewBlock(ctx context.Context, data types.EventDataNewBlock) error { +func (b *EventBus) PublishEventNewBlock(data types.EventDataNewBlock) error { events := data.ResultFinalizeBlock.Events // add Tendermint-reserved new block event events = append(events, types.EventNewBlock) - return b.pubsub.PublishWithEvents(ctx, data, events) + return b.pubsub.PublishWithEvents(data, events) } -func (b *EventBus) PublishEventNewBlockHeader(ctx context.Context, data types.EventDataNewBlockHeader) error { +func (b *EventBus) PublishEventNewBlockHeader(data types.EventDataNewBlockHeader) error { // no explicit deadline for publishing events events := data.ResultFinalizeBlock.Events @@ -98,33 +98,33 @@ func (b *EventBus) PublishEventNewBlockHeader(ctx context.Context, data types.Ev // add Tendermint-reserved new block header event events = append(events, types.EventNewBlockHeader) - return b.pubsub.PublishWithEvents(ctx, data, events) + return b.pubsub.PublishWithEvents(data, events) } -func (b *EventBus) PublishEventNewEvidence(ctx context.Context, evidence types.EventDataNewEvidence) error { - return b.Publish(ctx, types.EventNewEvidenceValue, evidence) +func (b *EventBus) PublishEventNewEvidence(evidence types.EventDataNewEvidence) error { + return b.Publish(types.EventNewEvidenceValue, evidence) } -func (b *EventBus) PublishEventVote(ctx context.Context, data types.EventDataVote) error { - return b.Publish(ctx, types.EventVoteValue, data) +func (b *EventBus) PublishEventVote(data types.EventDataVote) error { + return b.Publish(types.EventVoteValue, data) } -func (b *EventBus) PublishEventValidBlock(ctx context.Context, data types.EventDataRoundState) error { - return b.Publish(ctx, types.EventValidBlockValue, data) +func (b *EventBus) PublishEventValidBlock(data types.EventDataRoundState) error { + return b.Publish(types.EventValidBlockValue, data) } -func (b *EventBus) PublishEventBlockSyncStatus(ctx context.Context, data types.EventDataBlockSyncStatus) error { - return b.Publish(ctx, types.EventBlockSyncStatusValue, data) +func (b *EventBus) PublishEventBlockSyncStatus(data types.EventDataBlockSyncStatus) error { + return b.Publish(types.EventBlockSyncStatusValue, data) } -func (b *EventBus) PublishEventStateSyncStatus(ctx context.Context, data types.EventDataStateSyncStatus) error { - return b.Publish(ctx, types.EventStateSyncStatusValue, data) +func (b *EventBus) PublishEventStateSyncStatus(data types.EventDataStateSyncStatus) error { + return b.Publish(types.EventStateSyncStatusValue, data) } // PublishEventTx publishes tx event with events from Result. Note it will add // predefined keys (EventTypeKey, TxHashKey). Existing events with the same keys // will be overwritten. -func (b *EventBus) PublishEventTx(ctx context.Context, data types.EventDataTx) error { +func (b *EventBus) PublishEventTx(data types.EventDataTx) error { events := data.Result.Events // add Tendermint-reserved events @@ -152,45 +152,45 @@ func (b *EventBus) PublishEventTx(ctx context.Context, data types.EventDataTx) e }, }) - return b.pubsub.PublishWithEvents(ctx, data, events) + return b.pubsub.PublishWithEvents(data, events) } -func (b *EventBus) PublishEventNewRoundStep(ctx context.Context, data types.EventDataRoundState) error { - return b.Publish(ctx, types.EventNewRoundStepValue, data) +func (b *EventBus) PublishEventNewRoundStep(data types.EventDataRoundState) error { + return b.Publish(types.EventNewRoundStepValue, data) } -func (b *EventBus) PublishEventTimeoutPropose(ctx context.Context, data types.EventDataRoundState) error { - return b.Publish(ctx, types.EventTimeoutProposeValue, data) +func (b *EventBus) PublishEventTimeoutPropose(data types.EventDataRoundState) error { + return b.Publish(types.EventTimeoutProposeValue, data) } -func (b *EventBus) PublishEventTimeoutWait(ctx context.Context, data types.EventDataRoundState) error { - return b.Publish(ctx, types.EventTimeoutWaitValue, data) +func (b *EventBus) PublishEventTimeoutWait(data types.EventDataRoundState) error { + return b.Publish(types.EventTimeoutWaitValue, data) } -func (b *EventBus) PublishEventNewRound(ctx context.Context, data types.EventDataNewRound) error { - return b.Publish(ctx, types.EventNewRoundValue, data) +func (b *EventBus) PublishEventNewRound(data types.EventDataNewRound) error { + return b.Publish(types.EventNewRoundValue, data) } -func (b *EventBus) PublishEventCompleteProposal(ctx context.Context, data types.EventDataCompleteProposal) error { - return b.Publish(ctx, types.EventCompleteProposalValue, data) +func (b *EventBus) PublishEventCompleteProposal(data types.EventDataCompleteProposal) error { + return b.Publish(types.EventCompleteProposalValue, data) } -func (b *EventBus) PublishEventPolka(ctx context.Context, data types.EventDataRoundState) error { - return b.Publish(ctx, types.EventPolkaValue, data) +func (b *EventBus) PublishEventPolka(data types.EventDataRoundState) error { + return b.Publish(types.EventPolkaValue, data) } -func (b *EventBus) PublishEventRelock(ctx context.Context, data types.EventDataRoundState) error { - return b.Publish(ctx, types.EventRelockValue, data) +func (b *EventBus) PublishEventRelock(data types.EventDataRoundState) error { + return b.Publish(types.EventRelockValue, data) } -func (b *EventBus) PublishEventLock(ctx context.Context, data types.EventDataRoundState) error { - return b.Publish(ctx, types.EventLockValue, data) +func (b *EventBus) PublishEventLock(data types.EventDataRoundState) error { + return b.Publish(types.EventLockValue, data) } -func (b *EventBus) PublishEventValidatorSetUpdates(ctx context.Context, data types.EventDataValidatorSetUpdates) error { - return b.Publish(ctx, types.EventValidatorSetUpdatesValue, data) +func (b *EventBus) PublishEventValidatorSetUpdates(data types.EventDataValidatorSetUpdates) error { + return b.Publish(types.EventValidatorSetUpdatesValue, data) } -func (b *EventBus) PublishEventEvidenceValidated(ctx context.Context, evidence types.EventDataEvidenceValidated) error { - return b.Publish(ctx, types.EventEvidenceValidatedValue, evidence) +func (b *EventBus) PublishEventEvidenceValidated(evidence types.EventDataEvidenceValidated) error { + return b.Publish(types.EventEvidenceValidatedValue, evidence) } diff --git a/internal/eventbus/event_bus_test.go b/internal/eventbus/event_bus_test.go index 1bfea02e1..6fd8a2d72 100644 --- a/internal/eventbus/event_bus_test.go +++ b/internal/eventbus/event_bus_test.go @@ -55,7 +55,7 @@ func TestEventBusPublishEventTx(t *testing.T) { assert.Equal(t, result, edt.Result) }() - err = eventBus.PublishEventTx(ctx, types.EventDataTx{ + err = eventBus.PublishEventTx(types.EventDataTx{ TxResult: abci.TxResult{ Height: 1, Index: 0, @@ -112,7 +112,7 @@ func TestEventBusPublishEventNewBlock(t *testing.T) { assert.Equal(t, resultFinalizeBlock, edt.ResultFinalizeBlock) }() - err = eventBus.PublishEventNewBlock(ctx, types.EventDataNewBlock{ + err = eventBus.PublishEventNewBlock(types.EventDataNewBlock{ Block: block, BlockID: blockID, ResultFinalizeBlock: resultFinalizeBlock, @@ -223,7 +223,7 @@ func TestEventBusPublishEventTxDuplicateKeys(t *testing.T) { } }() - assert.NoError(t, eventBus.PublishEventTx(ctx, types.EventDataTx{ + assert.NoError(t, eventBus.PublishEventTx(types.EventDataTx{ TxResult: abci.TxResult{ Height: 1, Index: 0, @@ -280,7 +280,7 @@ func TestEventBusPublishEventNewBlockHeader(t *testing.T) { assert.Equal(t, resultFinalizeBlock, edt.ResultFinalizeBlock) }() - err = eventBus.PublishEventNewBlockHeader(ctx, types.EventDataNewBlockHeader{ + err = eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{ Header: block.Header, ResultFinalizeBlock: resultFinalizeBlock, }) @@ -322,7 +322,7 @@ func TestEventBusPublishEventEvidenceValidated(t *testing.T) { assert.Equal(t, int64(1), edt.Height) }() - err = eventBus.PublishEventEvidenceValidated(ctx, types.EventDataEvidenceValidated{ + err = eventBus.PublishEventEvidenceValidated(types.EventDataEvidenceValidated{ Evidence: ev, Height: int64(1), }) @@ -364,7 +364,7 @@ func TestEventBusPublishEventNewEvidence(t *testing.T) { assert.Equal(t, int64(4), edt.Height) }() - err = eventBus.PublishEventNewEvidence(ctx, types.EventDataNewEvidence{ + err = eventBus.PublishEventNewEvidence(types.EventDataNewEvidence{ Evidence: ev, Height: 4, }) @@ -408,22 +408,22 @@ func TestEventBusPublish(t *testing.T) { } }() - require.NoError(t, eventBus.Publish(ctx, types.EventNewBlockHeaderValue, + require.NoError(t, eventBus.Publish(types.EventNewBlockHeaderValue, types.EventDataNewBlockHeader{})) - require.NoError(t, eventBus.PublishEventNewBlock(ctx, types.EventDataNewBlock{})) - require.NoError(t, eventBus.PublishEventNewBlockHeader(ctx, types.EventDataNewBlockHeader{})) - require.NoError(t, eventBus.PublishEventVote(ctx, types.EventDataVote{})) - require.NoError(t, eventBus.PublishEventNewRoundStep(ctx, types.EventDataRoundState{})) - require.NoError(t, eventBus.PublishEventTimeoutPropose(ctx, types.EventDataRoundState{})) - require.NoError(t, eventBus.PublishEventTimeoutWait(ctx, types.EventDataRoundState{})) - require.NoError(t, eventBus.PublishEventNewRound(ctx, types.EventDataNewRound{})) - require.NoError(t, eventBus.PublishEventCompleteProposal(ctx, types.EventDataCompleteProposal{})) - require.NoError(t, eventBus.PublishEventPolka(ctx, types.EventDataRoundState{})) - require.NoError(t, eventBus.PublishEventRelock(ctx, types.EventDataRoundState{})) - require.NoError(t, eventBus.PublishEventLock(ctx, types.EventDataRoundState{})) - require.NoError(t, eventBus.PublishEventValidatorSetUpdates(ctx, types.EventDataValidatorSetUpdates{})) - require.NoError(t, eventBus.PublishEventBlockSyncStatus(ctx, types.EventDataBlockSyncStatus{})) - require.NoError(t, eventBus.PublishEventStateSyncStatus(ctx, types.EventDataStateSyncStatus{})) + require.NoError(t, eventBus.PublishEventNewBlock(types.EventDataNewBlock{})) + require.NoError(t, eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{})) + require.NoError(t, eventBus.PublishEventVote(types.EventDataVote{})) + require.NoError(t, eventBus.PublishEventNewRoundStep(types.EventDataRoundState{})) + require.NoError(t, eventBus.PublishEventTimeoutPropose(types.EventDataRoundState{})) + require.NoError(t, eventBus.PublishEventTimeoutWait(types.EventDataRoundState{})) + require.NoError(t, eventBus.PublishEventNewRound(types.EventDataNewRound{})) + require.NoError(t, eventBus.PublishEventCompleteProposal(types.EventDataCompleteProposal{})) + require.NoError(t, eventBus.PublishEventPolka(types.EventDataRoundState{})) + require.NoError(t, eventBus.PublishEventRelock(types.EventDataRoundState{})) + require.NoError(t, eventBus.PublishEventLock(types.EventDataRoundState{})) + require.NoError(t, eventBus.PublishEventValidatorSetUpdates(types.EventDataValidatorSetUpdates{})) + require.NoError(t, eventBus.PublishEventBlockSyncStatus(types.EventDataBlockSyncStatus{})) + require.NoError(t, eventBus.PublishEventStateSyncStatus(types.EventDataStateSyncStatus{})) require.GreaterOrEqual(t, <-count, numEventsExpected) } @@ -505,7 +505,7 @@ func benchmarkEventBus(numClients int, randQueries bool, randEvents bool, b *tes eventValue = randEventValue() } - err := eventBus.Publish(ctx, eventValue, types.EventDataString("Gamora")) + err := eventBus.Publish(eventValue, types.EventDataString("Gamora")) if err != nil { b.Error(err) } diff --git a/internal/evidence/pool.go b/internal/evidence/pool.go index d2d998c91..132c61f23 100644 --- a/internal/evidence/pool.go +++ b/internal/evidence/pool.go @@ -338,7 +338,7 @@ func (evpool *Pool) addPendingEvidence(ctx context.Context, ev types.Evidence) e return nil } - return evpool.eventBus.PublishEventEvidenceValidated(ctx, types.EventDataEvidenceValidated{ + return evpool.eventBus.PublishEventEvidenceValidated(types.EventDataEvidenceValidated{ Evidence: ev, Height: ev.Height(), }) diff --git a/internal/evidence/reactor_test.go b/internal/evidence/reactor_test.go index 2fdfa8c60..5575d7f97 100644 --- a/internal/evidence/reactor_test.go +++ b/internal/evidence/reactor_test.go @@ -46,7 +46,7 @@ type reactorTestSuite struct { numStateStores int } -func setup(ctx context.Context, t *testing.T, stateStores []sm.Store, chBuf uint) *reactorTestSuite { +func setup(ctx context.Context, t *testing.T, stateStores []sm.Store) *reactorTestSuite { t.Helper() pID := make([]byte, 16) @@ -245,7 +245,7 @@ func TestReactorMultiDisconnect(t *testing.T) { stateDB1 := initializeValidatorState(ctx, t, val, height) stateDB2 := initializeValidatorState(ctx, t, val, height) - rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}, 20) + rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}) primary := rts.nodes[0] secondary := rts.nodes[1] @@ -290,7 +290,7 @@ func TestReactorBroadcastEvidence(t *testing.T) { stateDBs[i] = initializeValidatorState(ctx, t, val, height) } - rts := setup(ctx, t, stateDBs, 0) + rts := setup(ctx, t, stateDBs) rts.start(ctx, t) @@ -348,7 +348,7 @@ func TestReactorBroadcastEvidence_Lagging(t *testing.T) { stateDB1 := initializeValidatorState(ctx, t, val, height1) stateDB2 := initializeValidatorState(ctx, t, val, height2) - rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}, 100) + rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}) rts.start(ctx, t) primary := rts.nodes[0] @@ -382,7 +382,7 @@ func TestReactorBroadcastEvidence_Pending(t *testing.T) { stateDB1 := initializeValidatorState(ctx, t, val, height) stateDB2 := initializeValidatorState(ctx, t, val, height) - rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}, 100) + rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}) primary := rts.nodes[0] secondary := rts.nodes[1] @@ -423,7 +423,7 @@ func TestReactorBroadcastEvidence_Committed(t *testing.T) { stateDB1 := initializeValidatorState(ctx, t, val, height) stateDB2 := initializeValidatorState(ctx, t, val, height) - rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}, 0) + rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}) primary := rts.nodes[0] secondary := rts.nodes[1] @@ -482,7 +482,7 @@ func TestReactorBroadcastEvidence_FullyConnected(t *testing.T) { stateDBs[i] = initializeValidatorState(ctx, t, val, height) } - rts := setup(ctx, t, stateDBs, 0) + rts := setup(ctx, t, stateDBs) rts.start(ctx, t) evList := createEvidenceList(ctx, t, rts.pools[rts.network.RandomNode().NodeID], val, numEvidence) diff --git a/internal/mempool/mempool_bench_test.go b/internal/mempool/mempool_bench_test.go index cc3ff7368..14fb22197 100644 --- a/internal/mempool/mempool_bench_test.go +++ b/internal/mempool/mempool_bench_test.go @@ -25,7 +25,7 @@ func BenchmarkTxMempool_CheckTx(b *testing.B) { // setup the cache and the mempool number for hitting GetEvictableTxs during the // benchmark. 5000 is the current default mempool size in the TM config. - txmp := setup(ctx, b, client, 10000) + txmp := setup(b, client, 10000) txmp.config.Size = 5000 rng := rand.New(rand.NewSource(time.Now().UnixNano())) diff --git a/internal/mempool/mempool_test.go b/internal/mempool/mempool_test.go index 0dd6ee00c..a20e793c3 100644 --- a/internal/mempool/mempool_test.go +++ b/internal/mempool/mempool_test.go @@ -72,7 +72,7 @@ func (app *application) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { } } -func setup(ctx context.Context, t testing.TB, app abciclient.Client, cacheSize int, options ...TxMempoolOption) *TxMempool { +func setup(t testing.TB, app abciclient.Client, cacheSize int, options ...TxMempoolOption) *TxMempool { t.Helper() logger := log.NewNopLogger() @@ -131,7 +131,7 @@ func TestTxMempool_TxsAvailable(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 0) + txmp := setup(t, client, 0) txmp.EnableTxsAvailable() ensureNoTxFire := func() { @@ -194,7 +194,7 @@ func TestTxMempool_Size(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 0) + txmp := setup(t, client, 0) txs := checkTxs(ctx, t, txmp, 100, 0) require.Equal(t, len(txs), txmp.Size()) require.Equal(t, int64(5690), txmp.SizeBytes()) @@ -227,7 +227,7 @@ func TestTxMempool_Flush(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 0) + txmp := setup(t, client, 0) txs := checkTxs(ctx, t, txmp, 100, 0) require.Equal(t, len(txs), txmp.Size()) require.Equal(t, int64(5690), txmp.SizeBytes()) @@ -261,7 +261,7 @@ func TestTxMempool_ReapMaxBytesMaxGas(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 0) + txmp := setup(t, client, 0) tTxs := checkTxs(ctx, t, txmp, 100, 0) // all txs request 1 gas unit require.Equal(t, len(tTxs), txmp.Size()) require.Equal(t, int64(5690), txmp.SizeBytes()) @@ -320,7 +320,7 @@ func TestTxMempool_ReapMaxTxs(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 0) + txmp := setup(t, client, 0) tTxs := checkTxs(ctx, t, txmp, 100, 0) require.Equal(t, len(tTxs), txmp.Size()) require.Equal(t, int64(5690), txmp.SizeBytes()) @@ -377,7 +377,7 @@ func TestTxMempool_CheckTxExceedsMaxSize(t *testing.T) { t.Fatal(err) } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 0) + txmp := setup(t, client, 0) rng := rand.New(rand.NewSource(time.Now().UnixNano())) tx := make([]byte, txmp.config.MaxTxBytes+1) @@ -403,7 +403,7 @@ func TestTxMempool_CheckTxSamePeer(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 100) + txmp := setup(t, client, 100) peerID := uint16(1) rng := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -427,7 +427,7 @@ func TestTxMempool_CheckTxSameSender(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 100) + txmp := setup(t, client, 100) peerID := uint16(1) rng := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -458,7 +458,7 @@ func TestTxMempool_ConcurrentTxs(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 100) + txmp := setup(t, client, 100) rng := rand.New(rand.NewSource(time.Now().UnixNano())) checkTxDone := make(chan struct{}) @@ -531,7 +531,7 @@ func TestTxMempool_ExpiredTxs_NumBlocks(t *testing.T) { } t.Cleanup(client.Wait) - txmp := setup(ctx, t, client, 500) + txmp := setup(t, client, 500) txmp.height = 100 txmp.config.TTLNumBlocks = 10 @@ -612,7 +612,7 @@ func TestTxMempool_CheckTxPostCheckError(t *testing.T) { postCheckFn := func(_ types.Tx, _ *abci.ResponseCheckTx) error { return testCase.err } - txmp := setup(ctx, t, client, 0, WithPostCheck(postCheckFn)) + txmp := setup(t, client, 0, WithPostCheck(postCheckFn)) rng := rand.New(rand.NewSource(time.Now().UnixNano())) tx := make([]byte, txmp.config.MaxTxBytes-1) _, err := rng.Read(tx) diff --git a/internal/mempool/reactor_test.go b/internal/mempool/reactor_test.go index 82a97aeec..8ceae2013 100644 --- a/internal/mempool/reactor_test.go +++ b/internal/mempool/reactor_test.go @@ -68,7 +68,7 @@ func setupReactors(ctx context.Context, t *testing.T, logger log.Logger, numNode require.NoError(t, client.Start(ctx)) t.Cleanup(client.Wait) - mempool := setup(ctx, t, client, 0) + mempool := setup(t, client, 0) rts.mempools[nodeID] = mempool rts.peerChans[nodeID] = make(chan p2p.PeerUpdate, chBuf) diff --git a/internal/p2p/conn/secret_connection_test.go b/internal/p2p/conn/secret_connection_test.go index 6752d9d21..2e37f8388 100644 --- a/internal/p2p/conn/secret_connection_test.go +++ b/internal/p2p/conn/secret_connection_test.go @@ -228,7 +228,7 @@ func TestDeriveSecretsAndChallengeGolden(t *testing.T) { goldenFilepath := filepath.Join("testdata", t.Name()+".golden") if *update { t.Logf("Updating golden test vector file %s", goldenFilepath) - data := createGoldenTestVectors(t) + data := createGoldenTestVectors() require.NoError(t, os.WriteFile(goldenFilepath, []byte(data), 0644)) } f, err := os.Open(goldenFilepath) @@ -306,7 +306,7 @@ func readLots(t *testing.T, wg *sync.WaitGroup, conn io.Reader, n int) { // Creates the data for a test vector file. // The file format is: // Hex(diffie_hellman_secret), loc_is_least, Hex(recvSecret), Hex(sendSecret), Hex(challenge) -func createGoldenTestVectors(t *testing.T) string { +func createGoldenTestVectors() string { data := "" for i := 0; i < 32; i++ { randSecretVector := tmrand.Bytes(32) diff --git a/internal/p2p/conn_tracker.go b/internal/p2p/conn_tracker.go index 09673c093..54f9c8980 100644 --- a/internal/p2p/conn_tracker.go +++ b/internal/p2p/conn_tracker.go @@ -26,6 +26,7 @@ func newConnTracker(max uint, window time.Duration) connectionTracker { cache: make(map[string]uint), lastConnect: make(map[string]time.Time), max: max, + window: window, } } @@ -43,7 +44,7 @@ func (rat *connTrackerImpl) AddConn(addr net.IP) error { if num := rat.cache[address]; num >= rat.max { return fmt.Errorf("%q has %d connections [max=%d]", address, num, rat.max) } else if num == 0 { - // if there is already at least connection, check to + // if there is already at least one connection, check to // see if it was established before within the window, // and error if so. if last := rat.lastConnect[address]; time.Since(last) < rat.window { diff --git a/internal/p2p/conn_tracker_test.go b/internal/p2p/conn_tracker_test.go index 66656e114..daa3351f2 100644 --- a/internal/p2p/conn_tracker_test.go +++ b/internal/p2p/conn_tracker_test.go @@ -70,4 +70,15 @@ func TestConnTracker(t *testing.T) { } require.Equal(t, 10, ct.Len()) }) + t.Run("Window", func(t *testing.T) { + const window = 100 * time.Millisecond + ct := newConnTracker(10, window) + ip := randLocalIPv4() + require.NoError(t, ct.AddConn(ip)) + ct.RemoveConn(ip) + require.Error(t, ct.AddConn(ip)) + time.Sleep(window) + require.NoError(t, ct.AddConn(ip)) + }) + } diff --git a/internal/p2p/pex/reactor_test.go b/internal/p2p/pex/reactor_test.go index 325ea72ab..f2132fbba 100644 --- a/internal/p2p/pex/reactor_test.go +++ b/internal/p2p/pex/reactor_test.go @@ -151,14 +151,14 @@ func TestReactorErrorsOnReceivingTooManyPeers(t *testing.T) { defer cancel() r := setupSingle(ctx, t) - peer := p2p.NodeAddress{Protocol: p2p.MemoryProtocol, NodeID: randomNodeID(t)} + peer := p2p.NodeAddress{Protocol: p2p.MemoryProtocol, NodeID: randomNodeID()} added, err := r.manager.Add(peer) require.NoError(t, err) require.True(t, added) addresses := make([]p2pproto.PexAddress, 101) for i := 0; i < len(addresses); i++ { - nodeAddress := p2p.NodeAddress{Protocol: p2p.MemoryProtocol, NodeID: randomNodeID(t)} + nodeAddress := p2p.NodeAddress{Protocol: p2p.MemoryProtocol, NodeID: randomNodeID()} addresses[i] = p2pproto.PexAddress{ URL: nodeAddress.String(), } @@ -730,6 +730,6 @@ func newNodeID(t *testing.T, id string) types.NodeID { return nodeID } -func randomNodeID(t *testing.T) types.NodeID { +func randomNodeID() types.NodeID { return types.NodeIDFromPubKey(ed25519.GenPrivKey().PubKey()) } diff --git a/internal/pubsub/example_test.go b/internal/pubsub/example_test.go index 22e735d6a..c4b5dc5c9 100644 --- a/internal/pubsub/example_test.go +++ b/internal/pubsub/example_test.go @@ -29,6 +29,6 @@ func TestExample(t *testing.T) { Attributes: []abci.EventAttribute{{Key: "name", Value: "John"}}, }, } - require.NoError(t, s.PublishWithEvents(ctx, pubstring("Tombstone"), events)) + require.NoError(t, s.PublishWithEvents(pubstring("Tombstone"), events)) sub.mustReceive(ctx, pubstring("Tombstone")) } diff --git a/internal/pubsub/pubsub.go b/internal/pubsub/pubsub.go index 3e887226b..c0ad4ae3c 100644 --- a/internal/pubsub/pubsub.go +++ b/internal/pubsub/pubsub.go @@ -287,16 +287,16 @@ func (s *Server) NumClientSubscriptions(clientID string) int { } // Publish publishes the given message. An error will be returned to the caller -// if the context is canceled. -func (s *Server) Publish(ctx context.Context, msg types.EventData) error { - return s.publish(ctx, msg, []abci.Event{}) +// if the pubsub server has shut down. +func (s *Server) Publish(msg types.EventData) error { + return s.publish(msg, []abci.Event{}) } // PublishWithEvents publishes the given message with the set of events. The set // is matched with clients queries. If there is a match, the message is sent to // the client. -func (s *Server) PublishWithEvents(ctx context.Context, msg types.EventData, events []abci.Event) error { - return s.publish(ctx, msg, events) +func (s *Server) PublishWithEvents(msg types.EventData, events []abci.Event) error { + return s.publish(msg, events) } // OnStop implements part of the Service interface. It is a no-op. @@ -309,15 +309,13 @@ func (s *Server) Wait() { <-s.exited; s.BaseService.Wait() } // OnStart implements Service.OnStart by starting the server. func (s *Server) OnStart(ctx context.Context) error { s.run(ctx); return nil } -func (s *Server) publish(ctx context.Context, data types.EventData, events []abci.Event) error { +func (s *Server) publish(data types.EventData, events []abci.Event) error { s.pubs.RLock() defer s.pubs.RUnlock() select { case <-s.done: return ErrServerStopped - case <-ctx.Done(): - return ctx.Err() case s.queue <- item{ Data: data, Events: events, diff --git a/internal/pubsub/pubsub_test.go b/internal/pubsub/pubsub_test.go index a6938ff75..e366977b5 100644 --- a/internal/pubsub/pubsub_test.go +++ b/internal/pubsub/pubsub_test.go @@ -42,7 +42,7 @@ func TestSubscribeWithArgs(t *testing.T) { require.Equal(t, 1, s.NumClients()) require.Equal(t, 1, s.NumClientSubscriptions(clientID)) - require.NoError(t, s.Publish(ctx, pubstring("Ka-Zar"))) + require.NoError(t, s.Publish(pubstring("Ka-Zar"))) sub.mustReceive(ctx, pubstring("Ka-Zar")) }) t.Run("PositiveLimit", func(t *testing.T) { @@ -51,7 +51,7 @@ func TestSubscribeWithArgs(t *testing.T) { Query: query.All, Limit: 10, })) - require.NoError(t, s.Publish(ctx, pubstring("Aggamon"))) + require.NoError(t, s.Publish(pubstring("Aggamon"))) sub.mustReceive(ctx, pubstring("Aggamon")) }) } @@ -72,7 +72,7 @@ func TestObserver(t *testing.T) { })) const input = pubstring("Lions and tigers and bears, oh my!") - require.NoError(t, s.Publish(ctx, input)) + require.NoError(t, s.Publish(input)) <-done require.Equal(t, got, input) } @@ -106,9 +106,9 @@ func TestPublishDoesNotBlock(t *testing.T) { go func() { defer close(published) - require.NoError(t, s.Publish(ctx, pubstring("Quicksilver"))) - require.NoError(t, s.Publish(ctx, pubstring("Asylum"))) - require.NoError(t, s.Publish(ctx, pubstring("Ivan"))) + require.NoError(t, s.Publish(pubstring("Quicksilver"))) + require.NoError(t, s.Publish(pubstring("Asylum"))) + require.NoError(t, s.Publish(pubstring("Ivan"))) }() select { @@ -149,9 +149,9 @@ func TestSlowSubscriber(t *testing.T) { Query: query.All, })) - require.NoError(t, s.Publish(ctx, pubstring("Fat Cobra"))) - require.NoError(t, s.Publish(ctx, pubstring("Viper"))) - require.NoError(t, s.Publish(ctx, pubstring("Black Panther"))) + require.NoError(t, s.Publish(pubstring("Fat Cobra"))) + require.NoError(t, s.Publish(pubstring("Viper"))) + require.NoError(t, s.Publish(pubstring("Black Panther"))) // We had capacity for one item, so we should get that item, but after that // the subscription should have been terminated by the publisher. @@ -176,7 +176,7 @@ func TestDifferentClients(t *testing.T) { Attributes: []abci.EventAttribute{{Key: "type", Value: "NewBlock"}}, }} - require.NoError(t, s.PublishWithEvents(ctx, pubstring("Iceman"), events)) + require.NoError(t, s.PublishWithEvents(pubstring("Iceman"), events)) sub1.mustReceive(ctx, pubstring("Iceman")) sub2 := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{ @@ -195,7 +195,7 @@ func TestDifferentClients(t *testing.T) { }, } - require.NoError(t, s.PublishWithEvents(ctx, pubstring("Ultimo"), events)) + require.NoError(t, s.PublishWithEvents(pubstring("Ultimo"), events)) sub1.mustReceive(ctx, pubstring("Ultimo")) sub2.mustReceive(ctx, pubstring("Ultimo")) @@ -210,7 +210,7 @@ func TestDifferentClients(t *testing.T) { Attributes: []abci.EventAttribute{{Key: "type", Value: "NewRoundStep"}}, }} - require.NoError(t, s.PublishWithEvents(ctx, pubstring("Valeria Richards"), events)) + require.NoError(t, s.PublishWithEvents(pubstring("Valeria Richards"), events)) sub3.mustTimeOut(ctx, 100*time.Millisecond) } @@ -259,7 +259,7 @@ func TestSubscribeDuplicateKeys(t *testing.T) { }, } - require.NoError(t, s.PublishWithEvents(ctx, pubstring("Iceman"), events)) + require.NoError(t, s.PublishWithEvents(pubstring("Iceman"), events)) if tc.expected != nil { sub.mustReceive(ctx, tc.expected) @@ -288,7 +288,7 @@ func TestClientSubscribesTwice(t *testing.T) { Query: q, })) - require.NoError(t, s.PublishWithEvents(ctx, pubstring("Goblin Queen"), events)) + require.NoError(t, s.PublishWithEvents(pubstring("Goblin Queen"), events)) sub1.mustReceive(ctx, pubstring("Goblin Queen")) // Subscribing a second time with the same client ID and query fails. @@ -302,7 +302,7 @@ func TestClientSubscribesTwice(t *testing.T) { } // The attempt to re-subscribe does not disrupt the existing sub. - require.NoError(t, s.PublishWithEvents(ctx, pubstring("Spider-Man"), events)) + require.NoError(t, s.PublishWithEvents(pubstring("Spider-Man"), events)) sub1.mustReceive(ctx, pubstring("Spider-Man")) } @@ -325,7 +325,7 @@ func TestUnsubscribe(t *testing.T) { })) // Publishing should still work. - require.NoError(t, s.Publish(ctx, pubstring("Nick Fury"))) + require.NoError(t, s.Publish(pubstring("Nick Fury"))) // The unsubscribed subscriber should report as such. sub.mustFail(ctx, pubsub.ErrUnsubscribed) @@ -373,7 +373,7 @@ func TestResubscribe(t *testing.T) { sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, args)) - require.NoError(t, s.Publish(ctx, pubstring("Cable"))) + require.NoError(t, s.Publish(pubstring("Cable"))) sub.mustReceive(ctx, pubstring("Cable")) } @@ -394,7 +394,7 @@ func TestUnsubscribeAll(t *testing.T) { })) require.NoError(t, s.UnsubscribeAll(ctx, clientID)) - require.NoError(t, s.Publish(ctx, pubstring("Nick Fury"))) + require.NoError(t, s.Publish(pubstring("Nick Fury"))) sub1.mustFail(ctx, pubsub.ErrUnsubscribed) sub2.mustFail(ctx, pubsub.ErrUnsubscribed) @@ -410,13 +410,24 @@ func TestBufferCapacity(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - require.NoError(t, s.Publish(ctx, pubstring("Nighthawk"))) - require.NoError(t, s.Publish(ctx, pubstring("Sage"))) + require.NoError(t, s.Publish(pubstring("Nighthawk"))) + require.NoError(t, s.Publish(pubstring("Sage"))) ctx, cancel = context.WithTimeout(ctx, 100*time.Millisecond) defer cancel() - require.ErrorIs(t, s.Publish(ctx, pubstring("Ironclad")), context.DeadlineExceeded) + sig := make(chan struct{}) + + go func() { defer close(sig); _ = s.Publish(pubstring("Ironclad")) }() + + select { + case <-sig: + t.Fatal("should not fire") + + case <-ctx.Done(): + return + } + } func newTestServer(ctx context.Context, t testing.TB, logger log.Logger) *pubsub.Server { diff --git a/internal/state/execution.go b/internal/state/execution.go index 145251428..0b2c83dbc 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -7,6 +7,7 @@ import ( abciclient "github.com/tendermint/tendermint/abci/client" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/internal/eventbus" @@ -291,34 +292,38 @@ func (blockExec *BlockExecutor) ApplyBlock( // Events are fired after everything else. // NOTE: if we crash between Commit and Save, events wont be fired during replay - fireEvents(ctx, blockExec.logger, blockExec.eventBus, block, blockID, finalizeBlockResponse, validatorUpdates) + fireEvents(blockExec.logger, blockExec.eventBus, block, blockID, finalizeBlockResponse, validatorUpdates) return state, nil } -func (blockExec *BlockExecutor) ExtendVote(ctx context.Context, vote *types.Vote) (types.VoteExtension, error) { +func (blockExec *BlockExecutor) ExtendVote(ctx context.Context, vote *types.Vote) ([]byte, error) { req := abci.RequestExtendVote{ - Vote: vote.ToProto(), + Hash: vote.BlockID.Hash, + Height: vote.Height, } resp, err := blockExec.appClient.ExtendVote(ctx, req) if err != nil { - return types.VoteExtension{}, err + panic(fmt.Errorf("ExtendVote call failed: %w", err)) } - return types.VoteExtensionFromProto(resp.VoteExtension), nil + return resp.VoteExtension, nil } func (blockExec *BlockExecutor) VerifyVoteExtension(ctx context.Context, vote *types.Vote) error { req := abci.RequestVerifyVoteExtension{ - Vote: vote.ToProto(), + Hash: vote.BlockID.Hash, + ValidatorAddress: vote.ValidatorAddress, + Height: vote.Height, + VoteExtension: vote.Extension, } resp, err := blockExec.appClient.VerifyVoteExtension(ctx, req) if err != nil { - return err + panic(fmt.Errorf("VerifyVoteExtension call failed: %w", err)) } - if resp.IsErr() { + if !resp.IsOK() { return types.ErrVoteInvalidExtension } @@ -417,16 +422,39 @@ func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) a } } +// extendedCommitInfo expects a CommitInfo struct along with all of the +// original votes relating to that commit, including their vote extensions. The +// order of votes does not matter. func extendedCommitInfo(c abci.CommitInfo, votes []*types.Vote) abci.ExtendedCommitInfo { + if len(c.Votes) != len(votes) { + panic(fmt.Sprintf("extendedCommitInfo: number of votes from commit differ from the number of votes supplied (%d != %d)", len(c.Votes), len(votes))) + } + votesByVal := make(map[string]*types.Vote) + for _, vote := range votes { + if vote != nil { + valAddr := vote.ValidatorAddress.String() + if _, ok := votesByVal[valAddr]; ok { + panic(fmt.Sprintf("extendedCommitInfo: found duplicate vote for validator with address %s", valAddr)) + } + votesByVal[valAddr] = vote + } + } vs := make([]abci.ExtendedVoteInfo, len(c.Votes)) for i := range vs { + var ext []byte + // votes[i] will be nil if c.Votes[i].SignedLastBlock is false + if c.Votes[i].SignedLastBlock { + valAddr := crypto.Address(c.Votes[i].Validator.Address).String() + vote, ok := votesByVal[valAddr] + if !ok || vote == nil { + panic(fmt.Sprintf("extendedCommitInfo: validator with address %s signed last block, but could not find vote for it", valAddr)) + } + ext = vote.Extension + } vs[i] = abci.ExtendedVoteInfo{ Validator: c.Votes[i].Validator, SignedLastBlock: c.Votes[i].SignedLastBlock, - /* - TODO: Include vote extensions information when implementing vote extensions. - VoteExtension: []byte{}, - */ + VoteExtension: ext, } } return abci.ExtendedCommitInfo{ @@ -530,7 +558,6 @@ func (state State) Update( // Fire TxEvent for every tx. // NOTE: if Tendermint crashes before commit, some or all of these events may be published again. func fireEvents( - ctx context.Context, logger log.Logger, eventBus types.BlockEventPublisher, block *types.Block, @@ -538,7 +565,7 @@ func fireEvents( finalizeBlockResponse *abci.ResponseFinalizeBlock, validatorUpdates []*types.Validator, ) { - if err := eventBus.PublishEventNewBlock(ctx, types.EventDataNewBlock{ + if err := eventBus.PublishEventNewBlock(types.EventDataNewBlock{ Block: block, BlockID: blockID, ResultFinalizeBlock: *finalizeBlockResponse, @@ -546,7 +573,7 @@ func fireEvents( logger.Error("failed publishing new block", "err", err) } - if err := eventBus.PublishEventNewBlockHeader(ctx, types.EventDataNewBlockHeader{ + if err := eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{ Header: block.Header, NumTxs: int64(len(block.Txs)), ResultFinalizeBlock: *finalizeBlockResponse, @@ -556,7 +583,7 @@ func fireEvents( if len(block.Evidence) != 0 { for _, ev := range block.Evidence { - if err := eventBus.PublishEventNewEvidence(ctx, types.EventDataNewEvidence{ + if err := eventBus.PublishEventNewEvidence(types.EventDataNewEvidence{ Evidence: ev, Height: block.Height, }); err != nil { @@ -572,7 +599,7 @@ func fireEvents( } for i, tx := range block.Data.Txs { - if err := eventBus.PublishEventTx(ctx, types.EventDataTx{ + if err := eventBus.PublishEventTx(types.EventDataTx{ TxResult: abci.TxResult{ Height: block.Height, Index: uint32(i), @@ -585,7 +612,7 @@ func fireEvents( } if len(finalizeBlockResponse.ValidatorUpdates) > 0 { - if err := eventBus.PublishEventValidatorSetUpdates(ctx, + if err := eventBus.PublishEventValidatorSetUpdates( types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}); err != nil { logger.Error("failed publishing event", "err", err) } @@ -644,7 +671,7 @@ func ExecCommitBlock( } blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - fireEvents(ctx, be.logger, be.eventBus, block, blockID, finalizeBlockResponse, validatorUpdates) + fireEvents(be.logger, be.eventBus, block, blockID, finalizeBlockResponse, validatorUpdates) } // Commit block, get hash back diff --git a/internal/state/execution_test.go b/internal/state/execution_test.go index c70286e28..dcbe01ef3 100644 --- a/internal/state/execution_test.go +++ b/internal/state/execution_test.go @@ -654,8 +654,8 @@ func TestEmptyPrepareProposal(t *testing.T) { sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) - commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) - _, err = blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + commit, votes := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + _, err = blockExec.CreateProposalBlock(ctx, height, state, commit, pa, votes) require.NoError(t, err) } @@ -709,8 +709,8 @@ func TestPrepareProposalErrorOnNonExistingRemoved(t *testing.T) { sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) - commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) - block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + commit, votes := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, votes) require.Nil(t, block) require.ErrorContains(t, err, "new transaction incorrectly marked as removed") @@ -765,8 +765,8 @@ func TestPrepareProposalRemoveTxs(t *testing.T) { sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) - commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) - block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + commit, votes := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, votes) require.NoError(t, err) require.Len(t, block.Data.Txs.ToSliceOfBytes(), len(trs)-2) @@ -824,8 +824,8 @@ func TestPrepareProposalAddedTxsIncluded(t *testing.T) { sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) - commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) - block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + commit, votes := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, votes) require.NoError(t, err) require.Equal(t, txs[0], block.Data.Txs[0]) @@ -880,8 +880,8 @@ func TestPrepareProposalReorderTxs(t *testing.T) { sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) - commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) - block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + commit, votes := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, votes) require.NoError(t, err) for i, tx := range block.Data.Txs { require.Equal(t, types.Tx(trs[i].Tx), tx) @@ -940,9 +940,9 @@ func TestPrepareProposalErrorOnTooManyTxs(t *testing.T) { sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) - commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + commit, votes := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) - block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, votes) require.Nil(t, block) require.ErrorContains(t, err, "transaction data size exceeds maximum") @@ -992,9 +992,9 @@ func TestPrepareProposalErrorOnPrepareProposalError(t *testing.T) { sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) - commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + commit, votes := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) - block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, votes) require.Nil(t, block) require.ErrorContains(t, err, "an injected error") diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index 1a926a91f..c3c143462 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -46,7 +46,7 @@ func makeAndCommitGoodBlock( state, blockID := makeAndApplyGoodBlock(ctx, t, state, height, lastCommit, proposerAddr, blockExec, evidence) // Simulate a lastCommit for this block from all validators for the next height - commit := makeValidCommit(ctx, t, height, blockID, state.Validators, privVals) + commit, _ := makeValidCommit(ctx, t, height, blockID, state.Validators, privVals) return state, blockID, commit } @@ -82,17 +82,19 @@ func makeValidCommit( blockID types.BlockID, vals *types.ValidatorSet, privVals map[string]types.PrivValidator, -) *types.Commit { +) (*types.Commit, []*types.Vote) { t.Helper() - sigs := make([]types.CommitSig, 0) + sigs := make([]types.CommitSig, vals.Size()) + votes := make([]*types.Vote, vals.Size()) for i := 0; i < vals.Size(); i++ { _, val := vals.GetByIndex(int32(i)) vote, err := factory.MakeVote(ctx, privVals[val.Address.String()], chainID, int32(i), height, 0, 2, blockID, time.Now()) require.NoError(t, err) - sigs = append(sigs, vote.CommitSig()) + sigs[i] = vote.CommitSig() + votes[i] = vote } - return types.NewCommit(height, 0, blockID, sigs) + return types.NewCommit(height, 0, blockID, sigs), votes } func makeState(t *testing.T, nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) { diff --git a/internal/state/indexer/indexer_service_test.go b/internal/state/indexer/indexer_service_test.go index a71b204ec..6126ae259 100644 --- a/internal/state/indexer/indexer_service_test.go +++ b/internal/state/indexer/indexer_service_test.go @@ -54,8 +54,7 @@ func TestIndexerServiceIndexesBlocks(t *testing.T) { assert.False(t, indexer.IndexingEnabled([]indexer.EventSink{})) // event sink setup - pool, err := setupDB(t) - assert.NoError(t, err) + pool := setupDB(t) store := dbm.NewMemDB() eventSinks := []indexer.EventSink{kv.NewEventSink(store), pSink} @@ -71,7 +70,7 @@ func TestIndexerServiceIndexesBlocks(t *testing.T) { t.Cleanup(service.Wait) // publish block with txs - err = eventBus.PublishEventNewBlockHeader(ctx, types.EventDataNewBlockHeader{ + err = eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{ Header: types.Header{Height: 1}, NumTxs: int64(2), }) @@ -82,7 +81,7 @@ func TestIndexerServiceIndexesBlocks(t *testing.T) { Tx: types.Tx("foo"), Result: abci.ExecTxResult{Code: 0}, } - err = eventBus.PublishEventTx(ctx, types.EventDataTx{TxResult: *txResult1}) + err = eventBus.PublishEventTx(types.EventDataTx{TxResult: *txResult1}) require.NoError(t, err) txResult2 := &abci.TxResult{ Height: 1, @@ -90,7 +89,7 @@ func TestIndexerServiceIndexesBlocks(t *testing.T) { Tx: types.Tx("bar"), Result: abci.ExecTxResult{Code: 0}, } - err = eventBus.PublishEventTx(ctx, types.EventDataTx{TxResult: *txResult2}) + err = eventBus.PublishEventTx(types.EventDataTx{TxResult: *txResult2}) require.NoError(t, err) time.Sleep(100 * time.Millisecond) @@ -133,7 +132,7 @@ func resetDB(t *testing.T) { assert.NoError(t, err) } -func setupDB(t *testing.T) (*dockertest.Pool, error) { +func setupDB(t *testing.T) *dockertest.Pool { t.Helper() pool, err := dockertest.NewPool(os.Getenv("DOCKER_URL")) assert.NoError(t, err) @@ -187,7 +186,7 @@ func setupDB(t *testing.T) (*dockertest.Pool, error) { err = migrator.Apply(psqldb, sm) assert.NoError(t, err) - return pool, nil + return pool } func teardown(t *testing.T, pool *dockertest.Pool) error { diff --git a/internal/statesync/reactor.go b/internal/statesync/reactor.go index ea2cac4f4..795da5063 100644 --- a/internal/statesync/reactor.go +++ b/internal/statesync/reactor.go @@ -333,7 +333,7 @@ func (r *Reactor) OnStop() { // of historical blocks before participating in consensus func (r *Reactor) Sync(ctx context.Context) (sm.State, error) { if r.eventBus != nil { - if err := r.eventBus.PublishEventStateSyncStatus(ctx, types.EventDataStateSyncStatus{ + if err := r.eventBus.PublishEventStateSyncStatus(types.EventDataStateSyncStatus{ Complete: false, Height: r.initialHeight, }); err != nil { @@ -387,7 +387,7 @@ func (r *Reactor) Sync(ctx context.Context) (sm.State, error) { } if r.eventBus != nil { - if err := r.eventBus.PublishEventStateSyncStatus(ctx, types.EventDataStateSyncStatus{ + if err := r.eventBus.PublishEventStateSyncStatus(types.EventDataStateSyncStatus{ Complete: true, Height: state.LastBlockHeight, }); err != nil { diff --git a/internal/statesync/stateprovider.go b/internal/statesync/stateprovider.go index 3e58ca5f4..a796b0b2e 100644 --- a/internal/statesync/stateprovider.go +++ b/internal/statesync/stateprovider.go @@ -379,7 +379,7 @@ func (s *stateProviderP2P) consensusParams(ctx context.Context, height int64) (t } wg.Add(1) - go func(p *BlockProvider, peer types.NodeID) { + go func(peer types.NodeID) { defer wg.Done() timer := time.NewTimer(0) @@ -424,7 +424,7 @@ func (s *stateProviderP2P) consensusParams(ctx context.Context, height int64) (t } } - }(p, peer) + }(peer) } sig := make(chan struct{}) go func() { wg.Wait(); close(sig) }() diff --git a/internal/store/store_test.go b/internal/store/store_test.go index 82949b103..4fa577cc4 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -17,7 +17,6 @@ import ( "github.com/tendermint/tendermint/crypto" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/state/test/factory" - "github.com/tendermint/tendermint/libs/log" tmrand "github.com/tendermint/tendermint/libs/rand" tmtime "github.com/tendermint/tendermint/libs/time" "github.com/tendermint/tendermint/types" @@ -46,7 +45,7 @@ func makeTestCommit(height int64, timestamp time.Time) *types.Commit { commitSigs) } -func makeStateAndBlockStore(dir string, logger log.Logger) (sm.State, *BlockStore, cleanupFunc, error) { +func makeStateAndBlockStore(dir string) (sm.State, *BlockStore, cleanupFunc, error) { cfg, err := config.ResetTestRoot(dir, "blockchain_reactor_test") if err != nil { return sm.State{}, nil, nil, err @@ -81,7 +80,7 @@ func TestMain(m *testing.M) { } var cleanup cleanupFunc - state, _, cleanup, err = makeStateAndBlockStore(dir, log.NewNopLogger()) + state, _, cleanup, err = makeStateAndBlockStore(dir) if err != nil { stdlog.Fatal(err) } @@ -103,7 +102,7 @@ func TestMain(m *testing.M) { // TODO: This test should be simplified ... func TestBlockStoreSaveLoadBlock(t *testing.T) { - state, bs, cleanup, err := makeStateAndBlockStore(t.TempDir(), log.NewNopLogger()) + state, bs, cleanup, err := makeStateAndBlockStore(t.TempDir()) defer cleanup() require.NoError(t, err) require.Equal(t, bs.Base(), int64(0), "initially the base should be zero") @@ -492,7 +491,7 @@ func TestLoadBlockMeta(t *testing.T) { } func TestBlockFetchAtHeight(t *testing.T) { - state, bs, cleanup, err := makeStateAndBlockStore(t.TempDir(), log.NewNopLogger()) + state, bs, cleanup, err := makeStateAndBlockStore(t.TempDir()) defer cleanup() require.NoError(t, err) require.Equal(t, bs.Height(), int64(0), "initially the height should be zero") diff --git a/internal/test/factory/commit.go b/internal/test/factory/commit.go index 1a8691855..bc4022499 100644 --- a/internal/test/factory/commit.go +++ b/internal/test/factory/commit.go @@ -31,6 +31,7 @@ func MakeCommit(ctx context.Context, blockID types.BlockID, height int64, round return nil, err } vote.Signature = v.Signature + vote.ExtensionSignature = v.ExtensionSignature if _, err := voteSet.AddVote(vote); err != nil { return nil, err } diff --git a/libs/bits/bit_array_test.go b/libs/bits/bit_array_test.go index b76085bee..e4bf45c38 100644 --- a/libs/bits/bit_array_test.go +++ b/libs/bits/bit_array_test.go @@ -13,25 +13,25 @@ import ( tmprotobits "github.com/tendermint/tendermint/proto/tendermint/libs/bits" ) -func randBitArray(bits int) (*BitArray, []byte) { +func randBitArray(bits int) *BitArray { src := tmrand.Bytes((bits + 7) / 8) bA := NewBitArray(bits) for i := 0; i < len(src); i++ { for j := 0; j < 8; j++ { if i*8+j >= bits { - return bA, src + return bA } setBit := src[i]&(1< 0 bA.SetIndex(i*8+j, setBit) } } - return bA, src + return bA } func TestAnd(t *testing.T) { - bA1, _ := randBitArray(51) - bA2, _ := randBitArray(31) + bA1 := randBitArray(51) + bA2 := randBitArray(31) bA3 := bA1.And(bA2) var bNil *BitArray @@ -54,9 +54,8 @@ func TestAnd(t *testing.T) { } func TestOr(t *testing.T) { - - bA1, _ := randBitArray(51) - bA2, _ := randBitArray(31) + bA1 := randBitArray(51) + bA2 := randBitArray(31) bA3 := bA1.Or(bA2) bNil := (*BitArray)(nil) @@ -191,10 +190,7 @@ func TestEmptyFull(t *testing.T) { } func TestUpdateNeverPanics(t *testing.T) { - newRandBitArray := func(n int) *BitArray { - ba, _ := randBitArray(n) - return ba - } + newRandBitArray := func(n int) *BitArray { return randBitArray(n) } pairs := []struct { a, b *BitArray }{ diff --git a/libs/events/events.go b/libs/events/events.go index 5ad1170a9..1b8db09c4 100644 --- a/libs/events/events.go +++ b/libs/events/events.go @@ -2,7 +2,6 @@ package events import ( - "context" "sync" ) @@ -20,7 +19,7 @@ type Eventable interface { // // FireEvent fires an event with the given name and data. type Fireable interface { - FireEvent(ctx context.Context, eventValue string, data EventData) + FireEvent(eventValue string, data EventData) } // EventSwitch is the interface for synchronous pubsub, where listeners @@ -62,7 +61,7 @@ func (evsw *eventSwitch) AddListenerForEvent(listenerID, eventValue string, cb E return nil } -func (evsw *eventSwitch) FireEvent(ctx context.Context, event string, data EventData) { +func (evsw *eventSwitch) FireEvent(event string, data EventData) { // Get the eventCell evsw.mtx.RLock() eventCell := evsw.eventCells[event] @@ -73,12 +72,12 @@ func (evsw *eventSwitch) FireEvent(ctx context.Context, event string, data Event } // Fire event for all listeners in eventCell - eventCell.fireEvent(ctx, data) + eventCell.fireEvent(data) } //----------------------------------------------------------------------------- -type EventCallback func(ctx context.Context, data EventData) error +type EventCallback func(data EventData) error // eventCell handles keeping track of listener callbacks for a given event. type eventCell struct { @@ -98,7 +97,7 @@ func (cell *eventCell) addListener(listenerID string, cb EventCallback) { cell.listeners[listenerID] = cb } -func (cell *eventCell) fireEvent(ctx context.Context, data EventData) { +func (cell *eventCell) fireEvent(data EventData) { cell.mtx.RLock() eventCallbacks := make([]EventCallback, 0, len(cell.listeners)) for _, cb := range cell.listeners { @@ -107,7 +106,7 @@ func (cell *eventCell) fireEvent(ctx context.Context, data EventData) { cell.mtx.RUnlock() for _, cb := range eventCallbacks { - if err := cb(ctx, data); err != nil { + if err := cb(data); err != nil { // should we log or abort here? continue } diff --git a/libs/events/events_test.go b/libs/events/events_test.go index fba2feba8..17f8c56d1 100644 --- a/libs/events/events_test.go +++ b/libs/events/events_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/fortytw2/leaktest" "github.com/stretchr/testify/require" ) @@ -20,7 +21,7 @@ func TestAddListenerForEventFireOnce(t *testing.T) { messages := make(chan EventData) require.NoError(t, evsw.AddListenerForEvent("listener", "event", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case messages <- data: return nil @@ -28,7 +29,7 @@ func TestAddListenerForEventFireOnce(t *testing.T) { return ctx.Err() } })) - go evsw.FireEvent(ctx, "event", "data") + go evsw.FireEvent("event", "data") received := <-messages if received != "data" { t.Errorf("message received does not match: %v", received) @@ -48,7 +49,7 @@ func TestAddListenerForEventFireMany(t *testing.T) { numbers := make(chan uint64, 4) // subscribe one listener for one event require.NoError(t, evsw.AddListenerForEvent("listener", "event", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers <- data.(uint64): return nil @@ -75,6 +76,8 @@ func TestAddListenerForDifferentEvents(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + t.Cleanup(leaktest.Check(t)) + evsw := NewEventSwitch() doneSum := make(chan uint64) @@ -84,7 +87,7 @@ func TestAddListenerForDifferentEvents(t *testing.T) { numbers := make(chan uint64, 4) // subscribe one listener to three events require.NoError(t, evsw.AddListenerForEvent("listener", "event1", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers <- data.(uint64): return nil @@ -93,7 +96,7 @@ func TestAddListenerForDifferentEvents(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener", "event2", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers <- data.(uint64): return nil @@ -102,7 +105,7 @@ func TestAddListenerForDifferentEvents(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener", "event3", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers <- data.(uint64): return nil @@ -135,6 +138,8 @@ func TestAddDifferentListenerForDifferentEvents(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + t.Cleanup(leaktest.Check(t)) + evsw := NewEventSwitch() doneSum1 := make(chan uint64) @@ -146,7 +151,7 @@ func TestAddDifferentListenerForDifferentEvents(t *testing.T) { numbers2 := make(chan uint64, 4) // subscribe two listener to three events require.NoError(t, evsw.AddListenerForEvent("listener1", "event1", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers1 <- data.(uint64): return nil @@ -155,7 +160,7 @@ func TestAddDifferentListenerForDifferentEvents(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener1", "event2", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers1 <- data.(uint64): return nil @@ -164,7 +169,7 @@ func TestAddDifferentListenerForDifferentEvents(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener1", "event3", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers1 <- data.(uint64): return nil @@ -173,7 +178,7 @@ func TestAddDifferentListenerForDifferentEvents(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener2", "event2", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers2 <- data.(uint64): return nil @@ -182,7 +187,7 @@ func TestAddDifferentListenerForDifferentEvents(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener2", "event3", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers2 <- data.(uint64): return nil @@ -238,7 +243,7 @@ func TestManageListenersAsync(t *testing.T) { numbers2 := make(chan uint64, 4) // subscribe two listener to three events require.NoError(t, evsw.AddListenerForEvent("listener1", "event1", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers1 <- data.(uint64): return nil @@ -247,7 +252,7 @@ func TestManageListenersAsync(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener1", "event2", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers1 <- data.(uint64): return nil @@ -256,7 +261,7 @@ func TestManageListenersAsync(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener1", "event3", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers1 <- data.(uint64): return nil @@ -265,7 +270,7 @@ func TestManageListenersAsync(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener2", "event1", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers2 <- data.(uint64): return nil @@ -274,7 +279,7 @@ func TestManageListenersAsync(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener2", "event2", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers2 <- data.(uint64): return nil @@ -283,7 +288,7 @@ func TestManageListenersAsync(t *testing.T) { } })) require.NoError(t, evsw.AddListenerForEvent("listener2", "event3", - func(ctx context.Context, data EventData) error { + func(data EventData) error { select { case numbers2 <- data.(uint64): return nil @@ -303,7 +308,7 @@ func TestManageListenersAsync(t *testing.T) { eventNumber := r1.Intn(3) + 1 go evsw.AddListenerForEvent(fmt.Sprintf("listener%v", listenerNumber), //nolint:errcheck // ignore for tests fmt.Sprintf("event%v", eventNumber), - func(context.Context, EventData) error { return nil }) + func(EventData) error { return nil }) } } addListenersStress() @@ -358,7 +363,7 @@ func fireEvents(ctx context.Context, evsw Fireable, event string, doneChan chan break } - evsw.FireEvent(ctx, event, i) + evsw.FireEvent(event, i) sentSum += i } diff --git a/light/client_benchmark_test.go b/light/client_benchmark_test.go index 4a54e2b54..c92b70990 100644 --- a/light/client_benchmark_test.go +++ b/light/client_benchmark_test.go @@ -69,7 +69,7 @@ func BenchmarkSequence(b *testing.B) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - headers, vals, _ := genLightBlocksWithKeys(b, chainID, 1000, 100, 1, bTime) + headers, vals, _ := genLightBlocksWithKeys(b, 1000, 100, 1, bTime) benchmarkFullNode := newProviderBenchmarkImpl(headers, vals) genesisBlock, _ := benchmarkFullNode.LightBlock(ctx, 1) @@ -106,7 +106,7 @@ func BenchmarkBisection(b *testing.B) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - headers, vals, _ := genLightBlocksWithKeys(b, chainID, 1000, 100, 1, bTime) + headers, vals, _ := genLightBlocksWithKeys(b, 1000, 100, 1, bTime) benchmarkFullNode := newProviderBenchmarkImpl(headers, vals) genesisBlock, _ := benchmarkFullNode.LightBlock(ctx, 1) @@ -142,7 +142,7 @@ func BenchmarkBackwards(b *testing.B) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - headers, vals, _ := genLightBlocksWithKeys(b, chainID, 1000, 100, 1, bTime) + headers, vals, _ := genLightBlocksWithKeys(b, 1000, 100, 1, bTime) benchmarkFullNode := newProviderBenchmarkImpl(headers, vals) trustedBlock, _ := benchmarkFullNode.LightBlock(ctx, 0) diff --git a/light/client_test.go b/light/client_test.go index fbf8536ba..8ecd842c9 100644 --- a/light/client_test.go +++ b/light/client_test.go @@ -387,7 +387,7 @@ func TestClient(t *testing.T) { // the appropriate range numBlocks := int64(300) - mockHeaders, mockVals, _ := genLightBlocksWithKeys(t, chainID, numBlocks, 101, 2, bTime) + mockHeaders, mockVals, _ := genLightBlocksWithKeys(t, numBlocks, 101, 2, bTime) lastBlock := &types.LightBlock{SignedHeader: mockHeaders[numBlocks], ValidatorSet: mockVals[numBlocks]} mockNode := &provider_mocks.Provider{} @@ -773,7 +773,7 @@ func TestClient(t *testing.T) { logger := log.NewNopLogger() { - headers, vals, _ := genLightBlocksWithKeys(t, chainID, 9, 3, 0, bTime) + headers, vals, _ := genLightBlocksWithKeys(t, 9, 3, 0, bTime) delete(headers, 1) delete(headers, 2) delete(vals, 1) diff --git a/light/detector_test.go b/light/detector_test.go index 82b0d2de6..4a86b5b87 100644 --- a/light/detector_test.go +++ b/light/detector_test.go @@ -35,7 +35,7 @@ func TestLightClientAttackEvidence_Lunatic(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - witnessHeaders, witnessValidators, chainKeys := genLightBlocksWithKeys(t, chainID, latestHeight, valSize, 2, bTime) + witnessHeaders, witnessValidators, chainKeys := genLightBlocksWithKeys(t, latestHeight, valSize, 2, bTime) forgedKeys := chainKeys[divergenceHeight-1].ChangeKeys(3) // we change 3 out of the 5 validators (still 2/5 remain) forgedVals := forgedKeys.ToValidators(2, 0) @@ -153,7 +153,7 @@ func TestLightClientAttackEvidence_Equivocation(t *testing.T) { // validators don't change in this network (however we still use a map just for convenience) primaryValidators = make(map[int64]*types.ValidatorSet, testCase.latestHeight) ) - witnessHeaders, witnessValidators, chainKeys := genLightBlocksWithKeys(t, chainID, + witnessHeaders, witnessValidators, chainKeys := genLightBlocksWithKeys(t, testCase.latestHeight+1, valSize, 2, bTime) for height := int64(1); height <= testCase.latestHeight; height++ { if height < testCase.divergenceHeight { @@ -250,7 +250,7 @@ func TestLightClientAttackEvidence_ForwardLunatic(t *testing.T) { defer cancel() logger := log.NewNopLogger() - witnessHeaders, witnessValidators, chainKeys := genLightBlocksWithKeys(t, chainID, latestHeight, valSize, 2, bTime) + witnessHeaders, witnessValidators, chainKeys := genLightBlocksWithKeys(t, latestHeight, valSize, 2, bTime) for _, unusedHeader := range []int64{3, 5, 6, 8} { delete(witnessHeaders, unusedHeader) } @@ -401,13 +401,13 @@ func TestClientDivergentTraces1(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - headers, vals, _ := genLightBlocksWithKeys(t, chainID, 1, 5, 2, bTime) + headers, vals, _ := genLightBlocksWithKeys(t, 1, 5, 2, bTime) mockPrimary := mockNodeFromHeadersAndVals(headers, vals) mockPrimary.On("ID").Return("mockPrimary") firstBlock, err := mockPrimary.LightBlock(ctx, 1) require.NoError(t, err) - headers, vals, _ = genLightBlocksWithKeys(t, chainID, 1, 5, 2, bTime) + headers, vals, _ = genLightBlocksWithKeys(t, 1, 5, 2, bTime) mockWitness := mockNodeFromHeadersAndVals(headers, vals) mockWitness.On("ID").Return("mockWitness") @@ -439,7 +439,7 @@ func TestClientDivergentTraces2(t *testing.T) { defer cancel() logger := log.NewNopLogger() - headers, vals, _ := genLightBlocksWithKeys(t, chainID, 2, 5, 2, bTime) + headers, vals, _ := genLightBlocksWithKeys(t, 2, 5, 2, bTime) mockPrimaryNode := mockNodeFromHeadersAndVals(headers, vals) mockPrimaryNode.On("ID").Return("mockPrimaryNode") @@ -485,7 +485,7 @@ func TestClientDivergentTraces3(t *testing.T) { logger := log.NewNopLogger() // - primaryHeaders, primaryVals, _ := genLightBlocksWithKeys(t, chainID, 2, 5, 2, bTime) + primaryHeaders, primaryVals, _ := genLightBlocksWithKeys(t, 2, 5, 2, bTime) mockPrimary := mockNodeFromHeadersAndVals(primaryHeaders, primaryVals) mockPrimary.On("ID").Return("mockPrimary") @@ -495,7 +495,7 @@ func TestClientDivergentTraces3(t *testing.T) { firstBlock, err := mockPrimary.LightBlock(ctx, 1) require.NoError(t, err) - mockHeaders, mockVals, _ := genLightBlocksWithKeys(t, chainID, 2, 5, 2, bTime) + mockHeaders, mockVals, _ := genLightBlocksWithKeys(t, 2, 5, 2, bTime) mockHeaders[1] = primaryHeaders[1] mockVals[1] = primaryVals[1] mockWitness := mockNodeFromHeadersAndVals(mockHeaders, mockVals) @@ -530,7 +530,7 @@ func TestClientDivergentTraces4(t *testing.T) { logger := log.NewNopLogger() // - primaryHeaders, primaryVals, _ := genLightBlocksWithKeys(t, chainID, 2, 5, 2, bTime) + primaryHeaders, primaryVals, _ := genLightBlocksWithKeys(t, 2, 5, 2, bTime) mockPrimary := mockNodeFromHeadersAndVals(primaryHeaders, primaryVals) mockPrimary.On("ID").Return("mockPrimary") @@ -540,7 +540,7 @@ func TestClientDivergentTraces4(t *testing.T) { firstBlock, err := mockPrimary.LightBlock(ctx, 1) require.NoError(t, err) - witnessHeaders, witnessVals, _ := genLightBlocksWithKeys(t, chainID, 2, 5, 2, bTime) + witnessHeaders, witnessVals, _ := genLightBlocksWithKeys(t, 2, 5, 2, bTime) primaryHeaders[2] = witnessHeaders[2] primaryVals[2] = witnessVals[2] mockWitness := mockNodeFromHeadersAndVals(primaryHeaders, primaryVals) diff --git a/light/helpers_test.go b/light/helpers_test.go index 73ef2ae65..4d002d936 100644 --- a/light/helpers_test.go +++ b/light/helpers_test.go @@ -160,7 +160,6 @@ func (pkz privKeys) ChangeKeys(delta int) privKeys { // NOTE: Expected to have a large validator set size ~ 100 validators. func genLightBlocksWithKeys( t testing.TB, - chainID string, numBlocks int64, valSize int, valVariation float32, diff --git a/node/node.go b/node/node.go index 8a4da29f2..c3aeaccf1 100644 --- a/node/node.go +++ b/node/node.go @@ -29,6 +29,7 @@ import ( rpccore "github.com/tendermint/tendermint/internal/rpc/core" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/state/indexer" + "github.com/tendermint/tendermint/internal/state/indexer/sink" "github.com/tendermint/tendermint/internal/statesync" "github.com/tendermint/tendermint/internal/store" "github.com/tendermint/tendermint/libs/log" @@ -168,15 +169,19 @@ func makeNode( Metrics: nodeMetrics.eventlog, }) if err != nil { - return nil, fmt.Errorf("initializing event log: %w", err) + return nil, combineCloseError(fmt.Errorf("initializing event log: %w", err), makeCloser(closers)) } } - - indexerService, eventSinks, err := createIndexerService( - cfg, dbProvider, eventBus, logger, genDoc.ChainID, nodeMetrics.indexer) + eventSinks, err := sink.EventSinksFromConfig(cfg, dbProvider, genDoc.ChainID) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) } + indexerService := indexer.NewService(indexer.ServiceArgs{ + Sinks: eventSinks, + EventBus: eventBus, + Logger: logger.With("module", "txindex"), + Metrics: nodeMetrics.indexer, + }) privValidator, err := createPrivval(ctx, logger, cfg, genDoc, filePrivval) if err != nil { @@ -260,11 +265,8 @@ func makeNode( node.rpcEnv.EvidencePool = evPool node.evPool = evPool - mpReactor, mp, err := createMempoolReactor(logger, cfg, proxyApp, stateStore, nodeMetrics.mempool, + mpReactor, mp := createMempoolReactor(logger, cfg, proxyApp, stateStore, nodeMetrics.mempool, peerManager.Subscribe, node.router.OpenChannel, peerManager.GetHeight) - if err != nil { - return nil, combineCloseError(err, makeCloser(closers)) - } node.rpcEnv.Mempool = mp node.services = append(node.services, mpReactor) @@ -292,16 +294,32 @@ func makeNode( blockSync := !onlyValidatorIsUs(state, pubKey) waitSync := stateSync || blockSync - csReactor, csState, err := createConsensusReactor(ctx, - cfg, stateStore, blockExec, blockStore, mp, evPool, - privValidator, nodeMetrics.consensus, waitSync, eventBus, - peerManager, node.router.OpenChannel, logger, + csState, err := consensus.NewState(logger.With("module", "consensus"), + cfg.Consensus, + stateStore, + blockExec, + blockStore, + mp, + evPool, + eventBus, + consensus.StateMetrics(nodeMetrics.consensus), + consensus.SkipStateStoreBootstrap, ) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) } - node.services = append(node.services, csReactor) node.rpcEnv.ConsensusState = csState + + csReactor := consensus.NewReactor( + logger, + csState, + node.router.OpenChannel, + peerManager.Subscribe, + eventBus, + waitSync, + nodeMetrics.consensus, + ) + node.services = append(node.services, csReactor) node.rpcEnv.ConsensusReactor = csReactor // Create the blockchain reactor. Note, we do not start block sync if we're @@ -370,6 +388,9 @@ func makeNode( )) if cfg.Mode == config.ModeValidator { + if privValidator != nil { + csState.SetPrivValidator(ctx, privValidator) + } node.rpcEnv.PubKey = pubKey } @@ -423,7 +444,7 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { // Start Internal Services if n.config.RPC.PprofListenAddress != "" { - rpcCtx, rpcCancel := context.WithCancel(ctx) + signal := make(chan struct{}) srv := &http.Server{Addr: n.config.RPC.PprofListenAddress, Handler: nil} go func() { select { @@ -431,7 +452,7 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { sctx, scancel := context.WithTimeout(context.Background(), time.Second) defer scancel() _ = srv.Shutdown(sctx) - case <-rpcCtx.Done(): + case <-signal: } }() @@ -440,7 +461,7 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { if err := srv.ListenAndServe(); err != nil { n.logger.Error("pprof server error", "err", err) - rpcCancel() + close(signal) } }() } @@ -562,21 +583,21 @@ func (n *nodeImpl) startPrometheusServer(ctx context.Context, addr string) *http ), } - promCtx, promCancel := context.WithCancel(ctx) + signal := make(chan struct{}) go func() { select { case <-ctx.Done(): sctx, scancel := context.WithTimeout(context.Background(), time.Second) defer scancel() _ = srv.Shutdown(sctx) - case <-promCtx.Done(): + case <-signal: } }() go func() { if err := srv.ListenAndServe(); err != nil { n.logger.Error("Prometheus HTTP server ListenAndServe", "err", err) - promCancel() + close(signal) } }() diff --git a/node/node_test.go b/node/node_test.go index 2736ca818..cb6f65add 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -28,6 +28,7 @@ import ( "github.com/tendermint/tendermint/internal/pubsub" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/state/indexer" + "github.com/tendermint/tendermint/internal/state/indexer/sink" "github.com/tendermint/tendermint/internal/store" "github.com/tendermint/tendermint/internal/test/factory" "github.com/tendermint/tendermint/libs/log" @@ -454,7 +455,8 @@ func TestMaxProposalBlockSize(t *testing.T) { err = proxyApp.Start(ctx) require.NoError(t, err) - state, stateDB, _ := state(t, types.MaxVotesCount, int64(1)) + state, stateDB, privVals := state(t, types.MaxVotesCount, int64(1)) + stateStore := sm.NewStore(stateDB) blockStore := store.NewBlockStore(dbm.NewMemDB()) const maxBytes int64 = 1024 * 1024 * 2 @@ -537,17 +539,25 @@ func TestMaxProposalBlockSize(t *testing.T) { BlockID: blockID, } + votes := make([]*types.Vote, types.MaxVotesCount) + // add maximum amount of signatures to a single commit for i := 0; i < types.MaxVotesCount; i++ { + pubKey, err := privVals[i].GetPubKey(ctx) + require.NoError(t, err) + votes[i] = &types.Vote{ + ValidatorAddress: pubKey.Address(), + } commit.Signatures = append(commit.Signatures, cs) } block, err := blockExec.CreateProposalBlock( ctx, math.MaxInt64, - state, commit, + state, + commit, proposerAddr, - nil, + votes, ) require.NoError(t, err) partSet, err := block.MakePartSet(types.BlockPartSizeBytes) @@ -627,11 +637,9 @@ func TestNodeSetEventSink(t *testing.T) { genDoc, err := types.GenesisDocFromFile(cfg.GenesisFile()) require.NoError(t, err) - indexService, eventSinks, err := createIndexerService(cfg, - config.DefaultDBProvider, eventBus, logger, genDoc.ChainID, - indexer.NopMetrics()) + eventSinks, err := sink.EventSinksFromConfig(cfg, config.DefaultDBProvider, genDoc.ChainID) require.NoError(t, err) - t.Cleanup(indexService.Wait) + return eventSinks } cleanup := func(ns service.Service) func() { diff --git a/node/setup.go b/node/setup.go index 1057fb6fa..512b02901 100644 --- a/node/setup.go +++ b/node/setup.go @@ -23,7 +23,6 @@ import ( "github.com/tendermint/tendermint/internal/p2p/pex" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/state/indexer" - "github.com/tendermint/tendermint/internal/state/indexer/sink" "github.com/tendermint/tendermint/internal/statesync" "github.com/tendermint/tendermint/internal/store" "github.com/tendermint/tendermint/libs/log" @@ -95,29 +94,6 @@ func initDBs( return blockStore, stateDB, makeCloser(closers), nil } -func createIndexerService( - cfg *config.Config, - dbProvider config.DBProvider, - eventBus *eventbus.EventBus, - logger log.Logger, - chainID string, - metrics *indexer.Metrics, -) (*indexer.Service, []indexer.EventSink, error) { - eventSinks, err := sink.EventSinksFromConfig(cfg, dbProvider, chainID) - if err != nil { - return nil, nil, err - } - - indexerService := indexer.NewService(indexer.ServiceArgs{ - Sinks: eventSinks, - EventBus: eventBus, - Logger: logger.With("module", "txindex"), - Metrics: metrics, - }) - - return indexerService, eventSinks, nil -} - func logNodeStartupInfo(state sm.State, pubKey crypto.PubKey, logger log.Logger, mode string) { // Log the version info. logger.Info("Version info", @@ -172,7 +148,7 @@ func createMempoolReactor( peerEvents p2p.PeerEventSubscriber, chCreator p2p.ChannelCreator, peerHeight func(types.NodeID) int64, -) (service.Service, mempool.Mempool, error) { +) (service.Service, mempool.Mempool) { logger = logger.With("module", "mempool") mp := mempool.NewTxMempool( @@ -197,7 +173,7 @@ func createMempoolReactor( mp.EnableTxsAvailable() } - return reactor, mp, nil + return reactor, mp } func createEvidenceReactor( @@ -215,70 +191,13 @@ func createEvidenceReactor( if err != nil { return nil, nil, func() error { return nil }, fmt.Errorf("unable to initialize evidence db: %w", err) } - dbCloser := evidenceDB.Close logger = logger.With("module", "evidence") evidencePool := evidence.NewPool(logger, evidenceDB, store, blockStore, metrics, eventBus) + evidenceReactor := evidence.NewReactor(logger, chCreator, peerEvents, evidencePool) - evidenceReactor := evidence.NewReactor( - logger, - chCreator, - peerEvents, - evidencePool, - ) - - return evidenceReactor, evidencePool, dbCloser, nil -} - -func createConsensusReactor( - ctx context.Context, - cfg *config.Config, - store sm.Store, - blockExec *sm.BlockExecutor, - blockStore sm.BlockStore, - mp mempool.Mempool, - evidencePool *evidence.Pool, - privValidator types.PrivValidator, - csMetrics *consensus.Metrics, - waitSync bool, - eventBus *eventbus.EventBus, - peerManager *p2p.PeerManager, - chCreator p2p.ChannelCreator, - logger log.Logger, -) (*consensus.Reactor, *consensus.State, error) { - logger = logger.With("module", "consensus") - - consensusState, err := consensus.NewState(ctx, - logger, - cfg.Consensus, - store, - blockExec, - blockStore, - mp, - evidencePool, - eventBus, - consensus.StateMetrics(csMetrics), - consensus.SkipStateStoreBootstrap, - ) - if err != nil { - return nil, nil, err - } - - if privValidator != nil && cfg.Mode == config.ModeValidator { - consensusState.SetPrivValidator(ctx, privValidator) - } - - reactor := consensus.NewReactor( - logger, - consensusState, - chCreator, - peerManager.Subscribe, - eventBus, - waitSync, - csMetrics, - ) - return reactor, consensusState, nil + return evidenceReactor, evidencePool, evidenceDB.Close, nil } func createPeerManager( diff --git a/privval/file.go b/privval/file.go index 728e0dc67..1e31b8c78 100644 --- a/privval/file.go +++ b/privval/file.go @@ -117,6 +117,14 @@ type FilePVLastSignState struct { filePath string } +func (lss *FilePVLastSignState) reset() { + lss.Height = 0 + lss.Round = 0 + lss.Step = 0 + lss.Signature = nil + lss.SignBytes = nil +} + // checkHRS checks the given height, round, step (HRS) against that of the // FilePVLastSignState. It returns an error if the arguments constitute a regression, // or if they match but the SignBytes are empty. @@ -328,12 +336,7 @@ func (pv *FilePV) Save() error { // Reset resets all fields in the FilePV. // NOTE: Unsafe! func (pv *FilePV) Reset() error { - var sig []byte - pv.LastSignState.Height = 0 - pv.LastSignState.Round = 0 - pv.LastSignState.Step = 0 - pv.LastSignState.Signature = sig - pv.LastSignState.SignBytes = nil + pv.LastSignState.reset() return pv.Save() } @@ -369,6 +372,12 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error { } signBytes := types.VoteSignBytes(chainID, vote) + extSignBytes := types.VoteExtensionSignBytes(chainID, vote) + // We always sign the vote extension. See below for details. + extSig, err := pv.Key.PrivKey.Sign(extSignBytes) + if err != nil { + return err + } // We might crash before writing to the wal, // causing us to try to re-sign for the same HRS. @@ -379,6 +388,8 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error { if bytes.Equal(signBytes, lss.SignBytes) { vote.Signature = lss.Signature } else { + // Compares the canonicalized votes (i.e. without vote extensions + // or vote extension signatures). timestamp, ok, err := checkVotesOnlyDifferByTimestamp(lss.SignBytes, signBytes) if err != nil { return err @@ -390,6 +401,12 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error { vote.Timestamp = timestamp vote.Signature = lss.Signature } + + // Vote extensions are non-deterministic, so it's possible that an + // application may have created a different extension. We therefore + // always re-sign the vote extension. + vote.ExtensionSignature = extSig + return nil } @@ -402,6 +419,8 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error { return err } vote.Signature = sig + vote.ExtensionSignature = extSig + return nil } @@ -453,8 +472,10 @@ func (pv *FilePV) saveSigned(height int64, round int32, step int8, signBytes []b //----------------------------------------------------------------------------------------- -// returns the timestamp from the lastSignBytes. -// returns true if the only difference in the votes is their timestamp. +// Returns the timestamp from the lastSignBytes. +// Returns true if the only difference in the votes is their timestamp. +// Performs these checks on the canonical votes (excluding the vote extension +// and vote extension signatures). func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool, error) { var lastVote, newVote tmproto.CanonicalVote if err := protoio.UnmarshalDelimited(lastSignBytes, &lastVote); err != nil { diff --git a/privval/file_test.go b/privval/file_test.go index 91c2e2a9b..30df335a2 100644 --- a/privval/file_test.go +++ b/privval/file_test.go @@ -21,20 +21,14 @@ import ( ) func TestGenLoadValidator(t *testing.T) { - tempKeyFile, err := os.CreateTemp(t.TempDir(), "priv_validator_key_") - require.NoError(t, err) - tempStateFile, err := os.CreateTemp(t.TempDir(), "priv_validator_state_") - require.NoError(t, err) - - privVal, err := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), "") - require.NoError(t, err) + privVal, tempKeyFileName, tempStateFileName := newTestFilePV(t) height := int64(100) privVal.LastSignState.Height = height require.NoError(t, privVal.Save()) addr := privVal.GetAddress() - privVal, err = LoadFilePV(tempKeyFile.Name(), tempStateFile.Name()) + privVal, err := LoadFilePV(tempKeyFileName, tempStateFileName) assert.NoError(t, err) assert.Equal(t, addr, privVal.GetAddress(), "expected privval addr to be the same") assert.Equal(t, height, privVal.LastSignState.Height, "expected privval.LastHeight to have been saved") @@ -44,14 +38,8 @@ func TestResetValidator(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - tempKeyFile, err := os.CreateTemp(t.TempDir(), "priv_validator_key_") - require.NoError(t, err) - tempStateFile, err := os.CreateTemp(t.TempDir(), "priv_validator_state_") - require.NoError(t, err) - - privVal, err := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), "") - require.NoError(t, err) - emptyState := FilePVLastSignState{filePath: tempStateFile.Name()} + privVal, _, tempStateFileName := newTestFilePV(t) + emptyState := FilePVLastSignState{filePath: tempStateFileName} // new priv val has empty state assert.Equal(t, privVal.LastSignState, emptyState) @@ -61,8 +49,8 @@ func TestResetValidator(t *testing.T) { voteType := tmproto.PrevoteType randBytes := tmrand.Bytes(tmhash.Size) blockID := types.BlockID{Hash: randBytes, PartSetHeader: types.PartSetHeader{}} - vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID) - err = privVal.SignVote(ctx, "mychainid", vote.ToProto()) + vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID, nil) + err := privVal.SignVote(ctx, "mychainid", vote.ToProto()) assert.NoError(t, err, "expected no error signing vote") // priv val after signing is not same as empty @@ -160,13 +148,7 @@ func TestSignVote(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - tempKeyFile, err := os.CreateTemp(t.TempDir(), "priv_validator_key_") - require.NoError(t, err) - tempStateFile, err := os.CreateTemp(t.TempDir(), "priv_validator_state_") - require.NoError(t, err) - - privVal, err := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), "") - require.NoError(t, err) + privVal, _, _ := newTestFilePV(t) randbytes := tmrand.Bytes(tmhash.Size) randbytes2 := tmrand.Bytes(tmhash.Size) @@ -180,10 +162,10 @@ func TestSignVote(t *testing.T) { voteType := tmproto.PrevoteType // sign a vote for first time - vote := newVote(privVal.Key.Address, 0, height, round, voteType, block1) + vote := newVote(privVal.Key.Address, 0, height, round, voteType, block1, nil) v := vote.ToProto() - err = privVal.SignVote(ctx, "mychainid", v) + err := privVal.SignVote(ctx, "mychainid", v) assert.NoError(t, err, "expected no error signing vote") // try to sign the same vote again; should be fine @@ -192,10 +174,10 @@ func TestSignVote(t *testing.T) { // now try some bad votes cases := []*types.Vote{ - newVote(privVal.Key.Address, 0, height, round-1, voteType, block1), // round regression - newVote(privVal.Key.Address, 0, height-1, round, voteType, block1), // height regression - newVote(privVal.Key.Address, 0, height-2, round+4, voteType, block1), // height regression and different round - newVote(privVal.Key.Address, 0, height, round, voteType, block2), // different block + newVote(privVal.Key.Address, 0, height, round-1, voteType, block1, nil), // round regression + newVote(privVal.Key.Address, 0, height-1, round, voteType, block1, nil), // height regression + newVote(privVal.Key.Address, 0, height-2, round+4, voteType, block1, nil), // height regression and different round + newVote(privVal.Key.Address, 0, height, round, voteType, block2, nil), // different block } for _, c := range cases { @@ -215,13 +197,7 @@ func TestSignProposal(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - tempKeyFile, err := os.CreateTemp(t.TempDir(), "priv_validator_key_") - require.NoError(t, err) - tempStateFile, err := os.CreateTemp(t.TempDir(), "priv_validator_state_") - require.NoError(t, err) - - privVal, err := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), "") - require.NoError(t, err) + privVal, _, _ := newTestFilePV(t) randbytes := tmrand.Bytes(tmhash.Size) randbytes2 := tmrand.Bytes(tmhash.Size) @@ -237,7 +213,7 @@ func TestSignProposal(t *testing.T) { proposal := newProposal(height, round, block1, ts) pbp := proposal.ToProto() - err = privVal.SignProposal(ctx, "mychainid", pbp) + err := privVal.SignProposal(ctx, "mychainid", pbp) assert.NoError(t, err, "expected no error signing proposal") // try to sign the same proposal again; should be fine @@ -278,7 +254,7 @@ func TestDifferByTimestamp(t *testing.T) { { voteType := tmproto.PrevoteType blockID := types.BlockID{Hash: randbytes, PartSetHeader: types.PartSetHeader{}} - vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID) + vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID, nil) v := vote.ToProto() err := privVal.SignVote(ctx, "mychainid", v) require.NoError(t, err, "expected no error signing vote") @@ -300,8 +276,69 @@ func TestDifferByTimestamp(t *testing.T) { } } +func TestVoteExtensionsAreAlwaysSigned(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + privVal, _, _ := newTestFilePV(t) + pubKey, err := privVal.GetPubKey(ctx) + assert.NoError(t, err) + + block := types.BlockID{ + Hash: tmrand.Bytes(tmhash.Size), + PartSetHeader: types.PartSetHeader{Total: 5, Hash: tmrand.Bytes(tmhash.Size)}, + } + + height, round := int64(10), int32(1) + voteType := tmproto.PrecommitType + + // We initially sign this vote without an extension + vote1 := newVote(privVal.Key.Address, 0, height, round, voteType, block, nil) + vpb1 := vote1.ToProto() + + err = privVal.SignVote(ctx, "mychainid", vpb1) + assert.NoError(t, err, "expected no error signing vote") + assert.NotNil(t, vpb1.ExtensionSignature) + + vesb1 := types.VoteExtensionSignBytes("mychainid", vpb1) + assert.True(t, pubKey.VerifySignature(vesb1, vpb1.ExtensionSignature)) + + // We duplicate this vote precisely, including its timestamp, but change + // its extension + vote2 := vote1.Copy() + vote2.Extension = []byte("new extension") + vpb2 := vote2.ToProto() + + err = privVal.SignVote(ctx, "mychainid", vpb2) + assert.NoError(t, err, "expected no error signing same vote with manipulated vote extension") + + // We need to ensure that a valid new extension signature has been created + // that validates against the vote extension sign bytes with the new + // extension, and does not validate against the vote extension sign bytes + // with the old extension. + vesb2 := types.VoteExtensionSignBytes("mychainid", vpb2) + assert.True(t, pubKey.VerifySignature(vesb2, vpb2.ExtensionSignature)) + assert.False(t, pubKey.VerifySignature(vesb1, vpb2.ExtensionSignature)) + + // We now manipulate the timestamp of the vote with the extension, as per + // TestDifferByTimestamp + expectedTimestamp := vpb2.Timestamp + + vpb2.Timestamp = vpb2.Timestamp.Add(time.Millisecond) + vpb2.Signature = nil + vpb2.ExtensionSignature = nil + + err = privVal.SignVote(ctx, "mychainid", vpb2) + assert.NoError(t, err, "expected no error signing same vote with manipulated timestamp and vote extension") + assert.Equal(t, expectedTimestamp, vpb2.Timestamp) + + vesb3 := types.VoteExtensionSignBytes("mychainid", vpb2) + assert.True(t, pubKey.VerifySignature(vesb3, vpb2.ExtensionSignature)) + assert.False(t, pubKey.VerifySignature(vesb1, vpb2.ExtensionSignature)) +} + func newVote(addr types.Address, idx int32, height int64, round int32, - typ tmproto.SignedMsgType, blockID types.BlockID) *types.Vote { + typ tmproto.SignedMsgType, blockID types.BlockID, extension []byte) *types.Vote { return &types.Vote{ ValidatorAddress: addr, ValidatorIndex: idx, @@ -310,6 +347,7 @@ func newVote(addr types.Address, idx int32, height int64, round int32, Type: typ, Timestamp: tmtime.Now(), BlockID: blockID, + Extension: extension, } } @@ -321,3 +359,15 @@ func newProposal(height int64, round int32, blockID types.BlockID, t time.Time) Timestamp: t, } } + +func newTestFilePV(t *testing.T) (*FilePV, string, string) { + tempKeyFile, err := os.CreateTemp(t.TempDir(), "priv_validator_key_") + require.NoError(t, err) + tempStateFile, err := os.CreateTemp(t.TempDir(), "priv_validator_state_") + require.NoError(t, err) + + privVal, err := GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), "") + require.NoError(t, err) + + return privVal, tempKeyFile.Name(), tempStateFile.Name() +} diff --git a/privval/msgs_test.go b/privval/msgs_test.go index bbd3f6319..20e73762c 100644 --- a/privval/msgs_test.go +++ b/privval/msgs_test.go @@ -22,23 +22,14 @@ var stamp = time.Date(2019, 10, 13, 16, 14, 44, 0, time.UTC) func exampleVote() *types.Vote { return &types.Vote{ - Type: tmproto.SignedMsgType(1), - Height: 3, - Round: 2, - Timestamp: stamp, - BlockID: types.BlockID{ - Hash: tmhash.Sum([]byte("blockID_hash")), - PartSetHeader: types.PartSetHeader{ - Total: 1000000, - Hash: tmhash.Sum([]byte("blockID_part_set_header_hash")), - }, - }, + Type: tmproto.PrecommitType, + Height: 3, + Round: 2, + BlockID: types.BlockID{Hash: tmhash.Sum([]byte("blockID_hash")), PartSetHeader: types.PartSetHeader{Total: 1000000, Hash: tmhash.Sum([]byte("blockID_part_set_header_hash"))}}, + Timestamp: stamp, ValidatorAddress: crypto.AddressHash([]byte("validator_address")), ValidatorIndex: 56789, - VoteExtension: types.VoteExtension{ - AppDataToSign: []byte("app_data_signed"), - AppDataSelfAuthenticating: []byte("app_data_self_authenticating"), - }, + Extension: []byte("extension"), } } @@ -87,8 +78,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}, "1a81010a7f080210031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0608f49a8ded0532146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb034a09657874656e73696f6e"}, + {"Vote Response", &privproto.SignedVoteResponse{Vote: *votepb, Error: nil}, "2281010a7f080210031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0608f49a8ded0532146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb034a09657874656e73696f6e"}, {"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/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index f9fc73b48..be13be433 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -384,7 +384,10 @@ message CommitInfo { } message ExtendedCommitInfo { - int32 round = 1; + // The round at which the block proposer decided in the previous height. + int32 round = 1; + // List of validators' addresses in the last validator set with their voting + // information, including vote extensions. repeated ExtendedVoteInfo votes = 2 [(gogoproto.nullable) = false]; } @@ -465,19 +468,12 @@ message VoteInfo { // ExtendedVoteInfo message ExtendedVoteInfo { - Validator validator = 1 [(gogoproto.nullable) = false]; - bool signed_last_block = 2; - bytes vote_extension = 3; -} - -// CanonicalVoteExtension -// TODO: move this to core Tendermint data structures -message CanonicalVoteExtension { - bytes extension = 1; - int64 height = 2; - int32 round = 3; - string chain_id = 4; - bytes address = 5; + // The validator that sent the vote. + Validator validator = 1 [(gogoproto.nullable) = false]; + // Indicates whether the validator signed the last block, allowing for rewards based on validator availability. + bool signed_last_block = 2; + // Non-deterministic extension provided by the sending validator's application. + bytes vote_extension = 3; } diff --git a/proto/tendermint/abci/types.proto.intermediate b/proto/tendermint/abci/types.proto.intermediate index c752cd87b..d4ed656f4 100644 --- a/proto/tendermint/abci/types.proto.intermediate +++ b/proto/tendermint/abci/types.proto.intermediate @@ -153,12 +153,16 @@ message RequestProcessProposal { // Extends a vote with application-side injection message RequestExtendVote { - types.Vote vote = 1; + bytes hash = 1; + int64 height = 2; } // Verify the vote extension message RequestVerifyVoteExtension { - types.Vote vote = 1; + bytes hash = 1; + bytes validator_address = 2; + int64 height = 3; + bytes vote_extension = 4; } message RequestFinalizeBlock { @@ -348,7 +352,7 @@ message ResponseProcessProposal { } message ResponseExtendVote { - tendermint.types.VoteExtension vote_extension = 1; + bytes vote_extension = 1; } message ResponseVerifyVoteExtension { @@ -379,8 +383,14 @@ message CommitInfo { repeated VoteInfo votes = 2 [(gogoproto.nullable) = false]; } +// ExtendedCommitInfo is similar to CommitInfo except that it is only used in +// the PrepareProposal request such that Tendermint can provide vote extensions +// to the application. message ExtendedCommitInfo { - int32 round = 1; + // The round at which the block proposer decided in the previous height. + int32 round = 1; + // List of validators' addresses in the last validator set with their voting + // information, including vote extensions. repeated ExtendedVoteInfo votes = 2 [(gogoproto.nullable) = false]; } @@ -461,10 +471,14 @@ message VoteInfo { reserved 4; // Placeholder for app_signed_extension in v0.37 } +// ExtendedVoteInfo message ExtendedVoteInfo { - Validator validator = 1 [(gogoproto.nullable) = false]; - bool signed_last_block = 2; - bytes vote_extension = 3; + // The validator that sent the vote. + Validator validator = 1 [(gogoproto.nullable) = false]; + // Indicates whether the validator signed the last block, allowing for rewards based on validator availability. + bool signed_last_block = 2; + // Non-deterministic extension provided by the sending validator's application. + bytes vote_extension = 3; } enum MisbehaviorType { diff --git a/proto/tendermint/types/canonical.pb.go b/proto/tendermint/types/canonical.pb.go index 0cd7386f7..50c0c84fa 100644 --- a/proto/tendermint/types/canonical.pb.go +++ b/proto/tendermint/types/canonical.pb.go @@ -225,13 +225,12 @@ func (m *CanonicalProposal) GetChainID() string { } type CanonicalVote struct { - Type SignedMsgType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.SignedMsgType" json:"type,omitempty"` - Height int64 `protobuf:"fixed64,2,opt,name=height,proto3" json:"height,omitempty"` - Round int64 `protobuf:"fixed64,3,opt,name=round,proto3" json:"round,omitempty"` - BlockID *CanonicalBlockID `protobuf:"bytes,4,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"` - Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"` - ChainID string `protobuf:"bytes,6,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - VoteExtension *VoteExtensionToSign `protobuf:"bytes,7,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` + Type SignedMsgType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.SignedMsgType" json:"type,omitempty"` + Height int64 `protobuf:"fixed64,2,opt,name=height,proto3" json:"height,omitempty"` + Round int64 `protobuf:"fixed64,3,opt,name=round,proto3" json:"round,omitempty"` + BlockID *CanonicalBlockID `protobuf:"bytes,4,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"` + Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"` + ChainID string `protobuf:"bytes,6,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` } func (m *CanonicalVote) Reset() { *m = CanonicalVote{} } @@ -309,57 +308,121 @@ func (m *CanonicalVote) GetChainID() string { return "" } -func (m *CanonicalVote) GetVoteExtension() *VoteExtensionToSign { +// CanonicalVoteExtension provides us a way to serialize a vote extension from +// a particular validator such that we can sign over those serialized bytes. +type CanonicalVoteExtension struct { + Extension []byte `protobuf:"bytes,1,opt,name=extension,proto3" json:"extension,omitempty"` + Height int64 `protobuf:"fixed64,2,opt,name=height,proto3" json:"height,omitempty"` + Round int64 `protobuf:"fixed64,3,opt,name=round,proto3" json:"round,omitempty"` + ChainId string `protobuf:"bytes,4,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` +} + +func (m *CanonicalVoteExtension) Reset() { *m = CanonicalVoteExtension{} } +func (m *CanonicalVoteExtension) String() string { return proto.CompactTextString(m) } +func (*CanonicalVoteExtension) ProtoMessage() {} +func (*CanonicalVoteExtension) Descriptor() ([]byte, []int) { + return fileDescriptor_8d1a1a84ff7267ed, []int{4} +} +func (m *CanonicalVoteExtension) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CanonicalVoteExtension) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CanonicalVoteExtension.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CanonicalVoteExtension) XXX_Merge(src proto.Message) { + xxx_messageInfo_CanonicalVoteExtension.Merge(m, src) +} +func (m *CanonicalVoteExtension) XXX_Size() int { + return m.Size() +} +func (m *CanonicalVoteExtension) XXX_DiscardUnknown() { + xxx_messageInfo_CanonicalVoteExtension.DiscardUnknown(m) +} + +var xxx_messageInfo_CanonicalVoteExtension proto.InternalMessageInfo + +func (m *CanonicalVoteExtension) GetExtension() []byte { if m != nil { - return m.VoteExtension + return m.Extension } return nil } +func (m *CanonicalVoteExtension) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *CanonicalVoteExtension) GetRound() int64 { + if m != nil { + return m.Round + } + return 0 +} + +func (m *CanonicalVoteExtension) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + func init() { proto.RegisterType((*CanonicalBlockID)(nil), "tendermint.types.CanonicalBlockID") proto.RegisterType((*CanonicalPartSetHeader)(nil), "tendermint.types.CanonicalPartSetHeader") proto.RegisterType((*CanonicalProposal)(nil), "tendermint.types.CanonicalProposal") proto.RegisterType((*CanonicalVote)(nil), "tendermint.types.CanonicalVote") + proto.RegisterType((*CanonicalVoteExtension)(nil), "tendermint.types.CanonicalVoteExtension") } func init() { proto.RegisterFile("tendermint/types/canonical.proto", fileDescriptor_8d1a1a84ff7267ed) } var fileDescriptor_8d1a1a84ff7267ed = []byte{ - // 522 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0x3f, 0x6f, 0xd3, 0x40, - 0x18, 0xc6, 0xe3, 0xd4, 0x49, 0x9c, 0x4b, 0x53, 0xc2, 0xa9, 0xaa, 0xac, 0x08, 0xd9, 0x96, 0x25, - 0x90, 0x59, 0x6c, 0x29, 0x1d, 0xd8, 0x5d, 0x90, 0x08, 0x2a, 0xa2, 0x5c, 0xa3, 0x0e, 0x2c, 0xd6, - 0xc5, 0x3e, 0x6c, 0x0b, 0xc7, 0x67, 0xd9, 0x97, 0x8a, 0x2e, 0x7c, 0x86, 0x7e, 0xac, 0x8e, 0x1d, - 0x61, 0x09, 0xc8, 0xf9, 0x12, 0x8c, 0xe8, 0xce, 0x49, 0x1c, 0x25, 0xc0, 0x02, 0xea, 0x12, 0xbd, - 0x7f, 0x1e, 0xbf, 0xef, 0xa3, 0xdf, 0xab, 0x1c, 0x30, 0x18, 0x49, 0x03, 0x92, 0xcf, 0xe2, 0x94, - 0x39, 0xec, 0x26, 0x23, 0x85, 0xe3, 0xe3, 0x94, 0xa6, 0xb1, 0x8f, 0x13, 0x3b, 0xcb, 0x29, 0xa3, - 0x70, 0x50, 0x2b, 0x6c, 0xa1, 0x18, 0x1e, 0x87, 0x34, 0xa4, 0xa2, 0xe9, 0xf0, 0xa8, 0xd2, 0x0d, - 0x9f, 0xec, 0x4d, 0x12, 0xbf, 0xab, 0xae, 0x1e, 0x52, 0x1a, 0x26, 0xc4, 0x11, 0xd9, 0x74, 0xfe, - 0xd1, 0x61, 0xf1, 0x8c, 0x14, 0x0c, 0xcf, 0xb2, 0x4a, 0x60, 0x7e, 0x01, 0x83, 0xb3, 0xf5, 0x66, - 0x37, 0xa1, 0xfe, 0xa7, 0xf1, 0x4b, 0x08, 0x81, 0x1c, 0xe1, 0x22, 0x52, 0x25, 0x43, 0xb2, 0x0e, - 0x91, 0x88, 0xe1, 0x15, 0x78, 0x94, 0xe1, 0x9c, 0x79, 0x05, 0x61, 0x5e, 0x44, 0x70, 0x40, 0x72, - 0xb5, 0x69, 0x48, 0x56, 0x6f, 0x64, 0xd9, 0xbb, 0x46, 0xed, 0xcd, 0xc0, 0x0b, 0x9c, 0xb3, 0x4b, - 0xc2, 0x5e, 0x0b, 0xbd, 0x2b, 0xdf, 0x2d, 0xf4, 0x06, 0xea, 0x67, 0xdb, 0x45, 0xd3, 0x05, 0x27, - 0xbf, 0x97, 0xc3, 0x63, 0xd0, 0x62, 0x94, 0xe1, 0x44, 0xd8, 0xe8, 0xa3, 0x2a, 0xd9, 0x78, 0x6b, - 0xd6, 0xde, 0xcc, 0x6f, 0x4d, 0xf0, 0xb8, 0x1e, 0x92, 0xd3, 0x8c, 0x16, 0x38, 0x81, 0xa7, 0x40, - 0xe6, 0x76, 0xc4, 0xe7, 0x47, 0x23, 0x7d, 0xdf, 0xe6, 0x65, 0x1c, 0xa6, 0x24, 0x78, 0x5b, 0x84, - 0x93, 0x9b, 0x8c, 0x20, 0x21, 0x86, 0x27, 0xa0, 0x1d, 0x91, 0x38, 0x8c, 0x98, 0x58, 0x30, 0x40, - 0xab, 0x8c, 0x9b, 0xc9, 0xe9, 0x3c, 0x0d, 0xd4, 0x03, 0x51, 0xae, 0x12, 0xf8, 0x1c, 0x74, 0x33, - 0x9a, 0x78, 0x55, 0x47, 0x36, 0x24, 0xeb, 0xc0, 0x3d, 0x2c, 0x17, 0xba, 0x72, 0xf1, 0xee, 0x1c, - 0xf1, 0x1a, 0x52, 0x32, 0x9a, 0x88, 0x08, 0xbe, 0x01, 0xca, 0x94, 0xe3, 0xf5, 0xe2, 0x40, 0x6d, - 0x09, 0x70, 0xe6, 0x5f, 0xc0, 0xad, 0x2e, 0xe1, 0xf6, 0xca, 0x85, 0xde, 0x59, 0x25, 0xa8, 0x23, - 0x06, 0x8c, 0x03, 0xe8, 0x82, 0xee, 0xe6, 0x8c, 0x6a, 0x5b, 0x0c, 0x1b, 0xda, 0xd5, 0xa1, 0xed, - 0xf5, 0xa1, 0xed, 0xc9, 0x5a, 0xe1, 0x2a, 0x9c, 0xfb, 0xed, 0x77, 0x5d, 0x42, 0xf5, 0x67, 0xf0, - 0x19, 0x50, 0xfc, 0x08, 0xc7, 0x29, 0xf7, 0xd3, 0x31, 0x24, 0xab, 0x5b, 0xed, 0x3a, 0xe3, 0x35, - 0xbe, 0x4b, 0x34, 0xc7, 0x81, 0xf9, 0xb3, 0x09, 0xfa, 0x1b, 0x5b, 0x57, 0x94, 0x91, 0x87, 0xe0, - 0xba, 0x0d, 0x4b, 0xfe, 0x9f, 0xb0, 0x5a, 0xff, 0x0e, 0xab, 0xfd, 0x67, 0x58, 0xf0, 0x1c, 0x1c, - 0x5d, 0x53, 0x46, 0x3c, 0xf2, 0x99, 0x91, 0xb4, 0x88, 0x69, 0x2a, 0xd0, 0xf6, 0x46, 0x4f, 0xf7, - 0xdd, 0x73, 0x94, 0xaf, 0xd6, 0xb2, 0x09, 0xe5, 0xcc, 0x50, 0xff, 0x7a, 0xbb, 0xe8, 0xbe, 0xbf, - 0x2b, 0x35, 0xe9, 0xbe, 0xd4, 0xa4, 0x1f, 0xa5, 0x26, 0xdd, 0x2e, 0xb5, 0xc6, 0xfd, 0x52, 0x6b, - 0x7c, 0x5d, 0x6a, 0x8d, 0x0f, 0x2f, 0xc2, 0x98, 0x45, 0xf3, 0xa9, 0xed, 0xd3, 0x99, 0xb3, 0xfd, - 0xf7, 0xaf, 0xc3, 0xea, 0x99, 0xd8, 0x7d, 0x1a, 0xa6, 0x6d, 0x51, 0x3f, 0xfd, 0x15, 0x00, 0x00, - 0xff, 0xff, 0x4e, 0x61, 0xcb, 0xc4, 0x7f, 0x04, 0x00, 0x00, + // 523 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0x8d, 0x53, 0x27, 0xb1, 0xb7, 0x0d, 0x84, 0x55, 0x55, 0x99, 0xa8, 0xb2, 0x2d, 0x1f, 0x90, + 0xb9, 0xd8, 0x52, 0x7b, 0xe0, 0xee, 0x82, 0x44, 0x10, 0x88, 0xe2, 0x56, 0x3d, 0x70, 0x89, 0x36, + 0xf6, 0x62, 0x5b, 0x38, 0xde, 0x95, 0xbd, 0x91, 0xe8, 0x05, 0x7e, 0xa1, 0xdf, 0xc1, 0x97, 0xf4, + 0xd8, 0x23, 0x5c, 0x02, 0x72, 0x7e, 0x04, 0xed, 0xda, 0xb1, 0xad, 0x16, 0x55, 0x42, 0x20, 0x2e, + 0xd1, 0xcc, 0x9b, 0xb7, 0x33, 0x4f, 0x6f, 0xe2, 0x01, 0x26, 0xc3, 0x59, 0x88, 0xf3, 0x65, 0x92, + 0x31, 0x97, 0x5d, 0x52, 0x5c, 0xb8, 0x01, 0xca, 0x48, 0x96, 0x04, 0x28, 0x75, 0x68, 0x4e, 0x18, + 0x81, 0x93, 0x96, 0xe1, 0x08, 0xc6, 0x74, 0x3f, 0x22, 0x11, 0x11, 0x45, 0x97, 0x47, 0x15, 0x6f, + 0x7a, 0x78, 0xa7, 0x93, 0xf8, 0xad, 0xab, 0x46, 0x44, 0x48, 0x94, 0x62, 0x57, 0x64, 0x8b, 0xd5, + 0x07, 0x97, 0x25, 0x4b, 0x5c, 0x30, 0xb4, 0xa4, 0x15, 0xc1, 0xfa, 0x0c, 0x26, 0x27, 0xdb, 0xc9, + 0x5e, 0x4a, 0x82, 0x8f, 0xb3, 0xe7, 0x10, 0x02, 0x39, 0x46, 0x45, 0xac, 0x49, 0xa6, 0x64, 0xef, + 0xf9, 0x22, 0x86, 0x17, 0xe0, 0x21, 0x45, 0x39, 0x9b, 0x17, 0x98, 0xcd, 0x63, 0x8c, 0x42, 0x9c, + 0x6b, 0x7d, 0x53, 0xb2, 0x77, 0x8f, 0x6c, 0xe7, 0xb6, 0x50, 0xa7, 0x69, 0x78, 0x8a, 0x72, 0x76, + 0x86, 0xd9, 0x4b, 0xc1, 0xf7, 0xe4, 0xeb, 0xb5, 0xd1, 0xf3, 0xc7, 0xb4, 0x0b, 0x5a, 0x1e, 0x38, + 0xf8, 0x3d, 0x1d, 0xee, 0x83, 0x01, 0x23, 0x0c, 0xa5, 0x42, 0xc6, 0xd8, 0xaf, 0x92, 0x46, 0x5b, + 0xbf, 0xd5, 0x66, 0x7d, 0xef, 0x83, 0x47, 0x6d, 0x93, 0x9c, 0x50, 0x52, 0xa0, 0x14, 0x1e, 0x03, + 0x99, 0xcb, 0x11, 0xcf, 0x1f, 0x1c, 0x19, 0x77, 0x65, 0x9e, 0x25, 0x51, 0x86, 0xc3, 0x37, 0x45, + 0x74, 0x7e, 0x49, 0xb1, 0x2f, 0xc8, 0xf0, 0x00, 0x0c, 0x63, 0x9c, 0x44, 0x31, 0x13, 0x03, 0x26, + 0x7e, 0x9d, 0x71, 0x31, 0x39, 0x59, 0x65, 0xa1, 0xb6, 0x23, 0xe0, 0x2a, 0x81, 0x4f, 0x81, 0x4a, + 0x49, 0x3a, 0xaf, 0x2a, 0xb2, 0x29, 0xd9, 0x3b, 0xde, 0x5e, 0xb9, 0x36, 0x94, 0xd3, 0xb7, 0xaf, + 0x7d, 0x8e, 0xf9, 0x0a, 0x25, 0xa9, 0x88, 0xe0, 0x2b, 0xa0, 0x2c, 0xb8, 0xbd, 0xf3, 0x24, 0xd4, + 0x06, 0xc2, 0x38, 0xeb, 0x1e, 0xe3, 0xea, 0x4d, 0x78, 0xbb, 0xe5, 0xda, 0x18, 0xd5, 0x89, 0x3f, + 0x12, 0x0d, 0x66, 0x21, 0xf4, 0x80, 0xda, 0xac, 0x51, 0x1b, 0x8a, 0x66, 0x53, 0xa7, 0x5a, 0xb4, + 0xb3, 0x5d, 0xb4, 0x73, 0xbe, 0x65, 0x78, 0x0a, 0xf7, 0xfd, 0xea, 0x87, 0x21, 0xf9, 0xed, 0x33, + 0xf8, 0x04, 0x28, 0x41, 0x8c, 0x92, 0x8c, 0xeb, 0x19, 0x99, 0x92, 0xad, 0x56, 0xb3, 0x4e, 0x38, + 0xc6, 0x67, 0x89, 0xe2, 0x2c, 0xb4, 0xbe, 0xf6, 0xc1, 0xb8, 0x91, 0x75, 0x41, 0x18, 0xfe, 0x1f, + 0xbe, 0x76, 0xcd, 0x92, 0xff, 0xa5, 0x59, 0x83, 0xbf, 0x37, 0x6b, 0x78, 0x8f, 0x59, 0x5f, 0x3a, + 0x7f, 0x66, 0xee, 0xd5, 0x8b, 0x4f, 0x0c, 0x67, 0x45, 0x42, 0x32, 0x78, 0x08, 0x54, 0xbc, 0x4d, + 0xea, 0xef, 0xaa, 0x05, 0xfe, 0xd0, 0x9d, 0xc7, 0x1d, 0x35, 0xdc, 0x1d, 0xb5, 0x11, 0xe0, 0xbd, + 0xbb, 0x2e, 0x75, 0xe9, 0xa6, 0xd4, 0xa5, 0x9f, 0xa5, 0x2e, 0x5d, 0x6d, 0xf4, 0xde, 0xcd, 0x46, + 0xef, 0x7d, 0xdb, 0xe8, 0xbd, 0xf7, 0xcf, 0xa2, 0x84, 0xc5, 0xab, 0x85, 0x13, 0x90, 0xa5, 0xdb, + 0xbd, 0x18, 0x6d, 0x58, 0x5d, 0x96, 0xdb, 0xd7, 0x64, 0x31, 0x14, 0xf8, 0xf1, 0xaf, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x2b, 0x89, 0x89, 0x5b, 0xb2, 0x04, 0x00, 0x00, } func (m *CanonicalBlockID) Marshal() (dAtA []byte, err error) { @@ -529,18 +592,6 @@ func (m *CanonicalVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.VoteExtension != nil { - { - size, err := m.VoteExtension.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCanonical(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x3a - } if len(m.ChainID) > 0 { i -= len(m.ChainID) copy(dAtA[i:], m.ChainID) @@ -548,12 +599,12 @@ func (m *CanonicalVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x32 } - n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err5 != nil { - return 0, err5 + n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err4 != nil { + return 0, err4 } - i -= n5 - i = encodeVarintCanonical(dAtA, i, uint64(n5)) + i -= n4 + i = encodeVarintCanonical(dAtA, i, uint64(n4)) i-- dAtA[i] = 0x2a if m.BlockID != nil { @@ -588,6 +639,55 @@ func (m *CanonicalVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *CanonicalVoteExtension) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CanonicalVoteExtension) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CanonicalVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintCanonical(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0x22 + } + if m.Round != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.Round)) + i-- + dAtA[i] = 0x19 + } + if m.Height != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(m.Height)) + i-- + dAtA[i] = 0x11 + } + if len(m.Extension) > 0 { + i -= len(m.Extension) + copy(dAtA[i:], m.Extension) + i = encodeVarintCanonical(dAtA, i, uint64(len(m.Extension))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintCanonical(dAtA []byte, offset int, v uint64) int { offset -= sovCanonical(v) base := offset @@ -686,8 +786,27 @@ func (m *CanonicalVote) Size() (n int) { if l > 0 { n += 1 + l + sovCanonical(uint64(l)) } - if m.VoteExtension != nil { - l = m.VoteExtension.Size() + return n +} + +func (m *CanonicalVoteExtension) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Extension) + if l > 0 { + n += 1 + l + sovCanonical(uint64(l)) + } + if m.Height != 0 { + n += 9 + } + if m.Round != 0 { + n += 9 + } + l = len(m.ChainId) + if l > 0 { n += 1 + l + sovCanonical(uint64(l)) } return n @@ -1297,11 +1416,61 @@ func (m *CanonicalVote) Unmarshal(dAtA []byte) error { } m.ChainID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) + default: + iNdEx = preIndex + skippy, err := skipCanonical(dAtA[iNdEx:]) + if err != nil { + return err } - var msglen int + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCanonical + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CanonicalVoteExtension) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCanonical + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CanonicalVoteExtension: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CanonicalVoteExtension: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Extension", wireType) + } + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowCanonical @@ -1311,27 +1480,77 @@ func (m *CanonicalVote) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthCanonical } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthCanonical } if postIndex > l { return io.ErrUnexpectedEOF } - if m.VoteExtension == nil { - m.VoteExtension = &VoteExtensionToSign{} + m.Extension = append(m.Extension[:0], dAtA[iNdEx:postIndex]...) + if m.Extension == nil { + m.Extension = []byte{} } - if err := m.VoteExtension.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + iNdEx = postIndex + case 2: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) } + m.Height = 0 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + m.Height = int64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + case 3: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Round", wireType) + } + m.Round = 0 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + m.Round = int64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCanonical + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCanonical + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCanonical + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/proto/tendermint/types/canonical.proto b/proto/tendermint/types/canonical.proto index e88fd6ffe..e9ed1e55d 100644 --- a/proto/tendermint/types/canonical.proto +++ b/proto/tendermint/types/canonical.proto @@ -35,3 +35,12 @@ message CanonicalVote { google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; string chain_id = 6 [(gogoproto.customname) = "ChainID"]; } + +// CanonicalVoteExtension provides us a way to serialize a vote extension from +// a particular validator such that we can sign over those serialized bytes. +message CanonicalVoteExtension { + bytes extension = 1; + sfixed64 height = 2; + sfixed64 round = 3; + string chain_id = 4; +} diff --git a/proto/tendermint/types/types.pb.go b/proto/tendermint/types/types.pb.go index 5c1f99d23..370a3714e 100644 --- a/proto/tendermint/types/types.pb.go +++ b/proto/tendermint/types/types.pb.go @@ -466,15 +466,22 @@ func (m *Data) GetTxs() [][]byte { // Vote represents a prevote, precommit, or commit vote from validators for // consensus. type Vote struct { - Type SignedMsgType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.SignedMsgType" json:"type,omitempty"` - Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` - Round int32 `protobuf:"varint,3,opt,name=round,proto3" json:"round,omitempty"` - BlockID BlockID `protobuf:"bytes,4,opt,name=block_id,json=blockId,proto3" json:"block_id"` - Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"` - ValidatorAddress []byte `protobuf:"bytes,6,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` - ValidatorIndex int32 `protobuf:"varint,7,opt,name=validator_index,json=validatorIndex,proto3" json:"validator_index,omitempty"` - Signature []byte `protobuf:"bytes,8,opt,name=signature,proto3" json:"signature,omitempty"` - VoteExtension *VoteExtension `protobuf:"bytes,9,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` + Type SignedMsgType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.SignedMsgType" json:"type,omitempty"` + Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + Round int32 `protobuf:"varint,3,opt,name=round,proto3" json:"round,omitempty"` + BlockID BlockID `protobuf:"bytes,4,opt,name=block_id,json=blockId,proto3" json:"block_id"` + Timestamp time.Time `protobuf:"bytes,5,opt,name=timestamp,proto3,stdtime" json:"timestamp"` + ValidatorAddress []byte `protobuf:"bytes,6,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` + ValidatorIndex int32 `protobuf:"varint,7,opt,name=validator_index,json=validatorIndex,proto3" json:"validator_index,omitempty"` + // Vote signature by the validator if they participated in consensus for the + // associated block. + Signature []byte `protobuf:"bytes,8,opt,name=signature,proto3" json:"signature,omitempty"` + // Vote extension provided by the application. Only valid for precommit + // messages. + Extension []byte `protobuf:"bytes,9,opt,name=extension,proto3" json:"extension,omitempty"` + // Vote extension signature by the validator if they participated in + // consensus for the associated block. + ExtensionSignature []byte `protobuf:"bytes,10,opt,name=extension_signature,json=extensionSignature,proto3" json:"extension_signature,omitempty"` } func (m *Vote) Reset() { *m = Vote{} } @@ -566,108 +573,16 @@ func (m *Vote) GetSignature() []byte { return nil } -func (m *Vote) GetVoteExtension() *VoteExtension { +func (m *Vote) GetExtension() []byte { if m != nil { - return m.VoteExtension + return m.Extension } return nil } -// VoteExtension is app-defined additional information to the validator votes. -type VoteExtension struct { - AppDataToSign []byte `protobuf:"bytes,1,opt,name=app_data_to_sign,json=appDataToSign,proto3" json:"app_data_to_sign,omitempty"` - AppDataSelfAuthenticating []byte `protobuf:"bytes,2,opt,name=app_data_self_authenticating,json=appDataSelfAuthenticating,proto3" json:"app_data_self_authenticating,omitempty"` -} - -func (m *VoteExtension) Reset() { *m = VoteExtension{} } -func (m *VoteExtension) String() string { return proto.CompactTextString(m) } -func (*VoteExtension) ProtoMessage() {} -func (*VoteExtension) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{6} -} -func (m *VoteExtension) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *VoteExtension) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_VoteExtension.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *VoteExtension) XXX_Merge(src proto.Message) { - xxx_messageInfo_VoteExtension.Merge(m, src) -} -func (m *VoteExtension) XXX_Size() int { - return m.Size() -} -func (m *VoteExtension) XXX_DiscardUnknown() { - xxx_messageInfo_VoteExtension.DiscardUnknown(m) -} - -var xxx_messageInfo_VoteExtension proto.InternalMessageInfo - -func (m *VoteExtension) GetAppDataToSign() []byte { +func (m *Vote) GetExtensionSignature() []byte { if m != nil { - return m.AppDataToSign - } - return nil -} - -func (m *VoteExtension) GetAppDataSelfAuthenticating() []byte { - if m != nil { - return m.AppDataSelfAuthenticating - } - return nil -} - -// VoteExtensionToSign is a subset of VoteExtension that is signed by the validators private key. -// VoteExtensionToSign is extracted from an existing VoteExtension. -type VoteExtensionToSign struct { - AppDataToSign []byte `protobuf:"bytes,1,opt,name=app_data_to_sign,json=appDataToSign,proto3" json:"app_data_to_sign,omitempty"` -} - -func (m *VoteExtensionToSign) Reset() { *m = VoteExtensionToSign{} } -func (m *VoteExtensionToSign) String() string { return proto.CompactTextString(m) } -func (*VoteExtensionToSign) ProtoMessage() {} -func (*VoteExtensionToSign) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{7} -} -func (m *VoteExtensionToSign) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *VoteExtensionToSign) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_VoteExtensionToSign.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *VoteExtensionToSign) XXX_Merge(src proto.Message) { - xxx_messageInfo_VoteExtensionToSign.Merge(m, src) -} -func (m *VoteExtensionToSign) XXX_Size() int { - return m.Size() -} -func (m *VoteExtensionToSign) XXX_DiscardUnknown() { - xxx_messageInfo_VoteExtensionToSign.DiscardUnknown(m) -} - -var xxx_messageInfo_VoteExtensionToSign proto.InternalMessageInfo - -func (m *VoteExtensionToSign) GetAppDataToSign() []byte { - if m != nil { - return m.AppDataToSign + return m.ExtensionSignature } return nil } @@ -685,7 +600,7 @@ func (m *Commit) Reset() { *m = Commit{} } func (m *Commit) String() string { return proto.CompactTextString(m) } func (*Commit) ProtoMessage() {} func (*Commit) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{8} + return fileDescriptor_d3a6e55e2345de56, []int{6} } func (m *Commit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -744,18 +659,17 @@ func (m *Commit) GetSignatures() []CommitSig { // CommitSig is a part of the Vote included in a Commit. type CommitSig struct { - BlockIdFlag BlockIDFlag `protobuf:"varint,1,opt,name=block_id_flag,json=blockIdFlag,proto3,enum=tendermint.types.BlockIDFlag" json:"block_id_flag,omitempty"` - ValidatorAddress []byte `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` - Timestamp time.Time `protobuf:"bytes,3,opt,name=timestamp,proto3,stdtime" json:"timestamp"` - Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` - VoteExtension *VoteExtensionToSign `protobuf:"bytes,5,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` + BlockIdFlag BlockIDFlag `protobuf:"varint,1,opt,name=block_id_flag,json=blockIdFlag,proto3,enum=tendermint.types.BlockIDFlag" json:"block_id_flag,omitempty"` + ValidatorAddress []byte `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` + Timestamp time.Time `protobuf:"bytes,3,opt,name=timestamp,proto3,stdtime" json:"timestamp"` + Signature []byte `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` } func (m *CommitSig) Reset() { *m = CommitSig{} } func (m *CommitSig) String() string { return proto.CompactTextString(m) } func (*CommitSig) ProtoMessage() {} func (*CommitSig) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{9} + return fileDescriptor_d3a6e55e2345de56, []int{7} } func (m *CommitSig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -812,13 +726,6 @@ func (m *CommitSig) GetSignature() []byte { return nil } -func (m *CommitSig) GetVoteExtension() *VoteExtensionToSign { - if m != nil { - return m.VoteExtension - } - return nil -} - type Proposal struct { Type SignedMsgType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.types.SignedMsgType" json:"type,omitempty"` Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` @@ -833,7 +740,7 @@ func (m *Proposal) Reset() { *m = Proposal{} } func (m *Proposal) String() string { return proto.CompactTextString(m) } func (*Proposal) ProtoMessage() {} func (*Proposal) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{10} + return fileDescriptor_d3a6e55e2345de56, []int{8} } func (m *Proposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -920,7 +827,7 @@ func (m *SignedHeader) Reset() { *m = SignedHeader{} } func (m *SignedHeader) String() string { return proto.CompactTextString(m) } func (*SignedHeader) ProtoMessage() {} func (*SignedHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{11} + return fileDescriptor_d3a6e55e2345de56, []int{9} } func (m *SignedHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -972,7 +879,7 @@ func (m *LightBlock) Reset() { *m = LightBlock{} } func (m *LightBlock) String() string { return proto.CompactTextString(m) } func (*LightBlock) ProtoMessage() {} func (*LightBlock) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{12} + return fileDescriptor_d3a6e55e2345de56, []int{10} } func (m *LightBlock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1026,7 +933,7 @@ func (m *BlockMeta) Reset() { *m = BlockMeta{} } func (m *BlockMeta) String() string { return proto.CompactTextString(m) } func (*BlockMeta) ProtoMessage() {} func (*BlockMeta) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{13} + return fileDescriptor_d3a6e55e2345de56, []int{11} } func (m *BlockMeta) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1095,7 +1002,7 @@ func (m *TxProof) Reset() { *m = TxProof{} } func (m *TxProof) String() string { return proto.CompactTextString(m) } func (*TxProof) ProtoMessage() {} func (*TxProof) Descriptor() ([]byte, []int) { - return fileDescriptor_d3a6e55e2345de56, []int{14} + return fileDescriptor_d3a6e55e2345de56, []int{12} } func (m *TxProof) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1154,8 +1061,6 @@ func init() { proto.RegisterType((*Header)(nil), "tendermint.types.Header") proto.RegisterType((*Data)(nil), "tendermint.types.Data") proto.RegisterType((*Vote)(nil), "tendermint.types.Vote") - proto.RegisterType((*VoteExtension)(nil), "tendermint.types.VoteExtension") - proto.RegisterType((*VoteExtensionToSign)(nil), "tendermint.types.VoteExtensionToSign") proto.RegisterType((*Commit)(nil), "tendermint.types.Commit") proto.RegisterType((*CommitSig)(nil), "tendermint.types.CommitSig") proto.RegisterType((*Proposal)(nil), "tendermint.types.Proposal") @@ -1168,96 +1073,91 @@ func init() { func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) } var fileDescriptor_d3a6e55e2345de56 = []byte{ - // 1423 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x4f, 0x6f, 0xdb, 0x64, - 0x18, 0xaf, 0x13, 0xb7, 0x49, 0x9e, 0xc4, 0x6d, 0xfa, 0xd2, 0x6d, 0x69, 0xb6, 0xa6, 0x91, 0xd1, - 0x58, 0x37, 0x50, 0x3a, 0x3a, 0xc4, 0x9f, 0x03, 0xa0, 0x24, 0xcd, 0xb6, 0x68, 0x6d, 0x1a, 0x9c, - 0x6c, 0x08, 0x2e, 0x96, 0x93, 0xbc, 0x4d, 0xcc, 0x1c, 0xdb, 0xb2, 0xdf, 0x94, 0x76, 0x9f, 0x00, - 0xf5, 0xb4, 0x13, 0xb7, 0x9e, 0xe0, 0x80, 0xc4, 0x05, 0x89, 0x2f, 0x80, 0x38, 0xed, 0xb8, 0x1b, - 0x9c, 0x06, 0xea, 0x24, 0x3e, 0x07, 0x7a, 0xff, 0xc4, 0xb1, 0x9b, 0x86, 0x4d, 0xd5, 0xc4, 0x25, - 0xf2, 0xfb, 0x3c, 0xbf, 0xe7, 0xff, 0xcf, 0x8f, 0xdf, 0xc0, 0x35, 0x82, 0xed, 0x1e, 0xf6, 0x86, - 0xa6, 0x4d, 0x36, 0xc9, 0x91, 0x8b, 0x7d, 0xfe, 0x5b, 0x72, 0x3d, 0x87, 0x38, 0x28, 0x3b, 0xd1, - 0x96, 0x98, 0x3c, 0xbf, 0xd2, 0x77, 0xfa, 0x0e, 0x53, 0x6e, 0xd2, 0x27, 0x8e, 0xcb, 0xaf, 0xf7, - 0x1d, 0xa7, 0x6f, 0xe1, 0x4d, 0x76, 0xea, 0x8c, 0xf6, 0x37, 0x89, 0x39, 0xc4, 0x3e, 0x31, 0x86, - 0xae, 0x00, 0xac, 0x85, 0xc2, 0x74, 0xbd, 0x23, 0x97, 0x38, 0x14, 0xeb, 0xec, 0x0b, 0x75, 0x21, - 0xa4, 0x3e, 0xc0, 0x9e, 0x6f, 0x3a, 0x76, 0x38, 0x8f, 0x7c, 0x71, 0x2a, 0xcb, 0x03, 0xc3, 0x32, - 0x7b, 0x06, 0x71, 0x3c, 0x8e, 0x50, 0x3f, 0x01, 0xa5, 0x69, 0x78, 0xa4, 0x85, 0xc9, 0x7d, 0x6c, - 0xf4, 0xb0, 0x87, 0x56, 0x60, 0x9e, 0x38, 0xc4, 0xb0, 0x72, 0x52, 0x51, 0xda, 0x50, 0x34, 0x7e, - 0x40, 0x08, 0xe4, 0x81, 0xe1, 0x0f, 0x72, 0xb1, 0xa2, 0xb4, 0x91, 0xd1, 0xd8, 0xb3, 0x3a, 0x00, - 0x99, 0x9a, 0x52, 0x0b, 0xd3, 0xee, 0xe1, 0xc3, 0xb1, 0x05, 0x3b, 0x50, 0x69, 0xe7, 0x88, 0x60, - 0x5f, 0x98, 0xf0, 0x03, 0xfa, 0x00, 0xe6, 0x59, 0xfe, 0xb9, 0x78, 0x51, 0xda, 0x48, 0x6f, 0xe5, - 0x4a, 0xa1, 0x46, 0xf1, 0xfa, 0x4a, 0x4d, 0xaa, 0xaf, 0xc8, 0xcf, 0x5e, 0xac, 0xcf, 0x69, 0x1c, - 0xac, 0x5a, 0x90, 0xa8, 0x58, 0x4e, 0xf7, 0x71, 0x7d, 0x3b, 0x48, 0x44, 0x9a, 0x24, 0x82, 0x76, - 0x61, 0xc9, 0x35, 0x3c, 0xa2, 0xfb, 0x98, 0xe8, 0x03, 0x56, 0x05, 0x0b, 0x9a, 0xde, 0x5a, 0x2f, - 0x9d, 0x9d, 0x43, 0x29, 0x52, 0xac, 0x88, 0xa2, 0xb8, 0x61, 0xa1, 0xfa, 0x8f, 0x0c, 0x0b, 0xa2, - 0x19, 0x9f, 0x42, 0x42, 0xb4, 0x95, 0x05, 0x4c, 0x6f, 0xad, 0x85, 0x3d, 0x0a, 0x55, 0xa9, 0xea, - 0xd8, 0x3e, 0xb6, 0xfd, 0x91, 0x2f, 0xfc, 0x8d, 0x6d, 0xd0, 0x3b, 0x90, 0xec, 0x0e, 0x0c, 0xd3, - 0xd6, 0xcd, 0x1e, 0xcb, 0x28, 0x55, 0x49, 0x9f, 0xbe, 0x58, 0x4f, 0x54, 0xa9, 0xac, 0xbe, 0xad, - 0x25, 0x98, 0xb2, 0xde, 0x43, 0x97, 0x61, 0x61, 0x80, 0xcd, 0xfe, 0x80, 0xb0, 0xb6, 0xc4, 0x35, - 0x71, 0x42, 0x1f, 0x83, 0x4c, 0x09, 0x91, 0x93, 0x59, 0xec, 0x7c, 0x89, 0xb3, 0xa5, 0x34, 0x66, - 0x4b, 0xa9, 0x3d, 0x66, 0x4b, 0x25, 0x49, 0x03, 0x3f, 0xfd, 0x6b, 0x5d, 0xd2, 0x98, 0x05, 0xaa, - 0x82, 0x62, 0x19, 0x3e, 0xd1, 0x3b, 0xb4, 0x6d, 0x34, 0xfc, 0x3c, 0x73, 0xb1, 0x3a, 0xdd, 0x10, - 0xd1, 0x58, 0x91, 0x7a, 0x9a, 0x5a, 0x71, 0x51, 0x0f, 0x6d, 0x40, 0x96, 0x39, 0xe9, 0x3a, 0xc3, - 0xa1, 0x49, 0x74, 0xd6, 0xf7, 0x05, 0xd6, 0xf7, 0x45, 0x2a, 0xaf, 0x32, 0xf1, 0x7d, 0x3a, 0x81, - 0xab, 0x90, 0xea, 0x19, 0xc4, 0xe0, 0x90, 0x04, 0x83, 0x24, 0xa9, 0x80, 0x29, 0x6f, 0xc0, 0x52, - 0xc0, 0x3a, 0x9f, 0x43, 0x92, 0xdc, 0xcb, 0x44, 0xcc, 0x80, 0xb7, 0x61, 0xc5, 0xc6, 0x87, 0x44, - 0x3f, 0x8b, 0x4e, 0x31, 0x34, 0xa2, 0xba, 0x47, 0x51, 0x8b, 0xeb, 0xb0, 0xd8, 0x1d, 0x37, 0x9f, - 0x63, 0x81, 0x61, 0x95, 0x40, 0xca, 0x60, 0xab, 0x90, 0x34, 0x5c, 0x97, 0x03, 0xd2, 0x0c, 0x90, - 0x30, 0x5c, 0x97, 0xa9, 0x6e, 0xc1, 0x32, 0xab, 0xd1, 0xc3, 0xfe, 0xc8, 0x22, 0xc2, 0x49, 0x86, - 0x61, 0x96, 0xa8, 0x42, 0xe3, 0x72, 0x86, 0x7d, 0x1b, 0x14, 0x7c, 0x60, 0xf6, 0xb0, 0xdd, 0xc5, - 0x1c, 0xa7, 0x30, 0x5c, 0x66, 0x2c, 0x64, 0xa0, 0x9b, 0x90, 0x75, 0x3d, 0xc7, 0x75, 0x7c, 0xec, - 0xe9, 0x46, 0xaf, 0xe7, 0x61, 0xdf, 0xcf, 0x2d, 0x72, 0x7f, 0x63, 0x79, 0x99, 0x8b, 0xd5, 0x1c, - 0xc8, 0xdb, 0x06, 0x31, 0x50, 0x16, 0xe2, 0xe4, 0xd0, 0xcf, 0x49, 0xc5, 0xf8, 0x46, 0x46, 0xa3, - 0x8f, 0xea, 0x2f, 0x71, 0x90, 0x1f, 0x39, 0x04, 0xa3, 0x3b, 0x20, 0xd3, 0x31, 0x31, 0xf6, 0x2d, - 0x9e, 0xc7, 0xe7, 0x96, 0xd9, 0xb7, 0x71, 0x6f, 0xd7, 0xef, 0xb7, 0x8f, 0x5c, 0xac, 0x31, 0x70, - 0x88, 0x4e, 0xb1, 0x08, 0x9d, 0x56, 0x60, 0xde, 0x73, 0x46, 0x76, 0x8f, 0xb1, 0x6c, 0x5e, 0xe3, - 0x07, 0x54, 0x83, 0x64, 0xc0, 0x12, 0xf9, 0x55, 0x2c, 0x59, 0xa2, 0x2c, 0xa1, 0x1c, 0x16, 0x02, - 0x2d, 0xd1, 0x11, 0x64, 0xa9, 0x40, 0x2a, 0x58, 0x5e, 0x82, 0x6d, 0xaf, 0x47, 0xd8, 0x89, 0x19, - 0x7a, 0x17, 0x96, 0x83, 0xd9, 0x07, 0xcd, 0xe3, 0x8c, 0xcb, 0x06, 0x0a, 0xd1, 0xbd, 0x08, 0xad, - 0x74, 0xbe, 0x80, 0x12, 0xac, 0xae, 0x09, 0xad, 0xea, 0x6c, 0x13, 0x5d, 0x83, 0x94, 0x6f, 0xf6, - 0x6d, 0x83, 0x8c, 0x3c, 0x2c, 0x98, 0x37, 0x11, 0xa0, 0xbb, 0xb0, 0x78, 0xe0, 0x10, 0xac, 0xe3, - 0x43, 0x82, 0x6d, 0xf6, 0xa6, 0xa7, 0x66, 0xed, 0x0e, 0x3a, 0x91, 0xda, 0x18, 0xa6, 0x29, 0x07, - 0xe1, 0xa3, 0x7a, 0x04, 0x4a, 0x44, 0x8f, 0x6e, 0x40, 0x96, 0x92, 0x8e, 0xbd, 0x17, 0xc4, 0xd1, - 0x69, 0x44, 0xb1, 0xb5, 0x14, 0xc3, 0x75, 0xe9, 0xe0, 0xdb, 0x0e, 0x9d, 0x1e, 0xfa, 0x1c, 0xae, - 0x05, 0x40, 0x1f, 0x5b, 0xfb, 0xba, 0x31, 0x22, 0x03, 0x6c, 0x13, 0xb3, 0x6b, 0x10, 0xd3, 0xee, - 0x8b, 0x05, 0xba, 0x2a, 0x8c, 0x5a, 0xd8, 0xda, 0x2f, 0x47, 0x00, 0xea, 0x67, 0xf0, 0x56, 0x24, - 0xb4, 0xf0, 0xfb, 0xba, 0x09, 0xa8, 0xbf, 0x49, 0xb0, 0xc0, 0x5f, 0xe6, 0x10, 0x75, 0xa4, 0xf3, - 0xa9, 0x13, 0x9b, 0x45, 0x9d, 0xf8, 0xc5, 0xa9, 0x53, 0x06, 0x08, 0xe6, 0xe1, 0xe7, 0xe4, 0x62, - 0x7c, 0x23, 0xbd, 0x75, 0x75, 0xda, 0x11, 0x4f, 0xb1, 0x65, 0xf6, 0xc5, 0xae, 0x0a, 0x19, 0xa9, - 0x3f, 0xc7, 0x20, 0x15, 0xe8, 0x51, 0x19, 0x94, 0x71, 0x5e, 0xfa, 0xbe, 0x65, 0xf4, 0xc5, 0xeb, - 0xb3, 0x36, 0x33, 0xb9, 0xbb, 0x96, 0xd1, 0xd7, 0xd2, 0x22, 0x1f, 0x7a, 0x38, 0x9f, 0x8a, 0xb1, - 0x19, 0x54, 0x8c, 0x70, 0x3f, 0x7e, 0x31, 0xee, 0x47, 0x58, 0x2a, 0x9f, 0x65, 0xe9, 0xce, 0x14, - 0x4b, 0xf9, 0x2b, 0x76, 0xfd, 0x15, 0x2c, 0xe5, 0x13, 0x3e, 0xcb, 0xd5, 0x5f, 0x63, 0x90, 0x6c, - 0xb2, 0x65, 0x64, 0x58, 0xff, 0xc7, 0x8a, 0xb9, 0x0a, 0x29, 0xd7, 0xb1, 0x74, 0xae, 0x91, 0x99, - 0x26, 0xe9, 0x3a, 0x96, 0x36, 0x45, 0xa2, 0xf9, 0x37, 0xb4, 0x7f, 0x16, 0xde, 0xc0, 0x0c, 0x12, - 0x67, 0x66, 0xa0, 0x7a, 0x90, 0xe1, 0xad, 0x10, 0x97, 0x83, 0xdb, 0xb4, 0x07, 0xec, 0xb6, 0x21, - 0x4d, 0x5f, 0x66, 0x78, 0xda, 0x1c, 0xa9, 0x09, 0x1c, 0xb5, 0xe0, 0xdf, 0x52, 0x71, 0x3f, 0xc9, - 0xcd, 0x22, 0xb9, 0x26, 0x70, 0xea, 0xf7, 0x12, 0xc0, 0x0e, 0xed, 0x2c, 0xab, 0x97, 0x7e, 0xd6, - 0x7d, 0x96, 0x82, 0x1e, 0x89, 0x5c, 0x98, 0x35, 0x34, 0x11, 0x3f, 0xe3, 0x87, 0xf3, 0xae, 0x82, - 0x32, 0xa1, 0xb6, 0x8f, 0xc7, 0xc9, 0x9c, 0xe3, 0x24, 0xf8, 0xda, 0xb6, 0x30, 0xd1, 0x32, 0x07, - 0xa1, 0x93, 0xfa, 0xbb, 0x04, 0x29, 0x96, 0xd3, 0x2e, 0x26, 0x46, 0x64, 0x86, 0xd2, 0xc5, 0x67, - 0xb8, 0x06, 0xc0, 0xdd, 0xf8, 0xe6, 0x13, 0x2c, 0x98, 0x95, 0x62, 0x92, 0x96, 0xf9, 0x04, 0xa3, - 0x0f, 0x83, 0x86, 0xc7, 0xff, 0xbb, 0xe1, 0x62, 0x41, 0x8c, 0xdb, 0x7e, 0x05, 0x12, 0xf6, 0x68, - 0xa8, 0xd3, 0x6f, 0xac, 0xcc, 0xd9, 0x6a, 0x8f, 0x86, 0xed, 0x43, 0x5f, 0xfd, 0x06, 0x12, 0xed, - 0x43, 0x76, 0xdf, 0xa4, 0x14, 0xf5, 0x1c, 0x47, 0x5c, 0x72, 0xf8, 0x96, 0x4c, 0x52, 0x01, 0xfb, - 0xa6, 0x23, 0x90, 0xe9, 0x16, 0x1d, 0xdf, 0x7e, 0xe9, 0x33, 0x2a, 0xbd, 0xe6, 0x4d, 0x56, 0xdc, - 0x61, 0x6f, 0xfd, 0x21, 0x41, 0x3a, 0xb4, 0x6d, 0xd0, 0xfb, 0x70, 0xa9, 0xb2, 0xb3, 0x57, 0x7d, - 0xa0, 0xd7, 0xb7, 0xf5, 0xbb, 0x3b, 0xe5, 0x7b, 0xfa, 0xc3, 0xc6, 0x83, 0xc6, 0xde, 0x97, 0x8d, - 0xec, 0x5c, 0xfe, 0xf2, 0xf1, 0x49, 0x11, 0x85, 0xb0, 0x0f, 0xed, 0xc7, 0xb6, 0xf3, 0xad, 0x8d, - 0x36, 0x61, 0x25, 0x6a, 0x52, 0xae, 0xb4, 0x6a, 0x8d, 0x76, 0x56, 0xca, 0x5f, 0x3a, 0x3e, 0x29, - 0x2e, 0x87, 0x2c, 0xca, 0x1d, 0x1f, 0xdb, 0x64, 0xda, 0xa0, 0xba, 0xb7, 0xbb, 0x5b, 0x6f, 0x67, - 0x63, 0x53, 0x06, 0x62, 0xfd, 0xdf, 0x84, 0xe5, 0xa8, 0x41, 0xa3, 0xbe, 0x93, 0x8d, 0xe7, 0xd1, - 0xf1, 0x49, 0x71, 0x31, 0x84, 0x6e, 0x98, 0x56, 0x3e, 0xf9, 0xdd, 0x0f, 0x85, 0xb9, 0x9f, 0x7e, - 0x2c, 0x48, 0xb4, 0x32, 0x25, 0xb2, 0x23, 0xd0, 0x7b, 0x70, 0xa5, 0x55, 0xbf, 0xd7, 0xa8, 0x6d, - 0xeb, 0xbb, 0xad, 0x7b, 0x7a, 0xfb, 0xab, 0x66, 0x2d, 0x54, 0xdd, 0xd2, 0xf1, 0x49, 0x31, 0x2d, - 0x4a, 0x9a, 0x85, 0x6e, 0x6a, 0xb5, 0x47, 0x7b, 0xed, 0x5a, 0x56, 0xe2, 0xe8, 0xa6, 0x87, 0xe9, - 0x02, 0x63, 0xe8, 0xdb, 0xb0, 0x7a, 0x0e, 0x3a, 0x28, 0x6c, 0xf9, 0xf8, 0xa4, 0xa8, 0x34, 0x3d, - 0xcc, 0xdf, 0x1f, 0x66, 0x51, 0x82, 0xdc, 0xb4, 0xc5, 0x5e, 0x73, 0xaf, 0x55, 0xde, 0xc9, 0x16, - 0xf3, 0xd9, 0xe3, 0x93, 0x62, 0x66, 0xbc, 0x0c, 0x29, 0x7e, 0x52, 0x59, 0xe5, 0x8b, 0x67, 0xa7, - 0x05, 0xe9, 0xf9, 0x69, 0x41, 0xfa, 0xfb, 0xb4, 0x20, 0x3d, 0x7d, 0x59, 0x98, 0x7b, 0xfe, 0xb2, - 0x30, 0xf7, 0xe7, 0xcb, 0xc2, 0xdc, 0xd7, 0x1f, 0xf5, 0x4d, 0x32, 0x18, 0x75, 0x4a, 0x5d, 0x67, - 0xb8, 0x19, 0xfe, 0x8f, 0x35, 0x79, 0xe4, 0xff, 0xf5, 0xce, 0xfe, 0xff, 0xea, 0x2c, 0x30, 0xf9, - 0x9d, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x38, 0xfc, 0x14, 0xb1, 0x40, 0x0e, 0x00, 0x00, + // 1341 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcf, 0x73, 0xdb, 0xc4, + 0x17, 0x8f, 0x62, 0x25, 0xb6, 0x9f, 0xed, 0xc4, 0xd9, 0x6f, 0xda, 0xba, 0x6e, 0xe3, 0x68, 0xfc, + 0x1d, 0x20, 0x2d, 0x8c, 0x52, 0x52, 0x86, 0x1f, 0x07, 0x0e, 0xb6, 0x93, 0xb6, 0x9e, 0x26, 0x8e, + 0x91, 0xdd, 0x32, 0x70, 0xd1, 0xc8, 0xd6, 0xd6, 0x16, 0x95, 0x25, 0x8d, 0x76, 0x1d, 0x92, 0xfe, + 0x05, 0x4c, 0x4e, 0x3d, 0x71, 0xcb, 0x09, 0x0e, 0xdc, 0x39, 0x70, 0x65, 0x38, 0xf5, 0xd8, 0x1b, + 0x5c, 0x28, 0x4c, 0x3a, 0xc3, 0xdf, 0xc1, 0xec, 0x0f, 0xc9, 0x72, 0x9c, 0x40, 0xa7, 0xd3, 0xe1, + 0xe2, 0xd1, 0xbe, 0xf7, 0x79, 0x6f, 0xdf, 0x8f, 0xcf, 0xee, 0x5b, 0xc3, 0x75, 0x8a, 0x3d, 0x1b, + 0x87, 0x23, 0xc7, 0xa3, 0x9b, 0xf4, 0x28, 0xc0, 0x44, 0xfc, 0xea, 0x41, 0xe8, 0x53, 0x1f, 0x15, + 0x27, 0x5a, 0x9d, 0xcb, 0xcb, 0xab, 0x03, 0x7f, 0xe0, 0x73, 0xe5, 0x26, 0xfb, 0x12, 0xb8, 0xf2, + 0xfa, 0xc0, 0xf7, 0x07, 0x2e, 0xde, 0xe4, 0xab, 0xde, 0xf8, 0xd1, 0x26, 0x75, 0x46, 0x98, 0x50, + 0x6b, 0x14, 0x48, 0xc0, 0x5a, 0x62, 0x9b, 0x7e, 0x78, 0x14, 0x50, 0x9f, 0x61, 0xfd, 0x47, 0x52, + 0x5d, 0x49, 0xa8, 0x0f, 0x70, 0x48, 0x1c, 0xdf, 0x4b, 0xc6, 0x51, 0xd6, 0x66, 0xa2, 0x3c, 0xb0, + 0x5c, 0xc7, 0xb6, 0xa8, 0x1f, 0x0a, 0x44, 0xf5, 0x13, 0x28, 0xb4, 0xad, 0x90, 0x76, 0x30, 0xbd, + 0x87, 0x2d, 0x1b, 0x87, 0x68, 0x15, 0x16, 0xa8, 0x4f, 0x2d, 0xb7, 0xa4, 0x68, 0xca, 0x46, 0xc1, + 0x10, 0x0b, 0x84, 0x40, 0x1d, 0x5a, 0x64, 0x58, 0x9a, 0xd7, 0x94, 0x8d, 0xbc, 0xc1, 0xbf, 0xab, + 0x43, 0x50, 0x99, 0x29, 0xb3, 0x70, 0x3c, 0x1b, 0x1f, 0x46, 0x16, 0x7c, 0xc1, 0xa4, 0xbd, 0x23, + 0x8a, 0x89, 0x34, 0x11, 0x0b, 0xf4, 0x01, 0x2c, 0xf0, 0xf8, 0x4b, 0x29, 0x4d, 0xd9, 0xc8, 0x6d, + 0x95, 0xf4, 0x44, 0xa1, 0x44, 0x7e, 0x7a, 0x9b, 0xe9, 0xeb, 0xea, 0xb3, 0x17, 0xeb, 0x73, 0x86, + 0x00, 0x57, 0x5d, 0x48, 0xd7, 0x5d, 0xbf, 0xff, 0xb8, 0xb9, 0x1d, 0x07, 0xa2, 0x4c, 0x02, 0x41, + 0x7b, 0xb0, 0x1c, 0x58, 0x21, 0x35, 0x09, 0xa6, 0xe6, 0x90, 0x67, 0xc1, 0x37, 0xcd, 0x6d, 0xad, + 0xeb, 0x67, 0xfb, 0xa0, 0x4f, 0x25, 0x2b, 0x77, 0x29, 0x04, 0x49, 0x61, 0xf5, 0x2f, 0x15, 0x16, + 0x65, 0x31, 0x3e, 0x85, 0xb4, 0x2c, 0x2b, 0xdf, 0x30, 0xb7, 0xb5, 0x96, 0xf4, 0x28, 0x55, 0x7a, + 0xc3, 0xf7, 0x08, 0xf6, 0xc8, 0x98, 0x48, 0x7f, 0x91, 0x0d, 0x7a, 0x1b, 0x32, 0xfd, 0xa1, 0xe5, + 0x78, 0xa6, 0x63, 0xf3, 0x88, 0xb2, 0xf5, 0xdc, 0xe9, 0x8b, 0xf5, 0x74, 0x83, 0xc9, 0x9a, 0xdb, + 0x46, 0x9a, 0x2b, 0x9b, 0x36, 0xba, 0x0c, 0x8b, 0x43, 0xec, 0x0c, 0x86, 0x94, 0x97, 0x25, 0x65, + 0xc8, 0x15, 0xfa, 0x18, 0x54, 0x46, 0x88, 0x92, 0xca, 0xf7, 0x2e, 0xeb, 0x82, 0x2d, 0x7a, 0xc4, + 0x16, 0xbd, 0x1b, 0xb1, 0xa5, 0x9e, 0x61, 0x1b, 0x3f, 0xfd, 0x63, 0x5d, 0x31, 0xb8, 0x05, 0x6a, + 0x40, 0xc1, 0xb5, 0x08, 0x35, 0x7b, 0xac, 0x6c, 0x6c, 0xfb, 0x05, 0xee, 0xe2, 0xea, 0x6c, 0x41, + 0x64, 0x61, 0x65, 0xe8, 0x39, 0x66, 0x25, 0x44, 0x36, 0xda, 0x80, 0x22, 0x77, 0xd2, 0xf7, 0x47, + 0x23, 0x87, 0x9a, 0xbc, 0xee, 0x8b, 0xbc, 0xee, 0x4b, 0x4c, 0xde, 0xe0, 0xe2, 0x7b, 0xac, 0x03, + 0xd7, 0x20, 0x6b, 0x5b, 0xd4, 0x12, 0x90, 0x34, 0x87, 0x64, 0x98, 0x80, 0x2b, 0xdf, 0x81, 0xe5, + 0x98, 0x75, 0x44, 0x40, 0x32, 0xc2, 0xcb, 0x44, 0xcc, 0x81, 0xb7, 0x60, 0xd5, 0xc3, 0x87, 0xd4, + 0x3c, 0x8b, 0xce, 0x72, 0x34, 0x62, 0xba, 0x87, 0xd3, 0x16, 0x6f, 0xc1, 0x52, 0x3f, 0x2a, 0xbe, + 0xc0, 0x02, 0xc7, 0x16, 0x62, 0x29, 0x87, 0x5d, 0x85, 0x8c, 0x15, 0x04, 0x02, 0x90, 0xe3, 0x80, + 0xb4, 0x15, 0x04, 0x5c, 0x75, 0x13, 0x56, 0x78, 0x8e, 0x21, 0x26, 0x63, 0x97, 0x4a, 0x27, 0x79, + 0x8e, 0x59, 0x66, 0x0a, 0x43, 0xc8, 0x39, 0xf6, 0xff, 0x50, 0xc0, 0x07, 0x8e, 0x8d, 0xbd, 0x3e, + 0x16, 0xb8, 0x02, 0xc7, 0xe5, 0x23, 0x21, 0x07, 0xdd, 0x80, 0x62, 0x10, 0xfa, 0x81, 0x4f, 0x70, + 0x68, 0x5a, 0xb6, 0x1d, 0x62, 0x42, 0x4a, 0x4b, 0xc2, 0x5f, 0x24, 0xaf, 0x09, 0x71, 0xb5, 0x04, + 0xea, 0xb6, 0x45, 0x2d, 0x54, 0x84, 0x14, 0x3d, 0x24, 0x25, 0x45, 0x4b, 0x6d, 0xe4, 0x0d, 0xf6, + 0x59, 0xfd, 0x29, 0x05, 0xea, 0x43, 0x9f, 0x62, 0x74, 0x1b, 0x54, 0xd6, 0x26, 0xce, 0xbe, 0xa5, + 0xf3, 0xf8, 0xdc, 0x71, 0x06, 0x1e, 0xb6, 0xf7, 0xc8, 0xa0, 0x7b, 0x14, 0x60, 0x83, 0x83, 0x13, + 0x74, 0x9a, 0x9f, 0xa2, 0xd3, 0x2a, 0x2c, 0x84, 0xfe, 0xd8, 0xb3, 0x39, 0xcb, 0x16, 0x0c, 0xb1, + 0x40, 0x3b, 0x90, 0x89, 0x59, 0xa2, 0xfe, 0x1b, 0x4b, 0x96, 0x19, 0x4b, 0x18, 0x87, 0xa5, 0xc0, + 0x48, 0xf7, 0x24, 0x59, 0xea, 0x90, 0x8d, 0x2f, 0x2f, 0xc9, 0xb6, 0x57, 0x23, 0xec, 0xc4, 0x0c, + 0xbd, 0x0b, 0x2b, 0x71, 0xef, 0xe3, 0xe2, 0x09, 0xc6, 0x15, 0x63, 0x85, 0xac, 0xde, 0x14, 0xad, + 0x4c, 0x71, 0x01, 0xa5, 0x79, 0x5e, 0x13, 0x5a, 0x35, 0xf9, 0x4d, 0x74, 0x1d, 0xb2, 0xc4, 0x19, + 0x78, 0x16, 0x1d, 0x87, 0x58, 0x32, 0x6f, 0x22, 0x60, 0x5a, 0x7c, 0x48, 0xb1, 0xc7, 0x0f, 0xb9, + 0x60, 0xda, 0x44, 0x80, 0x36, 0xe1, 0x7f, 0xf1, 0xc2, 0x9c, 0x78, 0x11, 0x2c, 0x43, 0xb1, 0xaa, + 0x13, 0x69, 0xaa, 0x3f, 0x2b, 0xb0, 0x28, 0x0e, 0x46, 0xa2, 0x0d, 0xca, 0xf9, 0x6d, 0x98, 0xbf, + 0xa8, 0x0d, 0xa9, 0xd7, 0x6f, 0x43, 0x0d, 0x20, 0x0e, 0x93, 0x94, 0x54, 0x2d, 0xb5, 0x91, 0xdb, + 0xba, 0x36, 0xeb, 0x48, 0x84, 0xd8, 0x71, 0x06, 0xf2, 0xdc, 0x27, 0x8c, 0xaa, 0xbf, 0x2b, 0x90, + 0x8d, 0xf5, 0xa8, 0x06, 0x85, 0x28, 0x2e, 0xf3, 0x91, 0x6b, 0x0d, 0x24, 0x15, 0xd7, 0x2e, 0x0c, + 0xee, 0x8e, 0x6b, 0x0d, 0x8c, 0x9c, 0x8c, 0x87, 0x2d, 0xce, 0x6f, 0xeb, 0xfc, 0x05, 0x6d, 0x9d, + 0xe2, 0x51, 0xea, 0xf5, 0x78, 0x34, 0xd5, 0x71, 0xf5, 0x4c, 0xc7, 0xab, 0x3f, 0xce, 0x43, 0xa6, + 0xcd, 0x8f, 0xa2, 0xe5, 0xfe, 0x17, 0x07, 0xec, 0x1a, 0x64, 0x03, 0xdf, 0x35, 0x85, 0x46, 0xe5, + 0x9a, 0x4c, 0xe0, 0xbb, 0xc6, 0x4c, 0xdb, 0x17, 0xde, 0xd0, 0xe9, 0x5b, 0x7c, 0x03, 0x55, 0x4b, + 0x9f, 0xad, 0x5a, 0x08, 0x79, 0x51, 0x0a, 0x39, 0x1a, 0x6f, 0xb1, 0x1a, 0xf0, 0x59, 0xab, 0xcc, + 0x8e, 0x72, 0x11, 0xb6, 0x40, 0x1a, 0x12, 0xc7, 0x2c, 0xc4, 0x24, 0x91, 0xd3, 0xb9, 0x74, 0x11, + 0x2d, 0x0d, 0x89, 0xab, 0x7e, 0xab, 0x00, 0xec, 0xb2, 0xca, 0xf2, 0x7c, 0xd9, 0x50, 0x23, 0x3c, + 0x04, 0x73, 0x6a, 0xe7, 0xca, 0x45, 0x4d, 0x93, 0xfb, 0xe7, 0x49, 0x32, 0xee, 0x06, 0x14, 0x26, + 0x64, 0x24, 0x38, 0x0a, 0xe6, 0x1c, 0x27, 0xf1, 0xac, 0xe9, 0x60, 0x6a, 0xe4, 0x0f, 0x12, 0xab, + 0xea, 0x2f, 0x0a, 0x64, 0x79, 0x4c, 0x7b, 0x98, 0x5a, 0x53, 0x3d, 0x54, 0x5e, 0xbf, 0x87, 0x6b, + 0x00, 0xc2, 0x0d, 0x71, 0x9e, 0x60, 0xc9, 0xac, 0x2c, 0x97, 0x74, 0x9c, 0x27, 0x18, 0x7d, 0x18, + 0x17, 0x3c, 0xf5, 0xcf, 0x05, 0x97, 0x47, 0x3a, 0x2a, 0xfb, 0x15, 0x48, 0x7b, 0xe3, 0x91, 0xc9, + 0x26, 0x8c, 0x2a, 0xd8, 0xea, 0x8d, 0x47, 0xdd, 0x43, 0x52, 0xfd, 0x0a, 0xd2, 0xdd, 0x43, 0xfe, + 0xda, 0x62, 0x14, 0x0d, 0x7d, 0x5f, 0x8e, 0x78, 0xf1, 0xb4, 0xca, 0x30, 0x01, 0x9f, 0x68, 0x08, + 0x54, 0x36, 0xcb, 0xa3, 0xb7, 0x1f, 0xfb, 0x46, 0xfa, 0x2b, 0xbe, 0xe3, 0xe4, 0x0b, 0xee, 0xe6, + 0xaf, 0x0a, 0xe4, 0x12, 0xf7, 0x03, 0x7a, 0x1f, 0x2e, 0xd5, 0x77, 0xf7, 0x1b, 0xf7, 0xcd, 0xe6, + 0xb6, 0x79, 0x67, 0xb7, 0x76, 0xd7, 0x7c, 0xd0, 0xba, 0xdf, 0xda, 0xff, 0xbc, 0x55, 0x9c, 0x2b, + 0x5f, 0x3e, 0x3e, 0xd1, 0x50, 0x02, 0xfb, 0xc0, 0x7b, 0xec, 0xf9, 0x5f, 0xb3, 0xab, 0x78, 0x75, + 0xda, 0xa4, 0x56, 0xef, 0xec, 0xb4, 0xba, 0x45, 0xa5, 0x7c, 0xe9, 0xf8, 0x44, 0x5b, 0x49, 0x58, + 0xd4, 0x7a, 0x04, 0x7b, 0x74, 0xd6, 0xa0, 0xb1, 0xbf, 0xb7, 0xd7, 0xec, 0x16, 0xe7, 0x67, 0x0c, + 0xe4, 0x85, 0x7d, 0x03, 0x56, 0xa6, 0x0d, 0x5a, 0xcd, 0xdd, 0x62, 0xaa, 0x8c, 0x8e, 0x4f, 0xb4, + 0xa5, 0x04, 0xba, 0xe5, 0xb8, 0xe5, 0xcc, 0x37, 0xdf, 0x55, 0xe6, 0x7e, 0xf8, 0xbe, 0xa2, 0xb0, + 0xcc, 0x0a, 0x53, 0x77, 0x04, 0x7a, 0x0f, 0xae, 0x74, 0x9a, 0x77, 0x5b, 0x3b, 0xdb, 0xe6, 0x5e, + 0xe7, 0xae, 0xd9, 0xfd, 0xa2, 0xbd, 0x93, 0xc8, 0x6e, 0xf9, 0xf8, 0x44, 0xcb, 0xc9, 0x94, 0x2e, + 0x42, 0xb7, 0x8d, 0x9d, 0x87, 0xfb, 0xdd, 0x9d, 0xa2, 0x22, 0xd0, 0xed, 0x10, 0x1f, 0xf8, 0x14, + 0x73, 0xf4, 0x2d, 0xb8, 0x7a, 0x0e, 0x3a, 0x4e, 0x6c, 0xe5, 0xf8, 0x44, 0x2b, 0xb4, 0x43, 0x2c, + 0xce, 0x0f, 0xb7, 0xd0, 0xa1, 0x34, 0x6b, 0xb1, 0xdf, 0xde, 0xef, 0xd4, 0x76, 0x8b, 0x5a, 0xb9, + 0x78, 0x7c, 0xa2, 0xe5, 0xa3, 0xcb, 0x90, 0xe1, 0x27, 0x99, 0xd5, 0x3f, 0x7b, 0x76, 0x5a, 0x51, + 0x9e, 0x9f, 0x56, 0x94, 0x3f, 0x4f, 0x2b, 0xca, 0xd3, 0x97, 0x95, 0xb9, 0xe7, 0x2f, 0x2b, 0x73, + 0xbf, 0xbd, 0xac, 0xcc, 0x7d, 0xf9, 0xd1, 0xc0, 0xa1, 0xc3, 0x71, 0x4f, 0xef, 0xfb, 0xa3, 0xcd, + 0xe4, 0x3f, 0x8c, 0xc9, 0xa7, 0xf8, 0xa7, 0x73, 0xf6, 0xdf, 0x47, 0x6f, 0x91, 0xcb, 0x6f, 0xff, + 0x1d, 0x00, 0x00, 0xff, 0xff, 0xbb, 0xc0, 0x81, 0x37, 0x3e, 0x0d, 0x00, 0x00, } func (m *PartSetHeader) Marshal() (dAtA []byte, err error) { @@ -1558,15 +1458,17 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.VoteExtension != nil { - { - size, err := m.VoteExtension.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } + if len(m.ExtensionSignature) > 0 { + i -= len(m.ExtensionSignature) + copy(dAtA[i:], m.ExtensionSignature) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ExtensionSignature))) + i-- + dAtA[i] = 0x52 + } + if len(m.Extension) > 0 { + i -= len(m.Extension) + copy(dAtA[i:], m.Extension) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Extension))) i-- dAtA[i] = 0x4a } @@ -1589,12 +1491,12 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x32 } - n7, err7 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err7 != nil { - return 0, err7 + n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err6 != nil { + return 0, err6 } - i -= n7 - i = encodeVarintTypes(dAtA, i, uint64(n7)) + i -= n6 + i = encodeVarintTypes(dAtA, i, uint64(n6)) i-- dAtA[i] = 0x2a { @@ -1625,73 +1527,6 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *VoteExtension) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *VoteExtension) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *VoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AppDataSelfAuthenticating) > 0 { - i -= len(m.AppDataSelfAuthenticating) - copy(dAtA[i:], m.AppDataSelfAuthenticating) - i = encodeVarintTypes(dAtA, i, uint64(len(m.AppDataSelfAuthenticating))) - i-- - dAtA[i] = 0x12 - } - if len(m.AppDataToSign) > 0 { - i -= len(m.AppDataToSign) - copy(dAtA[i:], m.AppDataToSign) - i = encodeVarintTypes(dAtA, i, uint64(len(m.AppDataToSign))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *VoteExtensionToSign) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *VoteExtensionToSign) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *VoteExtensionToSign) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.AppDataToSign) > 0 { - i -= len(m.AppDataToSign) - copy(dAtA[i:], m.AppDataToSign) - i = encodeVarintTypes(dAtA, i, uint64(len(m.AppDataToSign))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func (m *Commit) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1769,18 +1604,6 @@ func (m *CommitSig) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.VoteExtension != nil { - { - size, err := m.VoteExtension.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - } if len(m.Signature) > 0 { i -= len(m.Signature) copy(dAtA[i:], m.Signature) @@ -1788,12 +1611,12 @@ func (m *CommitSig) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x22 } - n11, err11 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err11 != nil { - return 0, err11 + n9, err9 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err9 != nil { + return 0, err9 } - i -= n11 - i = encodeVarintTypes(dAtA, i, uint64(n11)) + i -= n9 + i = encodeVarintTypes(dAtA, i, uint64(n9)) i-- dAtA[i] = 0x1a if len(m.ValidatorAddress) > 0 { @@ -1838,12 +1661,12 @@ func (m *Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x3a } - n12, err12 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) - if err12 != nil { - return 0, err12 + n10, err10 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timestamp):]) + if err10 != nil { + return 0, err10 } - i -= n12 - i = encodeVarintTypes(dAtA, i, uint64(n12)) + i -= n10 + i = encodeVarintTypes(dAtA, i, uint64(n10)) i-- dAtA[i] = 0x32 { @@ -2238,37 +2061,11 @@ func (m *Vote) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if m.VoteExtension != nil { - l = m.VoteExtension.Size() - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - -func (m *VoteExtension) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.AppDataToSign) + l = len(m.Extension) if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - l = len(m.AppDataSelfAuthenticating) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - -func (m *VoteExtensionToSign) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.AppDataToSign) + l = len(m.ExtensionSignature) if l > 0 { n += 1 + l + sovTypes(uint64(l)) } @@ -2317,10 +2114,6 @@ func (m *CommitSig) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if m.VoteExtension != nil { - l = m.VoteExtension.Size() - n += 1 + l + sovTypes(uint64(l)) - } return n } @@ -3618,93 +3411,7 @@ func (m *Vote) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 9: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.VoteExtension == nil { - m.VoteExtension = &VoteExtension{} - } - if err := m.VoteExtension.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *VoteExtension) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: VoteExtension: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: VoteExtension: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AppDataToSign", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Extension", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -3731,14 +3438,14 @@ func (m *VoteExtension) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.AppDataToSign = append(m.AppDataToSign[:0], dAtA[iNdEx:postIndex]...) - if m.AppDataToSign == nil { - m.AppDataToSign = []byte{} + m.Extension = append(m.Extension[:0], dAtA[iNdEx:postIndex]...) + if m.Extension == nil { + m.Extension = []byte{} } iNdEx = postIndex - case 2: + case 10: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AppDataSelfAuthenticating", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExtensionSignature", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -3765,93 +3472,9 @@ func (m *VoteExtension) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.AppDataSelfAuthenticating = append(m.AppDataSelfAuthenticating[:0], dAtA[iNdEx:postIndex]...) - if m.AppDataSelfAuthenticating == nil { - m.AppDataSelfAuthenticating = []byte{} - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *VoteExtensionToSign) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: VoteExtensionToSign: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: VoteExtensionToSign: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AppDataToSign", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AppDataToSign = append(m.AppDataToSign[:0], dAtA[iNdEx:postIndex]...) - if m.AppDataToSign == nil { - m.AppDataToSign = []byte{} + m.ExtensionSignature = append(m.ExtensionSignature[:0], dAtA[iNdEx:postIndex]...) + if m.ExtensionSignature == nil { + m.ExtensionSignature = []byte{} } iNdEx = postIndex default: @@ -4179,42 +3802,6 @@ func (m *CommitSig) Unmarshal(dAtA []byte) error { m.Signature = []byte{} } iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.VoteExtension == nil { - m.VoteExtension = &VoteExtensionToSign{} - } - if err := m.VoteExtension.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/proto/tendermint/types/types.proto b/proto/tendermint/types/types.proto index bc2c53196..34013b418 100644 --- a/proto/tendermint/types/types.proto +++ b/proto/tendermint/types/types.proto @@ -112,7 +112,15 @@ message Vote { [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; bytes validator_address = 6; int32 validator_index = 7; - bytes signature = 8; + // Vote signature by the validator if they participated in consensus for the + // associated block. + bytes signature = 8; + // Vote extension provided by the application. Only valid for precommit + // messages. + bytes extension = 9; + // Vote extension signature by the validator if they participated in + // consensus for the associated block. + bytes extension_signature = 10; } // Commit contains the evidence that a block was committed by a set of diff --git a/rpc/client/eventstream/eventstream.go b/rpc/client/eventstream/eventstream.go index 887e723ce..59cfc8b5f 100644 --- a/rpc/client/eventstream/eventstream.go +++ b/rpc/client/eventstream/eventstream.go @@ -189,6 +189,5 @@ type MissedItemsError struct { // Error satisfies the error interface. func (e *MissedItemsError) Error() string { - return fmt.Sprintf("missed events matching %q between %q and %q", - e.Query, e.NewestSeen, e.OldestPresent) + return fmt.Sprintf("missed events matching %q between %q and %q", e.Query, e.NewestSeen, e.OldestPresent) } diff --git a/rpc/client/http/http.go b/rpc/client/http/http.go index 2a9507f8e..435f80a5c 100644 --- a/rpc/client/http/http.go +++ b/rpc/client/http/http.go @@ -207,19 +207,11 @@ func (c *baseRPCClient) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo return result, nil } -func (c *baseRPCClient) ABCIQuery( - ctx context.Context, - path string, - data bytes.HexBytes, -) (*coretypes.ResultABCIQuery, error) { +func (c *baseRPCClient) ABCIQuery(ctx context.Context, path string, data bytes.HexBytes) (*coretypes.ResultABCIQuery, error) { return c.ABCIQueryWithOptions(ctx, path, data, rpcclient.DefaultABCIQueryOptions) } -func (c *baseRPCClient) ABCIQueryWithOptions( - ctx context.Context, - path string, - data bytes.HexBytes, - opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { +func (c *baseRPCClient) ABCIQueryWithOptions(ctx context.Context, path string, data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { result := new(coretypes.ResultABCIQuery) if err := c.caller.Call(ctx, "abci_query", abciQueryArgs{ Path: path, @@ -232,10 +224,7 @@ func (c *baseRPCClient) ABCIQueryWithOptions( return result, nil } -func (c *baseRPCClient) BroadcastTxCommit( - ctx context.Context, - tx types.Tx, -) (*coretypes.ResultBroadcastTxCommit, error) { +func (c *baseRPCClient) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) { result := new(coretypes.ResultBroadcastTxCommit) if err := c.caller.Call(ctx, "broadcast_tx_commit", txArgs{Tx: tx}, result); err != nil { return nil, err @@ -243,25 +232,15 @@ func (c *baseRPCClient) BroadcastTxCommit( return result, nil } -func (c *baseRPCClient) BroadcastTxAsync( - ctx context.Context, - tx types.Tx, -) (*coretypes.ResultBroadcastTx, error) { +func (c *baseRPCClient) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { return c.broadcastTX(ctx, "broadcast_tx_async", tx) } -func (c *baseRPCClient) BroadcastTxSync( - ctx context.Context, - tx types.Tx, -) (*coretypes.ResultBroadcastTx, error) { +func (c *baseRPCClient) BroadcastTxSync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { return c.broadcastTX(ctx, "broadcast_tx_sync", tx) } -func (c *baseRPCClient) broadcastTX( - ctx context.Context, - route string, - tx types.Tx, -) (*coretypes.ResultBroadcastTx, error) { +func (c *baseRPCClient) broadcastTX(ctx context.Context, route string, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { result := new(coretypes.ResultBroadcastTx) if err := c.caller.Call(ctx, route, txArgs{Tx: tx}, result); err != nil { return nil, err @@ -269,11 +248,7 @@ func (c *baseRPCClient) broadcastTX( return result, nil } -func (c *baseRPCClient) UnconfirmedTxs( - ctx context.Context, - page *int, - perPage *int, -) (*coretypes.ResultUnconfirmedTxs, error) { +func (c *baseRPCClient) UnconfirmedTxs(ctx context.Context, page *int, perPage *int) (*coretypes.ResultUnconfirmedTxs, error) { result := new(coretypes.ResultUnconfirmedTxs) if err := c.caller.Call(ctx, "unconfirmed_txs", unconfirmedArgs{Page: page, PerPage: perPage}, result); err != nil { @@ -329,10 +304,7 @@ func (c *baseRPCClient) ConsensusState(ctx context.Context) (*coretypes.ResultCo return result, nil } -func (c *baseRPCClient) ConsensusParams( - ctx context.Context, - height *int64, -) (*coretypes.ResultConsensusParams, error) { +func (c *baseRPCClient) ConsensusParams(ctx context.Context, height *int64) (*coretypes.ResultConsensusParams, error) { result := new(coretypes.ResultConsensusParams) if err := c.caller.Call(ctx, "consensus_params", heightArgs{Height: height}, result); err != nil { return nil, err @@ -356,11 +328,7 @@ func (c *baseRPCClient) Health(ctx context.Context) (*coretypes.ResultHealth, er return result, nil } -func (c *baseRPCClient) BlockchainInfo( - ctx context.Context, - minHeight, - maxHeight int64, -) (*coretypes.ResultBlockchainInfo, error) { +func (c *baseRPCClient) BlockchainInfo(ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) { result := new(coretypes.ResultBlockchainInfo) if err := c.caller.Call(ctx, "blockchain", blockchainInfoArgs{ MinHeight: minHeight, @@ -403,10 +371,7 @@ func (c *baseRPCClient) BlockByHash(ctx context.Context, hash bytes.HexBytes) (* return result, nil } -func (c *baseRPCClient) BlockResults( - ctx context.Context, - height *int64, -) (*coretypes.ResultBlockResults, error) { +func (c *baseRPCClient) BlockResults(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) { result := new(coretypes.ResultBlockResults) if err := c.caller.Call(ctx, "block_results", heightArgs{Height: height}, result); err != nil { return nil, err @@ -446,14 +411,7 @@ func (c *baseRPCClient) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) return result, nil } -func (c *baseRPCClient) TxSearch( - ctx context.Context, - query string, - prove bool, - page, - perPage *int, - orderBy string, -) (*coretypes.ResultTxSearch, error) { +func (c *baseRPCClient) TxSearch(ctx context.Context, query string, prove bool, page, perPage *int, orderBy string) (*coretypes.ResultTxSearch, error) { result := new(coretypes.ResultTxSearch) if err := c.caller.Call(ctx, "tx_search", searchArgs{ Query: query, @@ -468,12 +426,7 @@ func (c *baseRPCClient) TxSearch( return result, nil } -func (c *baseRPCClient) BlockSearch( - ctx context.Context, - query string, - page, perPage *int, - orderBy string, -) (*coretypes.ResultBlockSearch, error) { +func (c *baseRPCClient) BlockSearch(ctx context.Context, query string, page, perPage *int, orderBy string) (*coretypes.ResultBlockSearch, error) { result := new(coretypes.ResultBlockSearch) if err := c.caller.Call(ctx, "block_search", searchArgs{ Query: query, @@ -487,12 +440,7 @@ func (c *baseRPCClient) BlockSearch( return result, nil } -func (c *baseRPCClient) Validators( - ctx context.Context, - height *int64, - page, - perPage *int, -) (*coretypes.ResultValidators, error) { +func (c *baseRPCClient) Validators(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) { result := new(coretypes.ResultValidators) if err := c.caller.Call(ctx, "validators", validatorArgs{ Height: height, @@ -504,10 +452,7 @@ func (c *baseRPCClient) Validators( return result, nil } -func (c *baseRPCClient) BroadcastEvidence( - ctx context.Context, - ev types.Evidence, -) (*coretypes.ResultBroadcastEvidence, error) { +func (c *baseRPCClient) BroadcastEvidence(ctx context.Context, ev types.Evidence) (*coretypes.ResultBroadcastEvidence, error) { result := new(coretypes.ResultBroadcastEvidence) if err := c.caller.Call(ctx, "broadcast_evidence", evidenceArgs{ Evidence: coretypes.Evidence{Value: ev}, diff --git a/rpc/client/http/ws.go b/rpc/client/http/ws.go index 2f188a24d..e9a5ac829 100644 --- a/rpc/client/http/ws.go +++ b/rpc/client/http/ws.go @@ -107,6 +107,7 @@ func (w *wsEvents) Unsubscribe(ctx context.Context, subscriber, query string) er } w.mtx.Lock() + defer w.mtx.Unlock() info, ok := w.subscriptions[query] if ok { if info.id != "" { @@ -114,7 +115,6 @@ func (w *wsEvents) Unsubscribe(ctx context.Context, subscriber, query string) er } delete(w.subscriptions, info.query) } - w.mtx.Unlock() return nil } @@ -129,8 +129,8 @@ func (w *wsEvents) UnsubscribeAll(ctx context.Context, subscriber string) error } w.mtx.Lock() + defer w.mtx.Unlock() w.subscriptions = make(map[string]*wsSubscription) - w.mtx.Unlock() return nil } diff --git a/rpc/client/local/local.go b/rpc/client/local/local.go index b9091efac..24a9a6d7e 100644 --- a/rpc/client/local/local.go +++ b/rpc/client/local/local.go @@ -78,11 +78,7 @@ func (c *Local) ABCIQuery(ctx context.Context, path string, data bytes.HexBytes) return c.ABCIQueryWithOptions(ctx, path, data, rpcclient.DefaultABCIQueryOptions) } -func (c *Local) ABCIQueryWithOptions( - ctx context.Context, - path string, - data bytes.HexBytes, - opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { +func (c *Local) ABCIQueryWithOptions(ctx context.Context, path string, data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { return c.env.ABCIQuery(ctx, path, data, opts.Height, opts.Prove) } @@ -189,23 +185,11 @@ func (c *Local) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) (*coret return c.env.Tx(ctx, hash, prove) } -func (c *Local) TxSearch( - ctx context.Context, - queryString string, - prove bool, - page, - perPage *int, - orderBy string, -) (*coretypes.ResultTxSearch, error) { +func (c *Local) TxSearch(ctx context.Context, queryString string, prove bool, page, perPage *int, orderBy string) (*coretypes.ResultTxSearch, error) { return c.env.TxSearch(ctx, queryString, prove, page, perPage, orderBy) } -func (c *Local) BlockSearch( - ctx context.Context, - queryString string, - page, perPage *int, - orderBy string, -) (*coretypes.ResultBlockSearch, error) { +func (c *Local) BlockSearch(ctx context.Context, queryString string, page, perPage *int, orderBy string) (*coretypes.ResultBlockSearch, error) { return c.env.BlockSearch(ctx, queryString, page, perPage, orderBy) } @@ -213,11 +197,7 @@ func (c *Local) BroadcastEvidence(ctx context.Context, ev types.Evidence) (*core return c.env.BroadcastEvidence(ctx, coretypes.Evidence{Value: ev}) } -func (c *Local) Subscribe( - ctx context.Context, - subscriber, - queryString string, - capacity ...int) (out <-chan coretypes.ResultEvent, err error) { +func (c *Local) Subscribe(ctx context.Context, subscriber, queryString string, capacity ...int) (<-chan coretypes.ResultEvent, error) { q, err := query.New(queryString) if err != nil { return nil, fmt.Errorf("failed to parse query: %w", err) @@ -251,12 +231,7 @@ func (c *Local) Subscribe( return outc, nil } -func (c *Local) eventsRoutine( - ctx context.Context, - sub eventbus.Subscription, - subArgs pubsub.SubscribeArgs, - outc chan<- coretypes.ResultEvent, -) { +func (c *Local) eventsRoutine(ctx context.Context, sub eventbus.Subscription, subArgs pubsub.SubscribeArgs, outc chan<- coretypes.ResultEvent) { qstr := subArgs.Query.String() for { msg, err := sub.Next(ctx) @@ -271,17 +246,24 @@ func (c *Local) eventsRoutine( } continue } - outc <- coretypes.ResultEvent{ + select { + case outc <- coretypes.ResultEvent{ SubscriptionID: msg.SubscriptionID(), Query: qstr, Data: msg.Data(), Events: msg.Events(), + }: + case <-ctx.Done(): + return } } } // Try to resubscribe with exponential backoff. func (c *Local) resubscribe(ctx context.Context, subArgs pubsub.SubscribeArgs) eventbus.Subscription { + timer := time.NewTimer(0) + defer timer.Stop() + attempts := 0 for { if !c.IsRunning() { @@ -294,7 +276,13 @@ func (c *Local) resubscribe(ctx context.Context, subArgs pubsub.SubscribeArgs) e } attempts++ - time.Sleep((10 << uint(attempts)) * time.Millisecond) // 10ms -> 20ms -> 40ms + timer.Reset((10 << uint(attempts)) * time.Millisecond) // 10ms -> 20ms -> 40ms + select { + case <-timer.C: + continue + case <-ctx.Done(): + return nil + } } } diff --git a/rpc/jsonrpc/server/http_server.go b/rpc/jsonrpc/server/http_server.go index 32917b8cb..0b715835d 100644 --- a/rpc/jsonrpc/server/http_server.go +++ b/rpc/jsonrpc/server/http_server.go @@ -46,13 +46,7 @@ func DefaultConfig() *Config { // Serve creates a http.Server and calls Serve with the given listener. It // wraps handler to recover panics and limit the request body size. -func Serve( - ctx context.Context, - listener net.Listener, - handler http.Handler, - logger log.Logger, - config *Config, -) error { +func Serve(ctx context.Context, listener net.Listener, handler http.Handler, logger log.Logger, config *Config) error { logger.Info(fmt.Sprintf("Starting RPC HTTP server on %s", listener.Addr())) h := recoverAndLogHandler(MaxBytesHandler(handler, config.MaxBodyBytes), logger) s := &http.Server{ @@ -83,19 +77,14 @@ func Serve( // Serve creates a http.Server and calls ServeTLS with the given listener, // certFile and keyFile. It wraps handler to recover panics and limit the // request body size. -func ServeTLS( - ctx context.Context, - listener net.Listener, - handler http.Handler, - certFile, keyFile string, - logger log.Logger, - config *Config, -) error { - logger.Info(fmt.Sprintf("Starting RPC HTTPS server on %s (cert: %q, key: %q)", - listener.Addr(), certFile, keyFile)) - h := recoverAndLogHandler(MaxBytesHandler(handler, config.MaxBodyBytes), logger) +func ServeTLS(ctx context.Context, listener net.Listener, handler http.Handler, certFile, keyFile string, logger log.Logger, config *Config) error { + logger.Info("Starting RPC HTTPS server", + "listenterAddr", listener.Addr(), + "certFile", certFile, + "keyFile", keyFile) + s := &http.Server{ - Handler: h, + Handler: recoverAndLogHandler(MaxBytesHandler(handler, config.MaxBodyBytes), logger), ReadTimeout: config.ReadTimeout, WriteTimeout: config.WriteTimeout, MaxHeaderBytes: config.MaxHeaderBytes, diff --git a/rpc/jsonrpc/server/ws_handler.go b/rpc/jsonrpc/server/ws_handler.go index 3fc86b86f..7f2221b24 100644 --- a/rpc/jsonrpc/server/ws_handler.go +++ b/rpc/jsonrpc/server/ws_handler.go @@ -36,11 +36,7 @@ type WebsocketManager struct { // NewWebsocketManager returns a new WebsocketManager that passes a map of // functions, connection options and logger to new WS connections. -func NewWebsocketManager( - logger log.Logger, - funcMap map[string]*RPCFunc, - wsConnOptions ...func(*wsConnection), -) *WebsocketManager { +func NewWebsocketManager(logger log.Logger, funcMap map[string]*RPCFunc, wsConnOptions ...func(*wsConnection)) *WebsocketManager { return &WebsocketManager{ funcMap: funcMap, Upgrader: websocket.Upgrader{ @@ -137,12 +133,7 @@ type wsConnection struct { // description of how to configure ping period and pong wait time. NOTE: if the // write buffer is full, pongs may be dropped, which may cause clients to // disconnect. see https://github.com/gorilla/websocket/issues/97 -func newWSConnection( - baseConn *websocket.Conn, - funcMap map[string]*RPCFunc, - logger log.Logger, - options ...func(*wsConnection), -) *wsConnection { +func newWSConnection(baseConn *websocket.Conn, funcMap map[string]*RPCFunc, logger log.Logger, options ...func(*wsConnection)) *wsConnection { wsc := &wsConnection{ Logger: logger, remoteAddr: baseConn.RemoteAddr().String(), diff --git a/scripts/abci-gen.sh b/scripts/abci-gen.sh index f4666dee9..1e602aaec 100755 --- a/scripts/abci-gen.sh +++ b/scripts/abci-gen.sh @@ -12,9 +12,9 @@ cp ./proto/tendermint/types/types.proto.intermediate ./proto/tendermint/types/ty MODNAME="$(go list -m)" find ./proto/tendermint -name '*.proto' -not -path "./proto/tendermint/abci/types.proto" \ - -exec sh ./scripts/protopackage.sh {} "$MODNAME" ';' + -exec ./scripts/protopackage.sh {} "$MODNAME" ';' -sh ./scripts/protopackage.sh ./proto/tendermint/abci/types.proto $MODNAME "abci/types" +./scripts/protopackage.sh ./proto/tendermint/abci/types.proto $MODNAME "abci/types" make proto-gen diff --git a/scripts/confix/confix_test.go b/scripts/confix/confix_test.go index b7be1247d..ec258f4ca 100644 --- a/scripts/confix/confix_test.go +++ b/scripts/confix/confix_test.go @@ -25,6 +25,7 @@ func TestGuessConfigVersion(t *testing.T) { path, want string }{ {"testdata/non-config.toml", ""}, + {"testdata/v30-config.toml", ""}, {"testdata/v31-config.toml", ""}, {"testdata/v32-config.toml", "v0.32"}, {"testdata/v33-config.toml", "v0.33"}, diff --git a/scripts/confix/testdata/diff-30-31.txt b/scripts/confix/testdata/diff-30-31.txt new file mode 100644 index 000000000..0f93b761e --- /dev/null +++ b/scripts/confix/testdata/diff-30-31.txt @@ -0,0 +1,7 @@ +-M consensus.blocktime-iota ++M mempool.max-txs-bytes ++M rpc.max-subscription-clients ++M rpc.max-subscriptions-per-client ++M rpc.timeout-broadcast-tx-commit ++M rpc.tls-cert-file ++M rpc.tls-key-file diff --git a/scripts/confix/testdata/v30-config.toml b/scripts/confix/testdata/v30-config.toml new file mode 100644 index 000000000..b4aaa5aae --- /dev/null +++ b/scripts/confix/testdata/v30-config.toml @@ -0,0 +1,252 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +##### main base config options ##### + +# TCP or UNIX socket address of the ABCI application, +# or the name of an ABCI application compiled in with the Tendermint binary +proxy_app = "tcp://127.0.0.1:26658" + +# A custom human readable name for this node +moniker = "localhost" + +# If this node is many blocks behind the tip of the chain, FastSync +# allows them to catchup quickly by downloading blocks in parallel +# and verifying their commits +fast_sync = true + +# Database backend: leveldb | memdb | cleveldb +db_backend = "leveldb" + +# Database directory +db_dir = "data" + +# Output level for logging, including package level options +log_level = "main:info,state:info,*:error" + +# Output format: 'plain' (colored text) or 'json' +log_format = "plain" + +##### additional base config options ##### + +# Path to the JSON file containing the initial validator set and other meta data +genesis_file = "config/genesis.json" + +# Path to the JSON file containing the private key to use as a validator in the consensus protocol +priv_validator_key_file = "config/priv_validator_key.json" + +# Path to the JSON file containing the last sign state of a validator +priv_validator_state_file = "data/priv_validator_state.json" + +# TCP or UNIX socket address for Tendermint to listen on for +# connections from an external PrivValidator process +priv_validator_laddr = "" + +# Path to the JSON file containing the private key to use for node authentication in the p2p protocol +node_key_file = "config/node_key.json" + +# Mechanism to connect to the ABCI application: socket | grpc +abci = "socket" + +# TCP or UNIX socket address for the profiling server to listen on +prof_laddr = "" + +# If true, query the ABCI app on connecting to a new peer +# so the app can decide if we should keep the connection or not +filter_peers = false + +##### advanced configuration options ##### + +##### rpc server configuration options ##### +[rpc] + +# TCP or UNIX socket address for the RPC server to listen on +laddr = "tcp://0.0.0.0:26657" + +# A list of origins a cross-domain request can be executed from +# Default value '[]' disables cors support +# Use '["*"]' to allow any origin +cors_allowed_origins = [] + +# A list of methods the client is allowed to use with cross-domain requests +cors_allowed_methods = ["HEAD", "GET", "POST", ] + +# A list of non simple headers the client is allowed to use with cross-domain requests +cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ] + +# TCP or UNIX socket address for the gRPC server to listen on +# NOTE: This server only supports /broadcast_tx_commit +grpc_laddr = "" + +# Maximum number of simultaneous connections. +# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +grpc_max_open_connections = 900 + +# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool +unsafe = false + +# Maximum number of simultaneous connections (including WebSocket). +# Does not include gRPC connections. See grpc_max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +max_open_connections = 900 + +##### peer to peer configuration options ##### +[p2p] + +# Address to listen for incoming connections +laddr = "tcp://0.0.0.0:26656" + +# Address to advertise to peers for them to dial +# If empty, will use the same port as the laddr, +# and will introspect on the listener or use UPnP +# to figure out the address. +external_address = "" + +# Comma separated list of seed nodes to connect to +seeds = "" + +# Comma separated list of nodes to keep persistent connections to +persistent_peers = "" + +# UPNP port forwarding +upnp = false + +# Path to address book +addr_book_file = "config/addrbook.json" + +# Set true for strict address routability rules +# Set false for private or local networks +addr_book_strict = true + +# Maximum number of inbound peers +max_num_inbound_peers = 40 + +# Maximum number of outbound peers to connect to, excluding persistent peers +max_num_outbound_peers = 10 + +# Time to wait before flushing messages out on the connection +flush_throttle_timeout = "100ms" + +# Maximum size of a message packet payload, in bytes +max_packet_msg_payload_size = 1024 + +# Rate at which packets can be sent, in bytes/second +send_rate = 5120000 + +# Rate at which packets can be received, in bytes/second +recv_rate = 5120000 + +# Set true to enable the peer-exchange reactor +pex = true + +# Seed mode, in which node constantly crawls the network and looks for +# peers. If another node asks it for addresses, it responds and disconnects. +# +# Does not work if the peer-exchange reactor is disabled. +seed_mode = false + +# Comma separated list of peer IDs to keep private (will not be gossiped to other peers) +private_peer_ids = "" + +# Toggle to disable guard against peers connecting from the same ip. +allow_duplicate_ip = false + +# Peer connection configuration. +handshake_timeout = "20s" +dial_timeout = "3s" + +##### mempool configuration options ##### +[mempool] + +recheck = true +broadcast = true +wal_dir = "" + +# size of the mempool +size = 5000 + +# size of the cache (used to filter transactions we saw earlier) +cache_size = 10000 + +##### consensus configuration options ##### +[consensus] + +wal_file = "data/cs.wal/wal" + +timeout_propose = "3s" +timeout_propose_delta = "500ms" +timeout_prevote = "1s" +timeout_prevote_delta = "500ms" +timeout_precommit = "1s" +timeout_precommit_delta = "500ms" +timeout_commit = "1s" + +# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) +skip_timeout_commit = false + +# EmptyBlocks mode and possible interval between empty blocks +create_empty_blocks = true +create_empty_blocks_interval = "0s" + +# Reactor sleep duration parameters +peer_gossip_sleep_duration = "100ms" +peer_query_maj23_sleep_duration = "2s" + +# Block time parameters. Corresponds to the minimum time increment between consecutive blocks. +blocktime_iota = "1s" + +##### transactions indexer configuration options ##### +[tx_index] + +# What indexer to use for transactions +# +# Options: +# 1) "null" +# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). +indexer = "kv" + +# Comma-separated list of tags to index (by default the only tag is "tx.hash") +# +# You can also index transactions by height by adding "tx.height" tag here. +# +# It's recommended to index only a subset of tags due to possible memory +# bloat. This is, of course, depends on the indexer's DB and the volume of +# transactions. +index_tags = "" + +# When set to true, tells indexer to index all tags (predefined tags: +# "tx.hash", "tx.height" and all tags from DeliverTx responses). +# +# Note this may be not desirable (see the comment above). IndexTags has a +# precedence over IndexAllTags (i.e. when given both, IndexTags will be +# indexed). +index_all_tags = false + +##### instrumentation configuration options ##### +[instrumentation] + +# When true, Prometheus metrics are served under /metrics on +# PrometheusListenAddr. +# Check out the documentation for the list of available metrics. +prometheus = false + +# Address to listen for Prometheus collector(s) connections +prometheus_listen_addr = ":26660" + +# Maximum number of simultaneous connections. +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +max_open_connections = 3 + +# Instrumentation namespace +namespace = "tendermint" diff --git a/scripts/protopackage.sh b/scripts/protopackage.sh index 5eace2752..fe3e78c8a 100755 --- a/scripts/protopackage.sh +++ b/scripts/protopackage.sh @@ -1,4 +1,4 @@ -#!/usr/bin/sh +#!/bin/bash set -eo pipefail # This script appends the "option go_package" proto option to the file located at $FNAME. diff --git a/scripts/scmigrate/migrate.go b/scripts/scmigrate/migrate.go index ba3de2698..c8e1d9490 100644 --- a/scripts/scmigrate/migrate.go +++ b/scripts/scmigrate/migrate.go @@ -115,7 +115,7 @@ func getAllSeenCommits(ctx context.Context, db dbm.DB) ([]toMigrate, error) { return scData, nil } -func renameRecord(ctx context.Context, db dbm.DB, keep toMigrate) error { +func renameRecord(db dbm.DB, keep toMigrate) error { wantKey := makeKeyFromPrefix(prefixSeenCommit) if bytes.Equal(keep.key, wantKey) { return nil // we already did this conversion @@ -143,7 +143,7 @@ func renameRecord(ctx context.Context, db dbm.DB, keep toMigrate) error { return cerr } -func deleteRecords(ctx context.Context, db dbm.DB, scData []toMigrate) error { +func deleteRecords(db dbm.DB, scData []toMigrate) error { // delete all the remaining stale values in a single batch batch := db.NewBatch() @@ -179,7 +179,7 @@ func Migrate(ctx context.Context, db dbm.DB) error { // retain only the latest. keep, remove := scData[0], scData[1:] - if err := renameRecord(ctx, db, keep); err != nil { + if err := renameRecord(db, keep); err != nil { return fmt.Errorf("renaming seen commit record: %w", err) } @@ -189,7 +189,7 @@ func Migrate(ctx context.Context, db dbm.DB) error { // Remove any older seen commits. Prior to v0.35, we kept these records for // all heights, but v0.35 keeps only the latest. - if err := deleteRecords(ctx, db, remove); err != nil { + if err := deleteRecords(db, remove); err != nil { return fmt.Errorf("writing data: %w", err) } diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 2736dad04..797c3b99c 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -3,20 +3,29 @@ package app import ( "bytes" "encoding/base64" + "encoding/binary" "errors" "fmt" + "math/rand" "path/filepath" "sort" "strconv" + "strings" "sync" "github.com/tendermint/tendermint/abci/example/code" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/version" ) +const ( + voteExtensionKey string = "extensionSum" + voteExtensionMaxVal int64 = 128 +) + // Application is an ABCI application for use by end-to-end tests. It is a // simple key/value store for strings, storing data in memory and persisting // to disk as JSON, taking state sync snapshots if requested. @@ -215,10 +224,10 @@ func (app *Application) Commit() abci.ResponseCommit { if err != nil { panic(err) } - app.logger.Info("Created state sync snapshot", "height", snapshot.Height) + app.logger.Info("created state sync snapshot", "height", snapshot.Height) err = app.snapshots.Prune(maxSnapshotCount) if err != nil { - app.logger.Error("Failed to prune snapshots", "err", err) + app.logger.Error("failed to prune snapshots", "err", err) } } retainHeight := int64(0) @@ -304,7 +313,74 @@ func (app *Application) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) a return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT} } +// PrepareProposal will take the given transactions and attempt to prepare a +// proposal from them when it's our turn to do so. In the process, vote +// extensions from the previous round of consensus, if present, will be used to +// construct a special transaction whose value is the sum of all of the vote +// extensions from the previous round. +// +// NB: Assumes that the supplied transactions do not exceed `req.MaxTxBytes`. +// If adding a special vote extension-generated transaction would cause the +// total number of transaction bytes to exceed `req.MaxTxBytes`, we will not +// append our special vote extension transaction. func (app *Application) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + var sum int64 + var extCount int + for _, vote := range req.LocalLastCommit.Votes { + if !vote.SignedLastBlock || len(vote.VoteExtension) == 0 { + continue + } + extValue, err := parseVoteExtension(vote.VoteExtension) + // This should have been verified in VerifyVoteExtension + if err != nil { + panic(fmt.Errorf("failed to parse vote extension in PrepareProposal: %w", err)) + } + valAddr := crypto.Address(vote.Validator.Address) + app.logger.Info("got vote extension value in PrepareProposal", "valAddr", valAddr, "value", extValue) + sum += extValue + extCount++ + } + // We only generate our special transaction if we have vote extensions + if extCount > 0 { + var totalBytes int64 + extTxPrefix := fmt.Sprintf("%s=", voteExtensionKey) + extTx := []byte(fmt.Sprintf("%s%d", extTxPrefix, sum)) + app.logger.Info("preparing proposal with custom transaction from vote extensions", "tx", extTx) + // Our generated transaction takes precedence over any supplied + // transaction that attempts to modify the "extensionSum" value. + txRecords := make([]*abci.TxRecord, len(req.Txs)+1) + for i, tx := range req.Txs { + if strings.HasPrefix(string(tx), extTxPrefix) { + txRecords[i] = &abci.TxRecord{ + Action: abci.TxRecord_REMOVED, + Tx: tx, + } + } else { + txRecords[i] = &abci.TxRecord{ + Action: abci.TxRecord_UNMODIFIED, + Tx: tx, + } + totalBytes += int64(len(tx)) + } + } + if totalBytes+int64(len(extTx)) < req.MaxTxBytes { + txRecords[len(req.Txs)] = &abci.TxRecord{ + Action: abci.TxRecord_ADDED, + Tx: extTx, + } + } else { + app.logger.Info( + "too many txs to include special vote extension-generated tx", + "totalBytes", totalBytes, + "MaxTxBytes", req.MaxTxBytes, + "extTx", extTx, + "extTxLen", len(extTx), + ) + } + return abci.ResponsePrepareProposal{ + TxRecords: txRecords, + } + } // None of the transactions are modified by this application. trs := make([]*abci.TxRecord, 0, len(req.Txs)) var totalBytes int64 @@ -325,14 +401,87 @@ func (app *Application) PrepareProposal(req abci.RequestPrepareProposal) abci.Re // It accepts any proposal that does not contain a malformed transaction. func (app *Application) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { for _, tx := range req.Txs { - _, _, err := parseTx(tx) + k, v, err := parseTx(tx) if err != nil { + app.logger.Error("malformed transaction in ProcessProposal", "tx", tx, "err", err) return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} } + // Additional check for vote extension-related txs + if k == voteExtensionKey { + _, err := strconv.Atoi(v) + if err != nil { + app.logger.Error("malformed vote extension transaction", k, v, "err", err) + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + } } return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} } +// ExtendVote will produce vote extensions in the form of random numbers to +// demonstrate vote extension nondeterminism. +// +// In the next block, if there are any vote extensions from the previous block, +// a new transaction will be proposed that updates a special value in the +// key/value store ("extensionSum") with the sum of all of the numbers collected +// from the vote extensions. +func (app *Application) ExtendVote(req abci.RequestExtendVote) abci.ResponseExtendVote { + // We ignore any requests for vote extensions that don't match our expected + // next height. + if req.Height != int64(app.state.Height)+1 { + app.logger.Error( + "got unexpected height in ExtendVote request", + "expectedHeight", app.state.Height+1, + "requestHeight", req.Height, + ) + return abci.ResponseExtendVote{} + } + ext := make([]byte, binary.MaxVarintLen64) + // We don't care that these values are generated by a weak random number + // generator. It's just for test purposes. + // nolint:gosec // G404: Use of weak random number generator + num := rand.Int63n(voteExtensionMaxVal) + extLen := binary.PutVarint(ext, num) + app.logger.Info("generated vote extension", "num", num, "ext", fmt.Sprintf("%x", ext[:extLen]), "state.Height", app.state.Height) + return abci.ResponseExtendVote{ + VoteExtension: ext[:extLen], + } +} + +// VerifyVoteExtension simply validates vote extensions from other validators +// without doing anything about them. In this case, it just makes sure that the +// vote extension is a well-formed integer value. +func (app *Application) VerifyVoteExtension(req abci.RequestVerifyVoteExtension) abci.ResponseVerifyVoteExtension { + // We allow vote extensions to be optional + if len(req.VoteExtension) == 0 { + return abci.ResponseVerifyVoteExtension{ + Status: abci.ResponseVerifyVoteExtension_ACCEPT, + } + } + if req.Height != int64(app.state.Height)+1 { + app.logger.Error( + "got unexpected height in VerifyVoteExtension request", + "expectedHeight", app.state.Height, + "requestHeight", req.Height, + ) + return abci.ResponseVerifyVoteExtension{ + Status: abci.ResponseVerifyVoteExtension_REJECT, + } + } + + num, err := parseVoteExtension(req.VoteExtension) + if err != nil { + app.logger.Error("failed to verify vote extension", "req", req, "err", err) + return abci.ResponseVerifyVoteExtension{ + Status: abci.ResponseVerifyVoteExtension_REJECT, + } + } + app.logger.Info("verified vote extension value", "req", req, "num", num) + return abci.ResponseVerifyVoteExtension{ + Status: abci.ResponseVerifyVoteExtension_ACCEPT, + } +} + func (app *Application) Rollback() error { app.mu.Lock() defer app.mu.Unlock() @@ -378,3 +527,19 @@ func parseTx(tx []byte) (string, string, error) { } return string(parts[0]), string(parts[1]), nil } + +// parseVoteExtension attempts to parse the given extension data into a positive +// integer value. +func parseVoteExtension(ext []byte) (int64, error) { + num, errVal := binary.Varint(ext) + if errVal == 0 { + return 0, errors.New("vote extension is too small to parse") + } + if errVal < 0 { + return 0, errors.New("vote extension value is too large") + } + if num >= voteExtensionMaxVal { + return 0, fmt.Errorf("vote extension value must be smaller than %d (was %d)", voteExtensionMaxVal, num) + } + return num, nil +} diff --git a/test/e2e/runner/main.go b/test/e2e/runner/main.go index 7d147f411..c4a73d33f 100644 --- a/test/e2e/runner/main.go +++ b/test/e2e/runner/main.go @@ -134,7 +134,7 @@ func NewCLI(logger log.Logger) *CLI { if err = Wait(ctx, logger, cli.testnet, 5); err != nil { // wait for network to settle before tests return err } - if err := Test(logger, cli.testnet); err != nil { + if err := Test(cli.testnet); err != nil { return err } return nil @@ -259,7 +259,7 @@ func NewCLI(logger log.Logger) *CLI { Use: "test", Short: "Runs test cases against a running testnet", RunE: func(cmd *cobra.Command, args []string) error { - return Test(logger, cli.testnet) + return Test(cli.testnet) }, }) diff --git a/test/e2e/runner/test.go b/test/e2e/runner/test.go index 22fcd730e..2237588a1 100644 --- a/test/e2e/runner/test.go +++ b/test/e2e/runner/test.go @@ -3,12 +3,11 @@ package main import ( "os" - "github.com/tendermint/tendermint/libs/log" e2e "github.com/tendermint/tendermint/test/e2e/pkg" ) // Test runs test cases under tests/ -func Test(logger log.Logger, testnet *e2e.Testnet) error { +func Test(testnet *e2e.Testnet) error { err := os.Setenv("E2E_MANIFEST", testnet.File) if err != nil { return err diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index 36115346b..ed041e186 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "math/rand" + "strconv" "testing" "time" @@ -45,9 +46,11 @@ func TestApp_Hash(t *testing.T) { testNode(t, func(ctx context.Context, t *testing.T, node e2e.Node) { client, err := node.Client() require.NoError(t, err) + info, err := client.ABCIInfo(ctx) require.NoError(t, err) require.NotEmpty(t, info.Response.LastBlockAppHash, "expected app to return app hash") + // In next-block execution, the app hash is stored in the next block blockHeight := info.Response.LastBlockHeight + 1 @@ -60,7 +63,6 @@ func TestApp_Hash(t *testing.T) { block, err := client.Block(ctx, &blockHeight) require.NoError(t, err) - require.Equal(t, blockHeight, block.Block.Height) require.Equal(t, fmt.Sprintf("%x", info.Response.LastBlockAppHash), @@ -185,3 +187,18 @@ func TestApp_Tx(t *testing.T) { } } + +func TestApp_VoteExtensions(t *testing.T) { + testNode(t, func(ctx context.Context, t *testing.T, node e2e.Node) { + client, err := node.Client() + require.NoError(t, err) + + // This special value should have been created by way of vote extensions + resp, err := client.ABCIQuery(ctx, "", []byte("extensionSum")) + require.NoError(t, err) + + extSum, err := strconv.Atoi(string(resp.Response.Value)) + require.NoError(t, err) + require.GreaterOrEqual(t, extSum, 0) + }) +} diff --git a/test/fuzz/Makefile b/test/fuzz/Makefile deleted file mode 100644 index 3bf4486b8..000000000 --- a/test/fuzz/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/make -f - -.PHONY: fuzz-mempool -fuzz-mempool: - cd mempool && \ - rm -f *-fuzz.zip && \ - go-fuzz-build && \ - go-fuzz - -.PHONY: fuzz-p2p-sc -fuzz-p2p-sc: - cd p2p/secretconnection && \ - rm -f *-fuzz.zip && \ - go run ./init-corpus/main.go && \ - go-fuzz-build && \ - go-fuzz - -.PHONY: fuzz-rpc-server -fuzz-rpc-server: - cd rpc/jsonrpc/server && \ - rm -f *-fuzz.zip && \ - go-fuzz-build && \ - go-fuzz - -clean: - find . -name corpus -type d -exec rm -rf {} +; - find . -name crashers -type d -exec rm -rf {} +; - find . -name suppressions -type d -exec rm -rf {} +; - find . -name *\.zip -type f -delete diff --git a/test/fuzz/README.md b/test/fuzz/README.md index 707217afd..11ec9d521 100644 --- a/test/fuzz/README.md +++ b/test/fuzz/README.md @@ -5,68 +5,18 @@ Fuzzing for various packages in Tendermint using [go-fuzz](https://github.com/dv Inputs: - mempool `CheckTx` (using kvstore in-process ABCI app) -- p2p `Addrbook#AddAddress` -- p2p `pex.Reactor#Receive` - p2p `SecretConnection#Read` and `SecretConnection#Write` - rpc jsonrpc server -## Directory structure - -``` -| test -| |- corpus/ -| |- crashers/ -| |- init-corpus/ -| |- suppressions/ -| |- testdata/ -| |- .go -``` - -`/corpus` directory contains corpus data. The idea is to help the fuzzier to -understand what bytes sequences are semantically valid (e.g. if we're testing -PNG decoder, then we would put black-white PNG into corpus directory; with -blockchain reactor - we would put blockchain messages into corpus). - -`/init-corpus` (if present) contains a script for generating corpus data. - -`/testdata` directory may contain an additional data (like `addrbook.json`). - -Upon running the fuzzier, `/crashers` and `/suppressions` dirs will be created, -along with .zip archive. `/crashers` will show any inputs, which have -lead to panics (plus a trace). `/suppressions` will show any suppressed inputs. - ## Running -```sh -make fuzz-mempool -make fuzz-p2p-addrbook -make fuzz-p2p-pex -make fuzz-p2p-sc -make fuzz-rpc-server -``` - -Each command will create corpus data (if needed), generate a fuzz archive and -call `go-fuzz` executable. - -Then watch out for the respective outputs in the fuzzer output to announce new -crashers which can be found in the directory `crashers`. - -For example if we find +The fuzz tests are in native Go fuzzing format. Use the `go` +tool to run them: ```sh -ls crashers/ -61bde465f47c93254d64d643c3b2480e0a54666e -61bde465f47c93254d64d643c3b2480e0a54666e.output -61bde465f47c93254d64d643c3b2480e0a54666e.quoted -da39a3ee5e6b4b0d3255bfef95601890afd80709 -da39a3ee5e6b4b0d3255bfef95601890afd80709.output -da39a3ee5e6b4b0d3255bfef95601890afd80709.quoted +go test -fuzz Mempool ./tests +go test -fuzz P2PSecretConnection ./tests +go test -fuzz RPCJSONRPCServer ./tests ``` -the crashing bytes generated by the fuzzer will be in -`61bde465f47c93254d64d643c3b2480e0a54666e` the respective crash report in -`61bde465f47c93254d64d643c3b2480e0a54666e.output` - -and the bug report can be created by retrieving the bytes in -`61bde465f47c93254d64d643c3b2480e0a54666e` and feeding those back into the -`Fuzz` function. +See [the Go Fuzzing introduction](https://go.dev/doc/fuzz/) for more information. diff --git a/test/fuzz/mempool/fuzz_test.go b/test/fuzz/mempool/fuzz_test.go deleted file mode 100644 index 69f34db64..000000000 --- a/test/fuzz/mempool/fuzz_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package mempool_test - -import ( - "io" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - - mempool "github.com/tendermint/tendermint/test/fuzz/mempool" -) - -const testdataCasesDir = "testdata/cases" - -func TestMempoolTestdataCases(t *testing.T) { - entries, err := os.ReadDir(testdataCasesDir) - require.NoError(t, err) - - for _, e := range entries { - entry := e - t.Run(entry.Name(), func(t *testing.T) { - defer func() { - r := recover() - require.Nilf(t, r, "testdata/cases test panic") - }() - f, err := os.Open(filepath.Join(testdataCasesDir, entry.Name())) - require.NoError(t, err) - input, err := io.ReadAll(f) - require.NoError(t, err) - mempool.Fuzz(input) - }) - } -} diff --git a/test/fuzz/mempool/testdata/cases/empty b/test/fuzz/mempool/testdata/cases/empty deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fuzz/oss-fuzz-build.sh b/test/fuzz/oss-fuzz-build.sh index ef2052614..836253d4d 100755 --- a/test/fuzz/oss-fuzz-build.sh +++ b/test/fuzz/oss-fuzz-build.sh @@ -1,10 +1,22 @@ -#!/bin/bash -eu +#!/bin/bash + +set -euo pipefail export FUZZ_ROOT="github.com/tendermint/tendermint" -(cd test/fuzz/p2p/secretconnection; go run ./init-corpus/main.go) -compile_go_fuzzer "$FUZZ_ROOT"/test/fuzz/p2p/secretconnection Fuzz fuzz_p2p_secretconnection fuzz +build_go_fuzzer() { + local function="$1" + local fuzzer="$2" -compile_go_fuzzer "$FUZZ_ROOT"/test/fuzz/mempool Fuzz fuzz_mempool fuzz + gotip run github.com/orijtech/otils/corpus2ossfuzz@latest -o "$OUT"/"$fuzzer"_seed_corpus.zip -corpus test/fuzz/tests/testdata/fuzz/"$function" + compile_native_go_fuzzer "$FUZZ_ROOT"/test/fuzz/tests "$function" "$fuzzer" +} -compile_go_fuzzer "$FUZZ_ROOT"/test/fuzz/rpc/jsonrpc/server Fuzz fuzz_rpc_jsonrpc_server fuzz +gotip get github.com/AdamKorcz/go-118-fuzz-build/utils +gotip get github.com/prometheus/common/expfmt@v0.32.1 + +build_go_fuzzer FuzzP2PSecretConnection fuzz_p2p_secretconnection + +build_go_fuzzer FuzzMempool fuzz_mempool + +build_go_fuzzer FuzzRPCJSONRPCServer fuzz_rpc_jsonrpc_server diff --git a/test/fuzz/p2p/secretconnection/fuzz_test.go b/test/fuzz/p2p/secretconnection/fuzz_test.go deleted file mode 100644 index 6fe19b03b..000000000 --- a/test/fuzz/p2p/secretconnection/fuzz_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package secretconnection_test - -import ( - "io" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/test/fuzz/p2p/secretconnection" -) - -const testdataCasesDir = "testdata/cases" - -func TestSecretConnectionTestdataCases(t *testing.T) { - entries, err := os.ReadDir(testdataCasesDir) - require.NoError(t, err) - - for _, e := range entries { - entry := e - t.Run(entry.Name(), func(t *testing.T) { - defer func() { - r := recover() - require.Nilf(t, r, "testdata/cases test panic") - }() - f, err := os.Open(filepath.Join(testdataCasesDir, entry.Name())) - require.NoError(t, err) - input, err := io.ReadAll(f) - require.NoError(t, err) - secretconnection.Fuzz(input) - }) - } -} diff --git a/test/fuzz/p2p/secretconnection/init-corpus/main.go b/test/fuzz/p2p/secretconnection/init-corpus/main.go deleted file mode 100644 index 3a2537ff7..000000000 --- a/test/fuzz/p2p/secretconnection/init-corpus/main.go +++ /dev/null @@ -1,47 +0,0 @@ -// nolint: gosec -package main - -import ( - "flag" - "fmt" - "log" - "os" - "path/filepath" -) - -func main() { - baseDir := flag.String("base", ".", `where the "corpus" directory will live`) - flag.Parse() - - initCorpus(*baseDir) -} - -func initCorpus(baseDir string) { - log.SetFlags(0) - - corpusDir := filepath.Join(baseDir, "corpus") - if err := os.MkdirAll(corpusDir, 0755); err != nil { - log.Fatal(err) - } - - data := []string{ - "dadc04c2-cfb1-4aa9-a92a-c0bf780ec8b6", - "", - " ", - " a ", - `{"a": 12, "tsp": 999, k: "blue"}`, - `9999.999`, - `""`, - `Tendermint fuzzing`, - } - - for i, datum := range data { - filename := filepath.Join(corpusDir, fmt.Sprintf("%d", i)) - - if err := os.WriteFile(filename, []byte(datum), 0644); err != nil { - log.Fatalf("can't write %v to %q: %v", datum, filename, err) - } - - log.Printf("wrote %q", filename) - } -} diff --git a/test/fuzz/p2p/secretconnection/testdata/cases/empty b/test/fuzz/p2p/secretconnection/testdata/cases/empty deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fuzz/rpc/jsonrpc/server/fuzz_test.go b/test/fuzz/rpc/jsonrpc/server/fuzz_test.go deleted file mode 100644 index 8a34da8a6..000000000 --- a/test/fuzz/rpc/jsonrpc/server/fuzz_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package server_test - -import ( - "io" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/test/fuzz/rpc/jsonrpc/server" -) - -const testdataCasesDir = "testdata/cases" - -func TestServerTestdataCases(t *testing.T) { - entries, err := os.ReadDir(testdataCasesDir) - require.NoError(t, err) - - for _, e := range entries { - entry := e - t.Run(entry.Name(), func(t *testing.T) { - defer func() { - r := recover() - require.Nilf(t, r, "testdata/cases test panic") - }() - f, err := os.Open(filepath.Join(testdataCasesDir, entry.Name())) - require.NoError(t, err) - input, err := io.ReadAll(f) - require.NoError(t, err) - server.Fuzz(input) - }) - } -} diff --git a/test/fuzz/rpc/jsonrpc/server/handler.go b/test/fuzz/rpc/jsonrpc/server/handler.go deleted file mode 100644 index c9203e9f5..000000000 --- a/test/fuzz/rpc/jsonrpc/server/handler.go +++ /dev/null @@ -1,65 +0,0 @@ -package server - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "net/http/httptest" - - "github.com/tendermint/tendermint/libs/log" - rs "github.com/tendermint/tendermint/rpc/jsonrpc/server" - "github.com/tendermint/tendermint/rpc/jsonrpc/types" -) - -var rpcFuncMap = map[string]*rs.RPCFunc{ - "c": rs.NewRPCFunc(func(ctx context.Context, s string, i int) (string, error) { - return "foo", nil - }, "s", "i"), -} -var mux *http.ServeMux - -func init() { - mux = http.NewServeMux() - rs.RegisterRPCFuncs(mux, rpcFuncMap, log.NewNopLogger()) -} - -func Fuzz(data []byte) int { - if len(data) == 0 { - return -1 - } - - req, _ := http.NewRequest("POST", "http://localhost/", bytes.NewReader(data)) - rec := httptest.NewRecorder() - mux.ServeHTTP(rec, req) - res := rec.Result() - blob, err := io.ReadAll(res.Body) - if err != nil { - panic(err) - } - if err := res.Body.Close(); err != nil { - panic(err) - } - if len(blob) == 0 { - return 1 - } - - if outputJSONIsSlice(blob) { - recv := []types.RPCResponse{} - if err := json.Unmarshal(blob, &recv); err != nil { - panic(err) - } - return 1 - } - recv := &types.RPCResponse{} - if err := json.Unmarshal(blob, recv); err != nil { - panic(err) - } - return 1 -} - -func outputJSONIsSlice(input []byte) bool { - slice := []interface{}{} - return json.Unmarshal(input, &slice) == nil -} diff --git a/test/fuzz/rpc/jsonrpc/server/testdata/1184f5b8d4b6dd08709cf1513f26744167065e0d b/test/fuzz/rpc/jsonrpc/server/testdata/1184f5b8d4b6dd08709cf1513f26744167065e0d deleted file mode 100644 index 6e7ea636e..000000000 --- a/test/fuzz/rpc/jsonrpc/server/testdata/1184f5b8d4b6dd08709cf1513f26744167065e0d +++ /dev/null @@ -1 +0,0 @@ -[0] \ No newline at end of file diff --git a/test/fuzz/rpc/jsonrpc/server/testdata/cases/1184f5b8d4b6dd08709cf1513f26744167065e0d b/test/fuzz/rpc/jsonrpc/server/testdata/cases/1184f5b8d4b6dd08709cf1513f26744167065e0d deleted file mode 100644 index 6e7ea636e..000000000 --- a/test/fuzz/rpc/jsonrpc/server/testdata/cases/1184f5b8d4b6dd08709cf1513f26744167065e0d +++ /dev/null @@ -1 +0,0 @@ -[0] \ No newline at end of file diff --git a/test/fuzz/rpc/jsonrpc/server/testdata/cases/bbcffb1cdb2cea50fd3dd8c1524905551d0b2e79 b/test/fuzz/rpc/jsonrpc/server/testdata/cases/bbcffb1cdb2cea50fd3dd8c1524905551d0b2e79 deleted file mode 100644 index e0be2aa4b..000000000 --- a/test/fuzz/rpc/jsonrpc/server/testdata/cases/bbcffb1cdb2cea50fd3dd8c1524905551d0b2e79 +++ /dev/null @@ -1 +0,0 @@ -[0,0] \ No newline at end of file diff --git a/test/fuzz/rpc/jsonrpc/server/testdata/cases/clusterfuzz-testcase-minimized-fuzz_rpc_jsonrpc_server-4738572803506176 b/test/fuzz/rpc/jsonrpc/server/testdata/cases/clusterfuzz-testcase-minimized-fuzz_rpc_jsonrpc_server-4738572803506176 deleted file mode 100644 index 0f7836d2f..000000000 --- a/test/fuzz/rpc/jsonrpc/server/testdata/cases/clusterfuzz-testcase-minimized-fuzz_rpc_jsonrpc_server-4738572803506176 +++ /dev/null @@ -1 +0,0 @@ -[{"iD":7},{"iD":7}] \ No newline at end of file diff --git a/test/fuzz/rpc/jsonrpc/server/testdata/cases/empty b/test/fuzz/rpc/jsonrpc/server/testdata/cases/empty deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fuzz/rpc/jsonrpc/server/testdata/clusterfuzz-testcase-minimized-fuzz_rpc_jsonrpc_server-4738572803506176 b/test/fuzz/rpc/jsonrpc/server/testdata/clusterfuzz-testcase-minimized-fuzz_rpc_jsonrpc_server-4738572803506176 deleted file mode 100644 index 0f7836d2f..000000000 --- a/test/fuzz/rpc/jsonrpc/server/testdata/clusterfuzz-testcase-minimized-fuzz_rpc_jsonrpc_server-4738572803506176 +++ /dev/null @@ -1 +0,0 @@ -[{"iD":7},{"iD":7}] \ No newline at end of file diff --git a/test/fuzz/mempool/checktx.go b/test/fuzz/tests/mempool_test.go similarity index 74% rename from test/fuzz/mempool/checktx.go rename to test/fuzz/tests/mempool_test.go index 8be90f0c2..a76b059ca 100644 --- a/test/fuzz/mempool/checktx.go +++ b/test/fuzz/tests/mempool_test.go @@ -1,7 +1,10 @@ -package mempool +//go:build gofuzz || go1.18 + +package tests import ( "context" + "testing" abciclient "github.com/tendermint/tendermint/abci/client" "github.com/tendermint/tendermint/abci/example/kvstore" @@ -33,11 +36,11 @@ func init() { } } -func Fuzz(data []byte) int { - err := getMp().CheckTx(context.Background(), data, nil, mempool.TxInfo{}) - if err != nil { - return 0 - } - - return 1 +func FuzzMempool(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + err := getMp().CheckTx(context.Background(), data, nil, mempool.TxInfo{}) + if err != nil { + panic(err) + } + }) } diff --git a/test/fuzz/p2p/secretconnection/read_write.go b/test/fuzz/tests/p2p_secretconnection_test.go similarity index 94% rename from test/fuzz/p2p/secretconnection/read_write.go rename to test/fuzz/tests/p2p_secretconnection_test.go index 87d547e55..65f268a7b 100644 --- a/test/fuzz/p2p/secretconnection/read_write.go +++ b/test/fuzz/tests/p2p_secretconnection_test.go @@ -1,19 +1,28 @@ -package secretconnection +//go:build gofuzz || go1.18 + +package tests import ( "bytes" "fmt" "io" "log" + "testing" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/internal/libs/async" sc "github.com/tendermint/tendermint/internal/p2p/conn" ) -func Fuzz(data []byte) int { +func FuzzP2PSecretConnection(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + fuzz(data) + }) +} + +func fuzz(data []byte) { if len(data) == 0 { - return -1 + return } fooConn, barConn := makeSecretConnPair() @@ -44,14 +53,11 @@ func Fuzz(data []byte) int { } copy(dataRead[totalRead:], buf[:m]) totalRead += m - log.Printf("total read: %d", totalRead) } if !bytes.Equal(data, dataRead) { panic("bytes written != read") } - - return 1 } type kvstoreConn struct { diff --git a/test/fuzz/tests/rpc_jsonrpc_server_test.go b/test/fuzz/tests/rpc_jsonrpc_server_test.go new file mode 100644 index 000000000..bc4e90881 --- /dev/null +++ b/test/fuzz/tests/rpc_jsonrpc_server_test.go @@ -0,0 +1,68 @@ +//go:build gofuzz || go1.18 + +package tests + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/tendermint/tendermint/libs/log" + rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" + "github.com/tendermint/tendermint/rpc/jsonrpc/types" +) + +func FuzzRPCJSONRPCServer(f *testing.F) { + var rpcFuncMap = map[string]*rpcserver.RPCFunc{ + "c": rpcserver.NewRPCFunc(func(ctx context.Context, s string, i int) (string, error) { + return "foo", nil + }, "s", "i"), + } + + mux := http.NewServeMux() + rpcserver.RegisterRPCFuncs(mux, rpcFuncMap, log.NewNopLogger()) + f.Fuzz(func(t *testing.T, data []byte) { + if len(data) == 0 { + return + } + + req, err := http.NewRequest("POST", "http://localhost/", bytes.NewReader(data)) + if err != nil { + panic(err) + } + rec := httptest.NewRecorder() + mux.ServeHTTP(rec, req) + res := rec.Result() + blob, err := io.ReadAll(res.Body) + if err != nil { + panic(err) + } + if err := res.Body.Close(); err != nil { + panic(err) + } + if len(blob) == 0 { + return + } + + if outputJSONIsSlice(blob) { + var recv []types.RPCResponse + if err := json.Unmarshal(blob, &recv); err != nil { + panic(err) + } + return + } + var recv types.RPCResponse + if err := json.Unmarshal(blob, &recv); err != nil { + panic(err) + } + }) +} + +func outputJSONIsSlice(input []byte) bool { + var slice []json.RawMessage + return json.Unmarshal(input, &slice) == nil +} diff --git a/test/fuzz/tests/testdata/fuzz/FuzzMempool/1daffc1033a0bfc7f0c2bccb7440674e67a9e2cc0a4531863076254ada059863 b/test/fuzz/tests/testdata/fuzz/FuzzMempool/1daffc1033a0bfc7f0c2bccb7440674e67a9e2cc0a4531863076254ada059863 new file mode 100644 index 000000000..88467017a --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzMempool/1daffc1033a0bfc7f0c2bccb7440674e67a9e2cc0a4531863076254ada059863 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("S1") diff --git a/test/fuzz/tests/testdata/fuzz/FuzzMempool/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 b/test/fuzz/tests/testdata/fuzz/FuzzMempool/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 new file mode 100644 index 000000000..a96f5599e --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzMempool/582528ddfad69eb57775199a43e0f9fd5c94bba343ce7bb6724d4ebafe311ed4 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0") diff --git a/test/fuzz/tests/testdata/fuzz/FuzzMempool/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d b/test/fuzz/tests/testdata/fuzz/FuzzMempool/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d new file mode 100644 index 000000000..e0f2da225 --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzMempool/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/0f1a3d10e4d642e42a3ccd9bad652d355431f5824327271aca6f648e8cd4e786 b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/0f1a3d10e4d642e42a3ccd9bad652d355431f5824327271aca6f648e8cd4e786 new file mode 100644 index 000000000..f0b8ea88b --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/0f1a3d10e4d642e42a3ccd9bad652d355431f5824327271aca6f648e8cd4e786 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte(" ") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/172c521d1c5e7a5cce55e39b235928fc1c8c4adbb4635913c204c4724cf47d20 b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/172c521d1c5e7a5cce55e39b235928fc1c8c4adbb4635913c204c4724cf47d20 new file mode 100644 index 000000000..a3668a6db --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/172c521d1c5e7a5cce55e39b235928fc1c8c4adbb4635913c204c4724cf47d20 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("{\"a\": 12, \"tsp\": 999, k: \"blue\"}") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/a9481542b8154bfe8fe868c8907cb66557347cb9b45709b17da861997d7cabea b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/a9481542b8154bfe8fe868c8907cb66557347cb9b45709b17da861997d7cabea new file mode 100644 index 000000000..98241189c --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/a9481542b8154bfe8fe868c8907cb66557347cb9b45709b17da861997d7cabea @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("\"\"") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/ba3758980fe724f83bdf1cb97caa73657b4a78d48e5fd6fc3b1590d24799e803 b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/ba3758980fe724f83bdf1cb97caa73657b4a78d48e5fd6fc3b1590d24799e803 new file mode 100644 index 000000000..c479f2604 --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/ba3758980fe724f83bdf1cb97caa73657b4a78d48e5fd6fc3b1590d24799e803 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("9999.999") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/c22ff3cdf5145a03ecc6a2c18a7ec4eb3c9e1384af92cfa14cf50951535b6c85 b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/c22ff3cdf5145a03ecc6a2c18a7ec4eb3c9e1384af92cfa14cf50951535b6c85 new file mode 100644 index 000000000..280f15bf7 --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/c22ff3cdf5145a03ecc6a2c18a7ec4eb3c9e1384af92cfa14cf50951535b6c85 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte(" a ") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d new file mode 100644 index 000000000..e0f2da225 --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/dc7304b2cddeadd08647d30b1d027f749960376c338e14a81e0396ffc6e6d6bd b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/dc7304b2cddeadd08647d30b1d027f749960376c338e14a81e0396ffc6e6d6bd new file mode 100644 index 000000000..017f8d03f --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzP2PSecretConnection/dc7304b2cddeadd08647d30b1d027f749960376c338e14a81e0396ffc6e6d6bd @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("Tendermint fuzzing") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/058ae08103537df220789dea46edb8b7cf7368e90da0cb35888a1452f4d114a2 b/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/058ae08103537df220789dea46edb8b7cf7368e90da0cb35888a1452f4d114a2 new file mode 100644 index 000000000..53742f182 --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/058ae08103537df220789dea46edb8b7cf7368e90da0cb35888a1452f4d114a2 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("[{\"iD\":7},{\"iD\":7}]") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/2ab633cb322fca9e76fc965b430076844ebd0b3c4f30f5263b94a3d50f00bce6 b/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/2ab633cb322fca9e76fc965b430076844ebd0b3c4f30f5263b94a3d50f00bce6 new file mode 100644 index 000000000..ef2bd593a --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/2ab633cb322fca9e76fc965b430076844ebd0b3c4f30f5263b94a3d50f00bce6 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("[0,0]") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/aadb440fa55da05c1185e3e64b33c804d994cce06781e8c39481411793a8a73f b/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/aadb440fa55da05c1185e3e64b33c804d994cce06781e8c39481411793a8a73f new file mode 100644 index 000000000..fb9f33963 --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/aadb440fa55da05c1185e3e64b33c804d994cce06781e8c39481411793a8a73f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("[0]") \ No newline at end of file diff --git a/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d b/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d new file mode 100644 index 000000000..e0f2da225 --- /dev/null +++ b/test/fuzz/tests/testdata/fuzz/FuzzRPCJSONRPCServer/d40a98862ed393eb712e47a91bcef18e6f24cf368bb4bd248c7a7101ef8e178d @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("") \ No newline at end of file diff --git a/types/block.go b/types/block.go index d6e45af6a..578ac43ee 100644 --- a/types/block.go +++ b/types/block.go @@ -603,21 +603,19 @@ const ( // CommitSig is a part of the Vote included in a Commit. type CommitSig struct { - BlockIDFlag BlockIDFlag `json:"block_id_flag"` - ValidatorAddress Address `json:"validator_address"` - Timestamp time.Time `json:"timestamp"` - Signature []byte `json:"signature"` - VoteExtension VoteExtensionToSign `json:"vote_extension"` + BlockIDFlag BlockIDFlag `json:"block_id_flag"` + ValidatorAddress Address `json:"validator_address"` + Timestamp time.Time `json:"timestamp"` + Signature []byte `json:"signature"` } // NewCommitSigForBlock returns new CommitSig with BlockIDFlagCommit. -func NewCommitSigForBlock(signature []byte, valAddr Address, ts time.Time, ext VoteExtensionToSign) CommitSig { +func NewCommitSigForBlock(signature []byte, valAddr Address, ts time.Time) CommitSig { return CommitSig{ BlockIDFlag: BlockIDFlagCommit, ValidatorAddress: valAddr, Timestamp: ts, Signature: signature, - VoteExtension: ext, } } @@ -650,14 +648,12 @@ func (cs CommitSig) Absent() bool { // 1. first 6 bytes of signature // 2. first 6 bytes of validator address // 3. block ID flag -// 4. first 6 bytes of the vote extension -// 5. timestamp +// 4. timestamp func (cs CommitSig) String() string { - return fmt.Sprintf("CommitSig{%X by %X on %v with %X @ %s}", + return fmt.Sprintf("CommitSig{%X by %X on %v @ %s}", tmbytes.Fingerprint(cs.Signature), tmbytes.Fingerprint(cs.ValidatorAddress), cs.BlockIDFlag, - tmbytes.Fingerprint(cs.VoteExtension.BytesPacked()), CanonicalTime(cs.Timestamp)) } @@ -729,7 +725,6 @@ func (cs *CommitSig) ToProto() *tmproto.CommitSig { ValidatorAddress: cs.ValidatorAddress, Timestamp: cs.Timestamp, Signature: cs.Signature, - VoteExtension: cs.VoteExtension.ToProto(), } } @@ -741,7 +736,6 @@ 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() } @@ -808,7 +802,6 @@ func (commit *Commit) GetVote(valIdx int32) *Vote { ValidatorAddress: commitSig.ValidatorAddress, ValidatorIndex: valIdx, Signature: commitSig.Signature, - VoteExtension: commitSig.VoteExtension.ToVoteExtension(), } } diff --git a/types/block_test.go b/types/block_test.go index 4ed47dd9d..97b12cdba 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -274,7 +274,7 @@ func TestCommit(t *testing.T) { require.NotNil(t, commit.BitArray()) assert.Equal(t, bits.NewBitArray(10).Size(), commit.BitArray().Size()) - assert.Equal(t, voteSet.GetByIndex(0), commit.GetByIndex(0)) + assert.Equal(t, voteWithoutExtension(voteSet.GetByIndex(0)), commit.GetByIndex(0)) assert.True(t, commit.IsCommit()) } @@ -571,7 +571,7 @@ func TestCommitToVoteSet(t *testing.T) { voteSet2 := CommitToVoteSet(chainID, commit, valSet) for i := int32(0); int(i) < len(vals); i++ { - vote1 := voteSet.GetByIndex(i) + vote1 := voteWithoutExtension(voteSet.GetByIndex(i)) vote2 := voteSet2.GetByIndex(i) vote3 := commit.GetVote(i) diff --git a/types/canonical.go b/types/canonical.go index 2e2063e36..9a3d995ec 100644 --- a/types/canonical.go +++ b/types/canonical.go @@ -51,26 +51,29 @@ func CanonicalizeProposal(chainID string, proposal *tmproto.Proposal) tmproto.Ca } } -func GetVoteExtensionToSign(ext *tmproto.VoteExtension) *tmproto.VoteExtensionToSign { - if ext == nil { - return nil - } - return &tmproto.VoteExtensionToSign{ - AppDataToSign: ext.AppDataToSign, +// CanonicalizeVote transforms the given Vote to a CanonicalVote, which does +// not contain ValidatorIndex and ValidatorAddress fields, or any fields +// relating to vote extensions. +func CanonicalizeVote(chainID string, vote *tmproto.Vote) tmproto.CanonicalVote { + return tmproto.CanonicalVote{ + Type: vote.Type, + Height: vote.Height, // encoded as sfixed64 + Round: int64(vote.Round), // encoded as sfixed64 + BlockID: CanonicalizeBlockID(vote.BlockID), + Timestamp: vote.Timestamp, + ChainID: chainID, } } -// CanonicalizeVote transforms the given Vote to a CanonicalVote, which does -// not contain ValidatorIndex and ValidatorAddress fields. -func CanonicalizeVote(chainID string, vote *tmproto.Vote) tmproto.CanonicalVote { - return tmproto.CanonicalVote{ - Type: vote.Type, - Height: vote.Height, // encoded as sfixed64 - Round: int64(vote.Round), // encoded as sfixed64 - BlockID: CanonicalizeBlockID(vote.BlockID), - Timestamp: vote.Timestamp, - ChainID: chainID, - VoteExtension: GetVoteExtensionToSign(vote.VoteExtension), +// CanonicalizeVoteExtension extracts the vote extension from the given vote +// and constructs a CanonicalizeVoteExtension struct, whose representation in +// bytes is what is signed in order to produce the vote extension's signature. +func CanonicalizeVoteExtension(chainID string, vote *tmproto.Vote) tmproto.CanonicalVoteExtension { + return tmproto.CanonicalVoteExtension{ + Extension: vote.Extension, + Height: vote.Height, + Round: int64(vote.Round), + ChainId: chainID, } } diff --git a/types/events.go b/types/events.go index cd535e71b..d87b74cb8 100644 --- a/types/events.go +++ b/types/events.go @@ -1,7 +1,6 @@ package types import ( - "context" "fmt" "strings" @@ -308,15 +307,15 @@ func QueryForEvent(eventValue string) *tmquery.Query { // BlockEventPublisher publishes all block related events type BlockEventPublisher interface { - PublishEventNewBlock(ctx context.Context, block EventDataNewBlock) error - PublishEventNewBlockHeader(ctx context.Context, header EventDataNewBlockHeader) error - PublishEventNewEvidence(ctx context.Context, evidence EventDataNewEvidence) error - PublishEventTx(context.Context, EventDataTx) error - PublishEventValidatorSetUpdates(context.Context, EventDataValidatorSetUpdates) error + PublishEventNewBlock(EventDataNewBlock) error + PublishEventNewBlockHeader(EventDataNewBlockHeader) error + PublishEventNewEvidence(EventDataNewEvidence) error + PublishEventTx(EventDataTx) error + PublishEventValidatorSetUpdates(EventDataValidatorSetUpdates) error } type TxEventPublisher interface { - PublishEventTx(context.Context, EventDataTx) error + PublishEventTx(EventDataTx) error } // eventWithAttr constructs a single abci.Event with a single attribute. diff --git a/types/evidence_test.go b/types/evidence_test.go index dd3b54d08..e284c2fca 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -295,7 +295,14 @@ func TestMockEvidenceValidateBasic(t *testing.T) { func makeVote( ctx context.Context, - t *testing.T, val PrivValidator, chainID string, valIndex int32, height int64, round int32, step int, blockID BlockID, + t *testing.T, + val PrivValidator, + chainID string, + valIndex int32, + height int64, + round int32, + step int, + blockID BlockID, time time.Time, ) *Vote { pubKey, err := val.GetPubKey(ctx) diff --git a/types/priv_validator.go b/types/priv_validator.go index 5a9b27cb6..29620f829 100644 --- a/types/priv_validator.go +++ b/types/priv_validator.go @@ -90,11 +90,17 @@ func (pv MockPV) SignVote(ctx context.Context, chainID string, vote *tmproto.Vot } signBytes := VoteSignBytes(useChainID, vote) + extSignBytes := VoteExtensionSignBytes(useChainID, vote) sig, err := pv.PrivKey.Sign(signBytes) if err != nil { return err } vote.Signature = sig + extSig, err := pv.PrivKey.Sign(extSignBytes) + if err != nil { + return err + } + vote.ExtensionSignature = extSig return nil } diff --git a/types/protobuf_test.go b/types/protobuf_test.go index 3ab095eee..c482153c1 100644 --- a/types/protobuf_test.go +++ b/types/protobuf_test.go @@ -14,11 +14,11 @@ import ( func TestABCIPubKey(t *testing.T) { pkEd := ed25519.GenPrivKey().PubKey() - err := testABCIPubKey(t, pkEd, ABCIPubKeyTypeEd25519) + err := testABCIPubKey(t, pkEd) assert.NoError(t, err) } -func testABCIPubKey(t *testing.T, pk crypto.PubKey, typeStr string) error { +func testABCIPubKey(t *testing.T, pk crypto.PubKey) error { abciPubKey, err := encoding.PubKeyToProto(pk) require.NoError(t, err) pk2, err := encoding.PubKeyFromProto(abciPubKey) diff --git a/types/test_util.go b/types/test_util.go index dbd3f81ec..8aea2f02c 100644 --- a/types/test_util.go +++ b/types/test_util.go @@ -43,5 +43,16 @@ func signAddVote(ctx context.Context, privVal PrivValidator, vote *Vote, voteSet return false, err } vote.Signature = v.Signature + vote.ExtensionSignature = v.ExtensionSignature return voteSet.AddVote(vote) } + +// Votes constructed from commits don't have extensions, because we don't store +// the extensions themselves in the commit. This method is used to construct a +// copy of a vote, but nil its extension and signature. +func voteWithoutExtension(v *Vote) *Vote { + vc := v.Copy() + vc.Extension = nil + vc.ExtensionSignature = nil + return vc +} diff --git a/types/vote.go b/types/vote.go index 7333f98fc..e66f40396 100644 --- a/types/vote.go +++ b/types/vote.go @@ -46,86 +46,19 @@ func NewConflictingVoteError(vote1, vote2 *Vote) *ErrVoteConflictingVotes { // Address is hex bytes. type Address = crypto.Address -// VoteExtensionToSign is a subset of VoteExtension -// that is signed by the validators private key -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 := []byte{} - res = append(res, ext.AppDataToSign...) - return res -} - -// ToVoteExtension constructs a VoteExtension from a VoteExtensionToSign -func (ext VoteExtensionToSign) ToVoteExtension() VoteExtension { - return VoteExtension{ - AppDataToSign: ext.AppDataToSign, - } -} - -// VoteExtension is a set of data provided by the application -// that is additionally included in the vote -type VoteExtension struct { - AppDataToSign []byte `json:"app_data_to_sign"` - AppDataSelfAuthenticating []byte `json:"app_data_self_authenticating"` -} - -// ToSign constructs a VoteExtensionToSign from a VoteExtenstion -func (ext VoteExtension) ToSign() VoteExtensionToSign { - return VoteExtensionToSign{ - AppDataToSign: ext.AppDataToSign, - } -} - -// BytesPacked returns a bytes-packed representation for -// debugging and human identification. This function should -// not be used for any logical operations. -func (ext VoteExtension) BytesPacked() []byte { - res := []byte{} - res = append(res, ext.AppDataToSign...) - res = append(res, ext.AppDataSelfAuthenticating...) - return res -} - // Vote represents a prevote, precommit, or commit vote from validators for // consensus. type Vote struct { - Type tmproto.SignedMsgType `json:"type"` - Height int64 `json:"height,string"` - Round int32 `json:"round"` // assume there will not be greater than 2_147_483_647 rounds - BlockID BlockID `json:"block_id"` // zero if vote is nil. - Timestamp time.Time `json:"timestamp"` - ValidatorAddress Address `json:"validator_address"` - ValidatorIndex int32 `json:"validator_index"` - Signature []byte `json:"signature"` - VoteExtension VoteExtension `json:"vote_extension"` + Type tmproto.SignedMsgType `json:"type"` + Height int64 `json:"height,string"` + Round int32 `json:"round"` // assume there will not be greater than 2_147_483_647 rounds + BlockID BlockID `json:"block_id"` // zero if vote is nil. + Timestamp time.Time `json:"timestamp"` + ValidatorAddress Address `json:"validator_address"` + ValidatorIndex int32 `json:"validator_index"` + Signature []byte `json:"signature"` + Extension []byte `json:"extension"` + ExtensionSignature []byte `json:"extension_signature"` } // CommitSig converts the Vote to a CommitSig. @@ -149,12 +82,11 @@ func (vote *Vote) CommitSig() CommitSig { ValidatorAddress: vote.ValidatorAddress, Timestamp: vote.Timestamp, Signature: vote.Signature, - VoteExtension: vote.VoteExtension.ToSign(), } } // VoteSignBytes returns the proto-encoding of the canonicalized Vote, for -// signing. Panics is the marshaling fails. +// signing. Panics if the marshaling fails. // // The encoded Protobuf message is varint length-prefixed (using MarshalDelimited) // for backwards-compatibility with the Amino encoding, due to e.g. hardware @@ -171,9 +103,23 @@ func VoteSignBytes(chainID string, vote *tmproto.Vote) []byte { return bz } +// VoteExtensionSignBytes returns the proto-encoding of the canonicalized vote +// extension for signing. Panics if the marshaling fails. +// +// Similar to VoteSignBytes, the encoded Protobuf message is varint +// length-prefixed for backwards-compatibility with the Amino encoding. +func VoteExtensionSignBytes(chainID string, vote *tmproto.Vote) []byte { + pb := CanonicalizeVoteExtension(chainID, vote) + bz, err := protoio.MarshalDelimited(&pb) + if err != nil { + panic(err) + } + + return bz +} + func (vote *Vote) Copy() *Vote { voteCopy := *vote - voteCopy.VoteExtension = vote.VoteExtension.Copy() return &voteCopy } @@ -213,7 +159,7 @@ func (vote *Vote) String() string { typeString, tmbytes.Fingerprint(vote.BlockID.Hash), tmbytes.Fingerprint(vote.Signature), - tmbytes.Fingerprint(vote.VoteExtension.BytesPacked()), + tmbytes.Fingerprint(vote.Extension), CanonicalTime(vote.Timestamp), ) } @@ -226,6 +172,12 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error { if !pubKey.VerifySignature(VoteSignBytes(chainID, v), vote.Signature) { return ErrVoteInvalidSignature } + extSignBytes := VoteExtensionSignBytes(chainID, v) + // TODO: Remove extension signature nil check to enforce vote extension + // signing once we resolve https://github.com/tendermint/tendermint/issues/8272 + if vote.ExtensionSignature != nil && !pubKey.VerifySignature(extSignBytes, vote.ExtensionSignature) { + return ErrVoteInvalidSignature + } return nil } @@ -272,40 +224,15 @@ func (vote *Vote) ValidateBasic() error { return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize) } - // XXX: add length verification for vote extension? + // TODO: Remove the extension length check such that we always require + // extension signatures to be present. + if len(vote.Extension) > 0 && len(vote.ExtensionSignature) == 0 { + return errors.New("vote extension signature is missing") + } return nil } -func (ext VoteExtension) Copy() VoteExtension { - res := VoteExtension{ - AppDataToSign: ext.AppDataToSign, - AppDataSelfAuthenticating: ext.AppDataSelfAuthenticating, - } - return res -} - -func (ext VoteExtension) IsEmpty() bool { - if len(ext.AppDataToSign) != 0 { - return false - } - if len(ext.AppDataSelfAuthenticating) != 0 { - return false - } - return true -} - -func (ext VoteExtension) ToProto() *tmproto.VoteExtension { - if ext.IsEmpty() { - return nil - } - - return &tmproto.VoteExtension{ - AppDataToSign: ext.AppDataToSign, - AppDataSelfAuthenticating: ext.AppDataSelfAuthenticating, - } -} - // ToProto converts the handwritten type to proto generated type // return type, nil if everything converts safely, otherwise nil, error func (vote *Vote) ToProto() *tmproto.Vote { @@ -314,15 +241,16 @@ func (vote *Vote) ToProto() *tmproto.Vote { } return &tmproto.Vote{ - Type: vote.Type, - Height: vote.Height, - Round: vote.Round, - BlockID: vote.BlockID.ToProto(), - Timestamp: vote.Timestamp, - ValidatorAddress: vote.ValidatorAddress, - ValidatorIndex: vote.ValidatorIndex, - Signature: vote.Signature, - VoteExtension: vote.VoteExtension.ToProto(), + Type: vote.Type, + Height: vote.Height, + Round: vote.Round, + BlockID: vote.BlockID.ToProto(), + Timestamp: vote.Timestamp, + ValidatorAddress: vote.ValidatorAddress, + ValidatorIndex: vote.ValidatorIndex, + Signature: vote.Signature, + Extension: vote.Extension, + ExtensionSignature: vote.ExtensionSignature, } } @@ -342,15 +270,6 @@ func VotesToProto(votes []*Vote) []*tmproto.Vote { return res } -func VoteExtensionFromProto(pext *tmproto.VoteExtension) VoteExtension { - ext := VoteExtension{} - if pext != nil { - ext.AppDataToSign = pext.AppDataToSign - ext.AppDataSelfAuthenticating = pext.AppDataSelfAuthenticating - } - return ext -} - // FromProto converts a proto generetad type to a handwritten type // return type, nil if everything converts safely, otherwise nil, error func VoteFromProto(pv *tmproto.Vote) (*Vote, error) { @@ -372,7 +291,8 @@ func VoteFromProto(pv *tmproto.Vote) (*Vote, error) { vote.ValidatorAddress = pv.ValidatorAddress vote.ValidatorIndex = pv.ValidatorIndex vote.Signature = pv.Signature - vote.VoteExtension = VoteExtensionFromProto(pv.VoteExtension) + vote.Extension = pv.Extension + vote.ExtensionSignature = pv.ExtensionSignature return vote, vote.ValidateBasic() } diff --git a/types/vote_set_test.go b/types/vote_set_test.go index 4de9b1837..1805b4c3e 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -127,6 +127,7 @@ func TestVoteSet_AddVote_Bad(t *testing.T) { t.Errorf("expected VoteSet.Add to fail, wrong type") } } + } func TestVoteSet_2_3Majority(t *testing.T) { @@ -509,7 +510,6 @@ func randVoteSet( ) (*VoteSet, *ValidatorSet, []PrivValidator) { t.Helper() valSet, privValidators := randValidatorPrivValSet(ctx, t, numValidators, votingPower) - return NewVoteSet("test_chain_id", height, round, signedMsgType, valSet), valSet, privValidators } diff --git a/types/vote_test.go b/types/vote_test.go index 4a852d81f..949c996d0 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -13,6 +13,7 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/internal/libs/protoio" + tmtime "github.com/tendermint/tendermint/libs/time" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -130,12 +131,13 @@ func TestVoteSignBytesTestVectors(t *testing.T) { }, // containing vote extension 5: { - "test_chain_id", &Vote{Height: 1, Round: 1, VoteExtension: VoteExtension{ - AppDataToSign: []byte("signed"), - AppDataSelfAuthenticating: []byte("auth"), - }}, + "test_chain_id", &Vote{ + Height: 1, + Round: 1, + Extension: []byte("extension"), + }, []byte{ - 0x38, // length + 0x2e, // length 0x11, // (field_number << 3) | wire_type 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height 0x19, // (field_number << 3) | wire_type @@ -146,13 +148,6 @@ func TestVoteSignBytesTestVectors(t *testing.T) { // (field_number << 3) | wire_type 0x32, 0xd, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, // chainID - // (field_number << 3) | wire_type - 0x3a, - 0x8, // length - 0xa, // (field_number << 3) | wire_type - 0x6, // length - 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, // AppDataSigned - // SelfAuthenticating data is excluded on signing }, // chainID }, } @@ -208,6 +203,82 @@ func TestVoteVerifySignature(t *testing.T) { require.True(t, valid) } +// TestVoteExtension tests that the vote verification behaves correctly in each case +// of vote extension being set on the vote. +func TestVoteExtension(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + testCases := []struct { + name string + extension []byte + includeSignature bool + expectError bool + }{ + { + name: "all fields present", + extension: []byte("extension"), + includeSignature: true, + expectError: false, + }, + // TODO: Re-enable once + // https://github.com/tendermint/tendermint/issues/8272 is resolved. + //{ + // name: "no extension signature", + // extension: []byte("extension"), + // includeSignature: false, + // expectError: true, + //}, + { + name: "empty extension", + includeSignature: true, + expectError: false, + }, + // TODO: Re-enable once + // https://github.com/tendermint/tendermint/issues/8272 is resolved. + //{ + // name: "no extension and no signature", + // includeSignature: false, + // expectError: true, + //}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + height, round := int64(1), int32(0) + privVal := NewMockPV() + pk, err := privVal.GetPubKey(ctx) + require.NoError(t, err) + blk := Block{} + ps, err := blk.MakePartSet(BlockPartSizeBytes) + require.NoError(t, err) + vote := &Vote{ + ValidatorAddress: pk.Address(), + ValidatorIndex: 0, + Height: height, + Round: round, + Timestamp: tmtime.Now(), + Type: tmproto.PrecommitType, + BlockID: BlockID{blk.Hash(), ps.Header()}, + } + + v := vote.ToProto() + err = privVal.SignVote(ctx, "test_chain_id", v) + require.NoError(t, err) + vote.Signature = v.Signature + if tc.includeSignature { + vote.ExtensionSignature = v.ExtensionSignature + } + err = vote.Verify("test_chain_id", pk) + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + func TestIsVoteTypeValid(t *testing.T) { tc := []struct { name string