mirror of
https://github.com/tendermint/tendermint.git
synced 2026-07-19 22:42:24 +00:00
Vote extensions: base implementation (#9836)
* [cherry-picked] abci: Vote Extension 1 (#6646)
* add proto, add boilerplates
* add canonical
* fix tests
* add vote signing test
* Update internal/consensus/msgs_test.go
* modify state execution in progress
* add extension signing
* VoteExtension -> ExtendVote
* apply review
* update data structures
* Add comments
* Apply suggestions from code review
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
* *Signed -> *ToSign
* add Vote to RequestExtendVote
* apply reviews
* Apply suggestions from code review
Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
* fix typo, modify proto
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
* [cherry-picked] ABCI Vote Extension 2 (#6885)
* add proto, add boilerplates
* add canonical
* fix tests
* add vote signing test
* Update internal/consensus/msgs_test.go
* modify state execution in progress
* add extension signing
* add extension signing
* VoteExtension -> ExtendVote
* modify state execution in progress
* add extension signing
* verify in progress
* modify CommitSig
* fix test
* apply review
* update data structures
* Apply suggestions from code review
* Add comments
* fix test
* VoteExtensionSigned => VoteExtensionToSigned
* Apply suggestions from code review
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
* *Signed -> *ToSign
* add Vote to RequestExtendVote
* add example VoteExtension
* apply reviews
* fix vote
* Apply suggestions from code review
Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
* fix typo, modify proto
* add abcipp_kvstore.go
* add extension test
* fix test
* fix test
* fix test
* fit lint
* uncomment test
* refactor test in progress
* gofmt
* apply review
* fix lint
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
* [cheryy-picked] abci: PrepareProposal-VoteExtension integration [2nd try] (#7821)
* PrepareProposal-VoteExtension integration (#6915)
* make proto-gen
* Fix protobuf crash in e2e nightly tests
* Update types/vote.go
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
* Addressed @creachadair's comments
Co-authored-by: mconcat <monoidconcat@gmail.com>
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
* [cherry-picked] Vote extensions: new design (#8031)
* Changed the spec text to agreed VoteExtension solution
* Revert "Removed protobufs related to vote extensions"
This reverts commit 4566f1e302.
* Changes to ABCI protocol buffers
* Update spec/core/data_structures.md
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
* Update spec/core/data_structures.md
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
* Fix dangling link in ABCI++ readme
* Addressed comments
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
* [cherry-picked] abci++: Sync implementation and spec for vote extensions (#8141)
* Refactor so building and linting works
This is the first step towards implementing vote extensions: generating
the relevant proto stubs and getting the build and linter to pass.
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Fix typo
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Better describe method given vote extensions
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Fix types tests
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Move CanonicalVoteExtension to canonical types proto defs
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Regenerate protos including latest PBTS synchrony params update
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Inject vote extensions into proposal
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Thread vote extensions through code and fix tests
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Remove extraneous empty value initialization
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Fix lint
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Fix missing VerifyVoteExtension request data
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Explicitly ensure length > 0 to sign vote extension
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Explicitly ensure length > 0 to sign vote extension
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Remove extraneous comment
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Update privval/file.go
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
* Update types/vote_test.go
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
* Format
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Fix ABCI proto generation scripts for Linux
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Sync intermediate and goal protos
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Update internal/consensus/common_test.go
Co-authored-by: Sergio Mena <sergio@informal.systems>
* Use dummy value with clearer meaning
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Rewrite loop for clarity
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Panic on ABCI++ method call failure
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Add strong correctness guarantees when constructing extended commit info for ABCI++
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Add strong guarantee in extendedCommitInfo that the number of votes corresponds
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Make extendedCommitInfo function more robust
At first extendedCommitInfo expected votes to be in the same order as
their corresponding validators in the supplied CommitInfo struct, but
this proved to be rather difficult since when a validator set's loaded
from state it's first sorted by voting power and then by address.
Instead of sorting the votes in the same way, this approach simply maps
votes to their corresponding validator's address prior to constructing
the extended commit info. This way it's easy to look up the
corresponding vote and we don't need to care about vote order.
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Remove extraneous validator address assignment
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Sign over canonical vote extension
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Validate vote extension signature against canonical vote extension
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Update privval tests for more meaningful dummy value
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Add vote extension capability to E2E test app
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Disable lint for weak RNG usage for test app
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Use parseVoteExtension instead of custom parsing in PrepareProposal
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Only include extension if we have received txs
It's unclear at this point why this is necessary to ensure that the
application's local app_hash matches that committed in the previous
block.
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Require app_hash from app to match that from last block
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Add contrived (possibly flaky) test to check that vote extensions code works
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Remove workaround for problem now solved by #8229
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* add tests for vote extension cases
* Fix spelling mistake to appease linter
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Collapse redundant if statement
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Formatting
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Always expect an extension signature, regardless of whether an extension is present
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Votes constructed from commits cannot include extensions or signatures
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Pass through vote extension in test helpers
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Temporarily disable vote extension signature requirement
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Expand on vote equality test errors for clarity
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Expand on vote matching error messages in testing
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Allow for selective subscription by vote type
This is an attempt to fix the intermittently failing
`TestPrepareProposalReceivesVoteExtensions` test in the internal
consensus package.
Occasionally we get prevote messages via the subscription channel, and
we're not interested in those. This change allows us to specify what
types of votes we're interested in (i.e. precommits) and discard the
rest.
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Read lock consensus state mutex in test helper to avoid data race
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Revert BlockIDFlag parameter in node test
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Perform additional check in ProcessProposal for special txs generated by vote extensions
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* e2e: check that our added tx does not cause all txs to exceed req.MaxTxBytes
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Only set vote extension signatures when signing is successful
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Remove channel capacity constraint in test helper to avoid missing messages
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Add TODO to always require extension signatures in vote validation
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* e2e: reject vote extensions if the request height does not match what we expect
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* types: remove extraneous call to voteWithoutExtension in test
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Remove unnecessary address parameter from CanonicalVoteExtension
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* privval: change test vote type to precommit since we use an extension
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* privval: update signing logic to cater for vote extensions
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* proto: update field descriptions for vote message
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* proto: update field description for vote extension sig in vote message
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* proto/types: use fixed-length 64-bit integers for rounds in CanonicalVoteExtension
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* consensus: fix flaky TestPrepareProposalReceivesVoteExtensions
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* consensus: remove previously added test helper functionality
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* e2e: add error logs when we get an unexpected height in ExtendVote or VerifyVoteExtension requests
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* node_test: get validator addresses from privvals
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* privval/file_test: optimize filepv creation in tests
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* privval: add test to check that vote extensions are always signed
Signed-off-by: Thane Thomson <connect@thanethomson.com>
* Add a script to check documentation for ToC entries. (#8356)
This script verifies that each document in the docs and architecture directory
has a corresponding table-of-contents entry in its README file. It can be run
manually from the command line.
- Hook up this script to run in CI (optional workflow).
- Update ADR ToC to include missing entries this script found.
* build(deps): Bump async from 2.6.3 to 2.6.4 in /docs (#8357)
Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)
---
updated-dependencies:
- dependency-name: async
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* privval/file_test: reset vote ext sig before signing
Signed-off-by: Thane Thomson <connect@thanethomson.com>
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
Co-authored-by: Sergio Mena <sergio@informal.systems>
Co-authored-by: William Banfield <wbanfield@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Fix cherry-picks
* make proto-gen
* make mockery
* fix build
* All units tests passing
* linter error
* Update consensus/state_test.go
Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>
* Addressed @williambanfield's comments
* Go, not C!
Co-authored-by: mconcat <monoidconcat@gmail.com>
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Dev Ojha <ValarDragon@users.noreply.github.com>
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
Co-authored-by: Thane Thomson <connect@thanethomson.com>
Co-authored-by: William Banfield <wbanfield@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com>
This commit is contained in:
@@ -234,6 +234,14 @@ func (cli *grpcClient) ProcessProposal(ctx context.Context, req *types.RequestPr
|
||||
return cli.client.ProcessProposal(ctx, types.ToRequestProcessProposal(req).GetProcessProposal(), grpc.WaitForReady(true))
|
||||
}
|
||||
|
||||
func (cli *grpcClient) ExtendVote(ctx context.Context, req *types.RequestExtendVote) (*types.ResponseExtendVote, error) {
|
||||
return cli.client.ExtendVote(ctx, types.ToRequestExtendVote(req).GetExtendVote(), grpc.WaitForReady(true))
|
||||
}
|
||||
|
||||
func (cli *grpcClient) VerifyVoteExtension(ctx context.Context, req *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) {
|
||||
return cli.client.VerifyVoteExtension(ctx, types.ToRequestVerifyVoteExtension(req).GetVerifyVoteExtension(), grpc.WaitForReady(true))
|
||||
}
|
||||
|
||||
func (cli *grpcClient) FinalizeBlock(ctx context.Context, req *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
|
||||
return cli.client.FinalizeBlock(ctx, types.ToRequestFinalizeBlock(req).GetFinalizeBlock(), grpc.WaitForReady(true))
|
||||
}
|
||||
|
||||
@@ -164,6 +164,20 @@ func (app *localClient) ProcessProposal(ctx context.Context, req *types.RequestP
|
||||
return app.Application.ProcessProposal(ctx, req)
|
||||
}
|
||||
|
||||
func (app *localClient) ExtendVote(ctx context.Context, req *types.RequestExtendVote) (*types.ResponseExtendVote, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
|
||||
return app.Application.ExtendVote(ctx, req)
|
||||
}
|
||||
|
||||
func (app *localClient) VerifyVoteExtension(ctx context.Context, req *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
|
||||
return app.Application.VerifyVoteExtension(ctx, req)
|
||||
}
|
||||
|
||||
func (app *localClient) FinalizeBlock(ctx context.Context, req *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
|
||||
@@ -148,6 +148,29 @@ func (_m *Client) Error() error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// ExtendVote provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Client) ExtendVote(_a0 context.Context, _a1 *types.RequestExtendVote) (*types.ResponseExtendVote, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *types.ResponseExtendVote
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.RequestExtendVote) *types.ResponseExtendVote); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseExtendVote)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.RequestExtendVote) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FinalizeBlock provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Client) FinalizeBlock(_a0 context.Context, _a1 *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
@@ -498,6 +521,29 @@ func (_m *Client) String() string {
|
||||
return r0
|
||||
}
|
||||
|
||||
// VerifyVoteExtension provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Client) VerifyVoteExtension(_a0 context.Context, _a1 *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *types.ResponseVerifyVoteExtension
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.RequestVerifyVoteExtension) *types.ResponseVerifyVoteExtension); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseVerifyVoteExtension)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.RequestVerifyVoteExtension) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewClient interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
|
||||
@@ -379,6 +379,28 @@ func (cli *socketClient) ProcessProposal(ctx context.Context, req *types.Request
|
||||
return reqRes.Response.GetProcessProposal(), cli.Error()
|
||||
}
|
||||
|
||||
func (cli *socketClient) ExtendVote(ctx context.Context, req *types.RequestExtendVote) (*types.ResponseExtendVote, error) {
|
||||
reqRes, err := cli.queueRequest(ctx, types.ToRequestExtendVote(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cli.Flush(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reqRes.Response.GetExtendVote(), cli.Error()
|
||||
}
|
||||
|
||||
func (cli *socketClient) VerifyVoteExtension(ctx context.Context, req *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) {
|
||||
reqRes, err := cli.queueRequest(ctx, types.ToRequestVerifyVoteExtension(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cli.Flush(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reqRes.Response.GetVerifyVoteExtension(), cli.Error()
|
||||
}
|
||||
|
||||
func (cli *socketClient) FinalizeBlock(ctx context.Context, req *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
|
||||
reqRes, err := cli.queueRequest(ctx, types.ToRequestFinalizeBlock(req))
|
||||
if err != nil {
|
||||
@@ -461,6 +483,10 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) {
|
||||
_, ok = res.Value.(*types.Response_ListSnapshots)
|
||||
case *types.Request_OfferSnapshot:
|
||||
_, ok = res.Value.(*types.Response_OfferSnapshot)
|
||||
case *types.Request_ExtendVote:
|
||||
_, ok = res.Value.(*types.Response_ExtendVote)
|
||||
case *types.Request_VerifyVoteExtension:
|
||||
_, ok = res.Value.(*types.Response_VerifyVoteExtension)
|
||||
case *types.Request_PrepareProposal:
|
||||
_, ok = res.Value.(*types.Response_PrepareProposal)
|
||||
case *types.Request_ProcessProposal:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# KVStore
|
||||
|
||||
The KVStoreApplication is a simple merkle key-value store.
|
||||
The KVStoreApplication is a simple merkle key-value store.
|
||||
Transactions of the form `key=value` are stored as key-value pairs in the tree.
|
||||
Transactions without an `=` sign set the value to the key.
|
||||
The app has no replay protection (other than what the mempool provides).
|
||||
|
||||
@@ -288,6 +288,18 @@ func (s *SocketServer) handleRequest(ctx context.Context, req *types.Request) (*
|
||||
return nil, err
|
||||
}
|
||||
return types.ToResponseApplySnapshotChunk(res), nil
|
||||
case *types.Request_ExtendVote:
|
||||
res, err := s.app.ExtendVote(ctx, r.ExtendVote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.ToResponseExtendVote(res), nil
|
||||
case *types.Request_VerifyVoteExtension:
|
||||
res, err := s.app.VerifyVoteExtension(ctx, r.VerifyVoteExtension)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.ToResponseVerifyVoteExtension(res), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown request from client: %T", req)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ type Application interface {
|
||||
ProcessProposal(context.Context, *RequestProcessProposal) (*ResponseProcessProposal, error)
|
||||
// Deliver the decided block with its txs to the Application
|
||||
FinalizeBlock(context.Context, *RequestFinalizeBlock) (*ResponseFinalizeBlock, error)
|
||||
// Create application specific vote extension
|
||||
ExtendVote(context.Context, *RequestExtendVote) (*ResponseExtendVote, error)
|
||||
// Verify application's vote extension data
|
||||
VerifyVoteExtension(context.Context, *RequestVerifyVoteExtension) (*ResponseVerifyVoteExtension, error)
|
||||
// Commit the state and return the application Merkle root hash
|
||||
Commit(context.Context, *RequestCommit) (*ResponseCommit, error)
|
||||
|
||||
@@ -94,6 +98,16 @@ func (BaseApplication) ProcessProposal(_ context.Context, req *RequestProcessPro
|
||||
return &ResponseProcessProposal{Status: ResponseProcessProposal_ACCEPT}, nil
|
||||
}
|
||||
|
||||
func (BaseApplication) ExtendVote(_ context.Context, req *RequestExtendVote) (*ResponseExtendVote, error) {
|
||||
return &ResponseExtendVote{}, nil
|
||||
}
|
||||
|
||||
func (BaseApplication) VerifyVoteExtension(_ context.Context, req *RequestVerifyVoteExtension) (*ResponseVerifyVoteExtension, error) {
|
||||
return &ResponseVerifyVoteExtension{
|
||||
Status: ResponseVerifyVoteExtension_ACCEPT,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (BaseApplication) FinalizeBlock(_ context.Context, req *RequestFinalizeBlock) (*ResponseFinalizeBlock, error) {
|
||||
txs := make([]*ExecTxResult, len(req.Txs))
|
||||
for i := range req.Txs {
|
||||
|
||||
@@ -105,6 +105,18 @@ func ToRequestProcessProposal(req *RequestProcessProposal) *Request {
|
||||
}
|
||||
}
|
||||
|
||||
func ToRequestExtendVote(req *RequestExtendVote) *Request {
|
||||
return &Request{
|
||||
Value: &Request_ExtendVote{req},
|
||||
}
|
||||
}
|
||||
|
||||
func ToRequestVerifyVoteExtension(req *RequestVerifyVoteExtension) *Request {
|
||||
return &Request{
|
||||
Value: &Request_VerifyVoteExtension{req},
|
||||
}
|
||||
}
|
||||
|
||||
func ToRequestFinalizeBlock(req *RequestFinalizeBlock) *Request {
|
||||
return &Request{
|
||||
Value: &Request_FinalizeBlock{req},
|
||||
@@ -197,6 +209,18 @@ func ToResponseProcessProposal(res *ResponseProcessProposal) *Response {
|
||||
}
|
||||
}
|
||||
|
||||
func ToResponseExtendVote(res *ResponseExtendVote) *Response {
|
||||
return &Response{
|
||||
Value: &Response_ExtendVote{res},
|
||||
}
|
||||
}
|
||||
|
||||
func ToResponseVerifyVoteExtension(res *ResponseVerifyVoteExtension) *Response {
|
||||
return &Response{
|
||||
Value: &Response_VerifyVoteExtension{res},
|
||||
}
|
||||
}
|
||||
|
||||
func ToResponseFinalizeBlock(res *ResponseFinalizeBlock) *Response {
|
||||
return &Response{
|
||||
Value: &Response_FinalizeBlock{res},
|
||||
|
||||
@@ -83,6 +83,29 @@ func (_m *Application) Commit(_a0 context.Context, _a1 *types.RequestCommit) (*t
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ExtendVote provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Application) ExtendVote(_a0 context.Context, _a1 *types.RequestExtendVote) (*types.ResponseExtendVote, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *types.ResponseExtendVote
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.RequestExtendVote) *types.ResponseExtendVote); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseExtendVote)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.RequestExtendVote) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FinalizeBlock provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Application) FinalizeBlock(_a0 context.Context, _a1 *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
@@ -290,6 +313,29 @@ func (_m *Application) Query(_a0 context.Context, _a1 *types.RequestQuery) (*typ
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// VerifyVoteExtension provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Application) VerifyVoteExtension(_a0 context.Context, _a1 *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *types.ResponseVerifyVoteExtension
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.RequestVerifyVoteExtension) *types.ResponseVerifyVoteExtension); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseVerifyVoteExtension)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.RequestVerifyVoteExtension) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewApplication interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
|
||||
@@ -51,6 +51,10 @@ func (r ResponseProcessProposal) IsStatusUnknown() bool {
|
||||
return r.Status == ResponseProcessProposal_UNKNOWN
|
||||
}
|
||||
|
||||
func (r ResponseVerifyVoteExtension) IsAccepted() bool {
|
||||
return r.Status == ResponseVerifyVoteExtension_ACCEPT
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// override JSON marshaling so we emit defaults (ie. disable omitempty)
|
||||
|
||||
@@ -156,3 +160,6 @@ func MarshalTxResults(r []*ExecTxResult) ([][]byte, error) {
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
// construct Result data
|
||||
|
||||
+1583
-288
File diff suppressed because it is too large
Load Diff
@@ -198,6 +198,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
}
|
||||
|
||||
var commit *types.Commit
|
||||
var votes []*types.Vote
|
||||
switch {
|
||||
case lazyProposer.Height == lazyProposer.state.InitialHeight:
|
||||
// We're creating a proposal for the first block.
|
||||
@@ -206,6 +207,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
case lazyProposer.LastCommit.HasTwoThirdsMajority():
|
||||
// Make the commit from LastCommit
|
||||
commit = lazyProposer.LastCommit.MakeCommit()
|
||||
votes = lazyProposer.LastCommit.GetVotes()
|
||||
default: // This shouldn't happen.
|
||||
lazyProposer.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block")
|
||||
return
|
||||
@@ -223,7 +225,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
|
||||
proposerAddr := lazyProposer.privValidatorPubKey.Address()
|
||||
|
||||
block, err := lazyProposer.blockExec.CreateProposalBlock(
|
||||
lazyProposer.Height, lazyProposer.state, commit, proposerAddr, nil)
|
||||
lazyProposer.Height, lazyProposer.state, commit, proposerAddr, votes)
|
||||
require.NoError(t, err)
|
||||
blockParts, err := block.MakePartSet(types.BlockPartSizeBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
+26
-32
@@ -93,7 +93,8 @@ func newValidatorStub(privValidator types.PrivValidator, valIndex int32) *valida
|
||||
func (vs *validatorStub) signVote(
|
||||
voteType tmproto.SignedMsgType,
|
||||
hash []byte,
|
||||
header types.PartSetHeader) (*types.Vote, error) {
|
||||
header types.PartSetHeader,
|
||||
voteExtension []byte) (*types.Vote, error) {
|
||||
|
||||
pubKey, err := vs.PrivValidator.GetPubKey()
|
||||
if err != nil {
|
||||
@@ -101,34 +102,37 @@ func (vs *validatorStub) signVote(
|
||||
}
|
||||
|
||||
vote := &types.Vote{
|
||||
ValidatorIndex: vs.Index,
|
||||
ValidatorAddress: pubKey.Address(),
|
||||
Type: voteType,
|
||||
Height: vs.Height,
|
||||
Round: vs.Round,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: voteType,
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: header},
|
||||
Timestamp: tmtime.Now(),
|
||||
ValidatorAddress: pubKey.Address(),
|
||||
ValidatorIndex: vs.Index,
|
||||
Extension: voteExtension,
|
||||
}
|
||||
v := vote.ToProto()
|
||||
if err := vs.PrivValidator.SignVote(test.DefaultTestChainID, v); err != nil {
|
||||
if err = vs.PrivValidator.SignVote(test.DefaultTestChainID, 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
|
||||
}
|
||||
|
||||
// Sign vote for type/hash/header
|
||||
func signVote(vs *validatorStub, voteType tmproto.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
|
||||
v, err := vs.signVote(voteType, hash, header)
|
||||
v, err := vs.signVote(voteType, hash, header, []byte("extension"))
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to sign vote: %v", err))
|
||||
}
|
||||
@@ -312,43 +316,27 @@ func validatePrecommit(
|
||||
}
|
||||
}
|
||||
|
||||
rs := cs.GetRoundState()
|
||||
if lockedBlockHash == nil {
|
||||
if cs.LockedRound != lockRound || cs.LockedBlock != nil {
|
||||
if rs.LockedRound != lockRound || rs.LockedBlock != nil {
|
||||
panic(fmt.Sprintf(
|
||||
"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 {
|
||||
if cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash) {
|
||||
if rs.LockedRound != lockRound || !bytes.Equal(rs.LockedBlock.Hash(), lockedBlockHash) {
|
||||
panic(fmt.Sprintf(
|
||||
"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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validatePrevoteAndPrecommit(
|
||||
t *testing.T,
|
||||
cs *State,
|
||||
thisRound,
|
||||
lockRound int32,
|
||||
privVal *validatorStub,
|
||||
votedBlockHash,
|
||||
lockedBlockHash []byte,
|
||||
) {
|
||||
// verify the prevote
|
||||
validatePrevote(t, cs, thisRound, privVal, votedBlockHash)
|
||||
// verify precommit
|
||||
cs.mtx.Lock()
|
||||
validatePrecommit(t, cs, thisRound, lockRound, privVal, votedBlockHash, lockedBlockHash)
|
||||
cs.mtx.Unlock()
|
||||
}
|
||||
|
||||
func subscribeToVoter(cs *State, addr []byte) <-chan tmpubsub.Message {
|
||||
votesSub, err := cs.eventBus.SubscribeUnbuffered(context.Background(), testSubscriber, types.EventQueryVote)
|
||||
if err != nil {
|
||||
@@ -695,6 +683,11 @@ func ensurePrevoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int
|
||||
ensureVoteMatch(t, voteCh, height, round, hash, tmproto.PrevoteType)
|
||||
}
|
||||
|
||||
func ensurePrecommitMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte) {
|
||||
t.Helper()
|
||||
ensureVoteMatch(t, voteCh, height, round, hash, tmproto.PrecommitType)
|
||||
}
|
||||
|
||||
func ensureVoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte, voteType tmproto.SignedMsgType) {
|
||||
t.Helper()
|
||||
select {
|
||||
@@ -960,5 +953,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)
|
||||
}
|
||||
|
||||
@@ -349,6 +349,8 @@ func TestConsMsgsVectors(t *testing.T) {
|
||||
BlockID: bi,
|
||||
}
|
||||
vpb := v.ToProto()
|
||||
v.Extension = []byte("extension")
|
||||
vextPb := v.ToProto()
|
||||
|
||||
testCases := []struct {
|
||||
testName string
|
||||
@@ -381,9 +383,12 @@ func TestConsMsgsVectors(t *testing.T) {
|
||||
{"BlockPart", &tmcons.Message{Sum: &tmcons.Message_BlockPart{
|
||||
BlockPart: &tmcons.BlockPart{Height: 1, Round: 1, Part: *pbParts}}},
|
||||
"2a36080110011a3008011204746573741a26080110011a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d"},
|
||||
{"Vote", &tmcons.Message{Sum: &tmcons.Message_Vote{
|
||||
{"Vote_without_ext", &tmcons.Message{Sum: &tmcons.Message_Vote{
|
||||
Vote: &tmcons.Vote{Vote: vpb}}},
|
||||
"32700a6e0802100122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a0608c0b89fdc0532146164645f6d6f72655f6578636c616d6174696f6e3801"},
|
||||
{"Vote_with_ext", &tmcons.Message{Sum: &tmcons.Message_Vote{
|
||||
Vote: &tmcons.Vote{Vote: vextPb}}},
|
||||
"327b0a790802100122480a206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d1224080112206164645f6d6f72655f6578636c616d6174696f6e5f6d61726b735f636f64652d2a0608c0b89fdc0532146164645f6d6f72655f6578636c616d6174696f6e38014a09657874656e73696f6e"},
|
||||
{"HasVote", &tmcons.Message{Sum: &tmcons.Message_HasVote{
|
||||
HasVote: &tmcons.HasVote{Height: 1, Round: 1, Type: tmproto.PrevoteType, Index: 1}}},
|
||||
"3a080801100118012001"},
|
||||
|
||||
+23
-2
@@ -765,7 +765,6 @@ func (cs *State) receiveRoutine(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(mi)
|
||||
@@ -1971,6 +1970,7 @@ func (cs *State) handleCompleteProposal(blockHeight int64) {
|
||||
// Attempt to add the vote. if its a duplicate signature, dupeout the validator
|
||||
func (cs *State) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, error) {
|
||||
added, err := cs.addVote(vote, peerID)
|
||||
|
||||
if err != nil {
|
||||
// If the vote height is off, we'll just ignore it,
|
||||
// But if it's a conflicting sig, add it to the cs.evpool.
|
||||
@@ -2068,6 +2068,13 @@ func (cs *State) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error
|
||||
return
|
||||
}
|
||||
|
||||
// Verify VoteExtension if precommit
|
||||
if vote.Type == tmproto.PrecommitType {
|
||||
if err = cs.blockExec.VerifyVoteExtension(vote); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
height := cs.Height
|
||||
added, err = cs.Votes.AddVote(vote, peerID)
|
||||
if !added {
|
||||
@@ -2229,9 +2236,19 @@ func (cs *State) signVote(
|
||||
BlockID: types.BlockID{Hash: hash, PartSetHeader: header},
|
||||
}
|
||||
|
||||
switch msgType {
|
||||
case tmproto.PrecommitType:
|
||||
// if the signedMessage type is for a precommit, add VoteExtension
|
||||
ext, err := cs.blockExec.ExtendVote(vote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vote.Extension = ext
|
||||
}
|
||||
v := vote.ToProto()
|
||||
err := cs.privValidator.SignVote(cs.state.ChainID, v)
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
vote.Timestamp = v.Timestamp
|
||||
|
||||
return vote, err
|
||||
@@ -2259,7 +2276,11 @@ func (cs *State) voteTime() time.Time {
|
||||
}
|
||||
|
||||
// sign the vote and publish on internalMsgQueue
|
||||
func (cs *State) signAddVote(msgType tmproto.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
|
||||
func (cs *State) signAddVote(
|
||||
msgType tmproto.SignedMsgType,
|
||||
hash []byte,
|
||||
header types.PartSetHeader,
|
||||
) *types.Vote {
|
||||
if cs.privValidator == nil { // the node does not have a key
|
||||
return nil
|
||||
}
|
||||
|
||||
+246
-6
@@ -363,7 +363,7 @@ func TestStateFullRound1(t *testing.T) {
|
||||
|
||||
// nil is proposed, so prevote and precommit nil
|
||||
func TestStateFullRoundNil(t *testing.T) {
|
||||
cs, vss := randState(1)
|
||||
cs, _ := randState(1)
|
||||
height, round := cs.Height, cs.Round
|
||||
|
||||
voteCh := subscribeUnBuffered(cs.eventBus, types.EventQueryVote)
|
||||
@@ -371,11 +371,8 @@ func TestStateFullRoundNil(t *testing.T) {
|
||||
cs.enterPrevote(height, round)
|
||||
cs.startRoutines(4)
|
||||
|
||||
ensurePrevote(voteCh, height, round) // prevote
|
||||
ensurePrecommit(voteCh, height, round) // precommit
|
||||
|
||||
// should prevote and precommit nil
|
||||
validatePrevoteAndPrecommit(t, cs, round, -1, vss[0], nil, nil)
|
||||
ensurePrevoteMatch(t, voteCh, height, round, nil) // prevote
|
||||
ensurePrecommitMatch(t, voteCh, height, round, nil) // precommit
|
||||
}
|
||||
|
||||
// run through propose, prevote, precommit commit with two validators
|
||||
@@ -1421,6 +1418,233 @@ func TestProcessProposalAccept(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) {
|
||||
m := abcimocks.NewApplication(t)
|
||||
m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{}, nil)
|
||||
m.On("ProcessProposal", mock.Anything, mock.Anything).Return(&abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil)
|
||||
m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{
|
||||
VoteExtension: []byte("extension"),
|
||||
}, nil)
|
||||
m.On("VerifyVoteExtension", mock.Anything, mock.Anything).Return(&abci.ResponseVerifyVoteExtension{
|
||||
Status: abci.ResponseVerifyVoteExtension_ACCEPT,
|
||||
}, nil)
|
||||
m.On("Commit", mock.Anything, mock.Anything).Return(&abci.ResponseCommit{}, nil).Maybe()
|
||||
m.On("FinalizeBlock", mock.Anything, mock.Anything).Return(&abci.ResponseFinalizeBlock{}, nil).Maybe()
|
||||
cs1, vss := randStateWithApp(4, m)
|
||||
height, round := cs1.Height, cs1.Round
|
||||
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
pv1, err := cs1.privValidator.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
addr := pv1.Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
startTestRound(cs1, cs1.Height, round)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
|
||||
m.AssertNotCalled(t, "ExtendVote", mock.Anything)
|
||||
|
||||
rs := cs1.GetRoundState()
|
||||
|
||||
blockID := types.BlockID{
|
||||
Hash: rs.ProposalBlock.Hash(),
|
||||
PartSetHeader: rs.ProposalBlockParts.Header(),
|
||||
}
|
||||
signAddVotes(cs1, tmproto.PrevoteType, blockID.Hash, blockID.PartSetHeader, vss[1:]...)
|
||||
ensurePrevoteMatch(t, voteCh, height, round, blockID.Hash)
|
||||
|
||||
ensurePrecommit(voteCh, height, round)
|
||||
|
||||
m.AssertCalled(t, "ExtendVote", context.TODO(), &abci.RequestExtendVote{
|
||||
Height: height,
|
||||
Hash: blockID.Hash,
|
||||
})
|
||||
|
||||
m.AssertCalled(t, "VerifyVoteExtension", context.TODO(), &abci.RequestVerifyVoteExtension{
|
||||
Hash: blockID.Hash,
|
||||
ValidatorAddress: addr,
|
||||
Height: height,
|
||||
VoteExtension: []byte("extension"),
|
||||
})
|
||||
|
||||
signAddVotes(cs1, tmproto.PrecommitType, blockID.Hash, blockID.PartSetHeader, vss[1:]...)
|
||||
ensureNewRound(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()
|
||||
require.NoError(t, err)
|
||||
addr := pv.Address()
|
||||
m.AssertCalled(t, "VerifyVoteExtension", context.TODO(), &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) {
|
||||
m := abcimocks.NewApplication(t)
|
||||
m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{}, nil)
|
||||
m.On("ProcessProposal", mock.Anything, mock.Anything).Return(&abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil)
|
||||
m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{
|
||||
VoteExtension: []byte("extension"),
|
||||
}, nil)
|
||||
m.On("VerifyVoteExtension", mock.Anything, mock.Anything).Return(&abci.ResponseVerifyVoteExtension{
|
||||
Status: abci.ResponseVerifyVoteExtension_ACCEPT,
|
||||
}, nil)
|
||||
m.On("FinalizeBlock", mock.Anything, mock.Anything).Return(&abci.ResponseFinalizeBlock{}, nil).Maybe()
|
||||
m.On("Commit", mock.Anything, mock.Anything).Return(&abci.ResponseCommit{}, nil).Maybe()
|
||||
cs1, vss := randStateWithApp(4, m)
|
||||
height, round := cs1.Height, cs1.Round
|
||||
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
pv1, err := cs1.privValidator.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
addr := pv1.Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
startTestRound(cs1, cs1.Height, round)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
rs := cs1.GetRoundState()
|
||||
|
||||
blockID := types.BlockID{
|
||||
Hash: rs.ProposalBlock.Hash(),
|
||||
PartSetHeader: rs.ProposalBlockParts.Header(),
|
||||
}
|
||||
signAddVotes(cs1, tmproto.PrevoteType, blockID.Hash, blockID.PartSetHeader, vss[2:]...)
|
||||
ensurePrevoteMatch(t, voteCh, height, round, blockID.Hash)
|
||||
|
||||
ensurePrecommit(voteCh, height, round)
|
||||
|
||||
m.AssertCalled(t, "ExtendVote", context.TODO(), &abci.RequestExtendVote{
|
||||
Height: height,
|
||||
Hash: blockID.Hash,
|
||||
})
|
||||
|
||||
m.AssertCalled(t, "VerifyVoteExtension", context.TODO(), &abci.RequestVerifyVoteExtension{
|
||||
Hash: blockID.Hash,
|
||||
ValidatorAddress: addr,
|
||||
Height: height,
|
||||
VoteExtension: []byte("extension"),
|
||||
})
|
||||
|
||||
signAddVotes(cs1, tmproto.PrecommitType, blockID.Hash, blockID.PartSetHeader, vss[2:]...)
|
||||
ensureNewRound(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()
|
||||
require.NoError(t, err)
|
||||
addr = pv.Address()
|
||||
|
||||
m.AssertNotCalled(t, "VerifyVoteExtension", context.TODO(), &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
|
||||
// by 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) {
|
||||
// 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.NewApplication(t)
|
||||
m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{
|
||||
VoteExtension: voteExtensions[0],
|
||||
}, nil)
|
||||
m.On("ProcessProposal", mock.Anything, mock.Anything).Return(&abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil)
|
||||
|
||||
// capture the prepare proposal request.
|
||||
rpp := &abci.RequestPrepareProposal{}
|
||||
m.On("PrepareProposal", mock.Anything, mock.MatchedBy(func(r *abci.RequestPrepareProposal) bool {
|
||||
rpp = r
|
||||
return true
|
||||
})).Return(&abci.ResponsePrepareProposal{}, nil)
|
||||
|
||||
m.On("VerifyVoteExtension", mock.Anything, mock.Anything).Return(&abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_ACCEPT}, nil)
|
||||
m.On("Commit", mock.Anything, mock.Anything).Return(&abci.ResponseCommit{}, nil).Maybe()
|
||||
m.On("FinalizeBlock", mock.Anything, mock.Anything).Return(&abci.ResponseFinalizeBlock{}, nil)
|
||||
|
||||
cs1, vss := randStateWithApp(4, m)
|
||||
height, round := cs1.Height, cs1.Round
|
||||
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
pv1, err := cs1.privValidator.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
addr := pv1.Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
startTestRound(cs1, height, round)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
|
||||
rs := cs1.GetRoundState()
|
||||
blockID := types.BlockID{
|
||||
Hash: rs.ProposalBlock.Hash(),
|
||||
PartSetHeader: rs.ProposalBlockParts.Header(),
|
||||
}
|
||||
signAddVotes(cs1, tmproto.PrevoteType, blockID.Hash, blockID.PartSetHeader, vss[1:]...)
|
||||
|
||||
// create a precommit for each validator with the associated vote extension.
|
||||
for i, vs := range vss[1:] {
|
||||
signAddPrecommitWithExtension(t, cs1, blockID.Hash, blockID.PartSetHeader, voteExtensions[i+1], vs)
|
||||
}
|
||||
|
||||
ensurePrevote(voteCh, height, round)
|
||||
|
||||
// ensure that the height is committed.
|
||||
ensurePrecommitMatch(t, voteCh, height, round, blockID.Hash)
|
||||
incrementHeight(vss[1:]...)
|
||||
|
||||
height++
|
||||
round = 0
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
incrementRound(vss[1:]...)
|
||||
incrementRound(vss[1:]...)
|
||||
incrementRound(vss[1:]...)
|
||||
round = 3
|
||||
|
||||
blockID2 := types.BlockID{}
|
||||
signAddVotes(cs1, tmproto.PrecommitType, blockID2.Hash, blockID2.PartSetHeader, vss[1:]...)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
|
||||
// ensure that the proposer received the list of vote extensions from the
|
||||
// previous height.
|
||||
require.Len(t, rpp.LocalLastCommit.Votes, len(vss))
|
||||
for i := range vss {
|
||||
require.Equal(t, rpp.LocalLastCommit.Votes[i].VoteExtension, voteExtensions[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinalizeBlockCalled(t *testing.T) {
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
@@ -1444,6 +1668,10 @@ func TestFinalizeBlockCalled(t *testing.T) {
|
||||
Status: abci.ResponseProcessProposal_ACCEPT,
|
||||
}, nil)
|
||||
m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{}, nil)
|
||||
m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{}, nil)
|
||||
m.On("VerifyVoteExtension", mock.Anything, mock.Anything).Return(&abci.ResponseVerifyVoteExtension{
|
||||
Status: abci.ResponseVerifyVoteExtension_ACCEPT,
|
||||
}, nil)
|
||||
r := &abci.ResponseFinalizeBlock{AgreedAppData: []byte("the_hash")}
|
||||
m.On("FinalizeBlock", mock.Anything, mock.Anything).Return(r, nil).Maybe()
|
||||
m.On("Commit", mock.Anything, mock.Anything).Return(&abci.ResponseCommit{}, nil).Maybe()
|
||||
@@ -2090,3 +2318,15 @@ func subscribeUnBuffered(eventBus *types.EventBus, q tmpubsub.Query) <-chan tmpu
|
||||
}
|
||||
return sub.Out()
|
||||
}
|
||||
|
||||
func signAddPrecommitWithExtension(
|
||||
t *testing.T,
|
||||
cs *State,
|
||||
hash []byte,
|
||||
header types.PartSetHeader,
|
||||
extension []byte,
|
||||
stub *validatorStub) {
|
||||
v, err := stub.signVote(tmproto.PrecommitType, hash, header, extension)
|
||||
require.NoError(t, err, "failed to sign vote")
|
||||
addVotes(cs, v)
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ func makeVoteHR(t *testing.T, height int64, valIndex, round int32, privVals []ty
|
||||
}
|
||||
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
|
||||
return vote
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ func MakeCommitFromVoteSet(blockID types.BlockID, voteSet *types.VoteSet, valida
|
||||
return nil, err
|
||||
}
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
if _, err := voteSet.AddVote(vote); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -38,5 +38,6 @@ func MakeVote(
|
||||
}
|
||||
|
||||
v.Signature = vpb.Signature
|
||||
v.ExtensionSignature = vpb.ExtensionSignature
|
||||
return v, nil
|
||||
}
|
||||
|
||||
+29
-8
@@ -82,6 +82,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.
|
||||
@@ -276,12 +284,7 @@ func (pv *FilePV) Save() {
|
||||
// Reset resets all fields in the FilePV.
|
||||
// NOTE: Unsafe!
|
||||
func (pv *FilePV) Reset() {
|
||||
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()
|
||||
pv.Save()
|
||||
}
|
||||
|
||||
@@ -312,6 +315,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.
|
||||
@@ -322,11 +331,19 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
|
||||
if bytes.Equal(signBytes, lss.SignBytes) {
|
||||
vote.Signature = lss.Signature
|
||||
} else if timestamp, ok := checkVotesOnlyDifferByTimestamp(lss.SignBytes, signBytes); ok {
|
||||
// Compares the canonicalized votes (i.e. without vote extensions
|
||||
// or vote extension signatures).
|
||||
vote.Timestamp = timestamp
|
||||
vote.Signature = lss.Signature
|
||||
} else {
|
||||
err = fmt.Errorf("conflicting data")
|
||||
}
|
||||
|
||||
// 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 err
|
||||
}
|
||||
|
||||
@@ -337,6 +354,8 @@ func (pv *FilePV) signVote(chainID string, vote *tmproto.Vote) error {
|
||||
}
|
||||
pv.saveSigned(height, round, step, signBytes, sig)
|
||||
vote.Signature = sig
|
||||
vote.ExtensionSignature = extSig
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -396,8 +415,10 @@ func (pv *FilePV) saveSigned(height int64, round int32, step int8,
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
// 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) {
|
||||
var lastVote, newVote tmproto.CanonicalVote
|
||||
if err := protoio.UnmarshalDelimited(lastSignBytes, &lastVote); err != nil {
|
||||
|
||||
+92
-41
@@ -20,33 +20,21 @@ import (
|
||||
)
|
||||
|
||||
func TestGenLoadValidator(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tempKeyFile, err := os.CreateTemp("", "priv_validator_key_")
|
||||
require.Nil(t, err)
|
||||
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
|
||||
require.Nil(t, err)
|
||||
|
||||
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
|
||||
privVal, tempKeyFileName, tempStateFileName := newTestFilePV(t)
|
||||
|
||||
height := int64(100)
|
||||
privVal.LastSignState.Height = height
|
||||
privVal.Save()
|
||||
addr := privVal.GetAddress()
|
||||
|
||||
privVal = LoadFilePV(tempKeyFile.Name(), tempStateFile.Name())
|
||||
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
|
||||
assert.Equal(height, privVal.LastSignState.Height, "expected privval.LastHeight to have been saved")
|
||||
privVal = LoadFilePV(tempKeyFileName, tempStateFileName)
|
||||
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")
|
||||
}
|
||||
|
||||
func TestResetValidator(t *testing.T) {
|
||||
tempKeyFile, err := os.CreateTemp("", "priv_validator_key_")
|
||||
require.Nil(t, err)
|
||||
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
|
||||
require.Nil(t, err)
|
||||
|
||||
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
|
||||
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)
|
||||
@@ -56,8 +44,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("mychainid", vote.ToProto())
|
||||
vote := newVote(privVal.Key.Address, 0, height, round, voteType, blockID, nil)
|
||||
err := privVal.SignVote("mychainid", vote.ToProto())
|
||||
assert.NoError(t, err, "expected no error signing vote")
|
||||
|
||||
// priv val after signing is not same as empty
|
||||
@@ -158,12 +146,7 @@ func TestUnmarshalValidatorKey(t *testing.T) {
|
||||
func TestSignVote(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tempKeyFile, err := os.CreateTemp("", "priv_validator_key_")
|
||||
require.Nil(t, err)
|
||||
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
|
||||
require.Nil(t, err)
|
||||
|
||||
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
|
||||
privVal, _, _ := newTestFilePV(t)
|
||||
|
||||
randbytes := tmrand.Bytes(tmhash.Size)
|
||||
randbytes2 := tmrand.Bytes(tmhash.Size)
|
||||
@@ -177,9 +160,9 @@ 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("mychainid", v)
|
||||
err := privVal.SignVote("mychainid", v)
|
||||
assert.NoError(err, "expected no error signing vote")
|
||||
|
||||
// try to sign the same vote again; should be fine
|
||||
@@ -188,10 +171,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 {
|
||||
@@ -211,12 +194,7 @@ func TestSignVote(t *testing.T) {
|
||||
func TestSignProposal(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tempKeyFile, err := os.CreateTemp("", "priv_validator_key_")
|
||||
require.Nil(t, err)
|
||||
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
|
||||
require.Nil(t, err)
|
||||
|
||||
privVal := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
|
||||
privVal, _, _ := newTestFilePV(t)
|
||||
|
||||
randbytes := tmrand.Bytes(tmhash.Size)
|
||||
randbytes2 := tmrand.Bytes(tmhash.Size)
|
||||
@@ -230,7 +208,7 @@ func TestSignProposal(t *testing.T) {
|
||||
// sign a proposal for first time
|
||||
proposal := newProposal(height, round, block1)
|
||||
pbp := proposal.ToProto()
|
||||
err = privVal.SignProposal("mychainid", pbp)
|
||||
err := privVal.SignProposal("mychainid", pbp)
|
||||
assert.NoError(err, "expected no error signing proposal")
|
||||
|
||||
// try to sign the same proposal again; should be fine
|
||||
@@ -297,30 +275,91 @@ 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("mychainid", v)
|
||||
assert.NoError(t, err, "expected no error signing vote")
|
||||
|
||||
signBytes := types.VoteSignBytes(chainID, v)
|
||||
sig := v.Signature
|
||||
extSig := v.ExtensionSignature
|
||||
timeStamp := vote.Timestamp
|
||||
|
||||
// manipulate the timestamp. should get changed back
|
||||
v.Timestamp = v.Timestamp.Add(time.Millisecond)
|
||||
var emptySig []byte
|
||||
v.Signature = emptySig
|
||||
v.ExtensionSignature = emptySig
|
||||
err = privVal.SignVote("mychainid", v)
|
||||
assert.NoError(t, err, "expected no error on signing same vote")
|
||||
|
||||
assert.Equal(t, timeStamp, v.Timestamp)
|
||||
assert.Equal(t, signBytes, types.VoteSignBytes(chainID, v))
|
||||
assert.Equal(t, sig, v.Signature)
|
||||
assert.Equal(t, extSig, v.ExtensionSignature)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVoteExtensionsAreAlwaysSigned(t *testing.T) {
|
||||
privVal, _, _ := newTestFilePV(t)
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
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("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("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("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,
|
||||
@@ -329,6 +368,7 @@ func newVote(addr types.Address, idx int32, height int64, round int32,
|
||||
Type: typ,
|
||||
Timestamp: tmtime.Now(),
|
||||
BlockID: blockID,
|
||||
Extension: extension,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,3 +380,14 @@ func newProposal(height int64, round int32, blockID types.BlockID) *types.Propos
|
||||
Timestamp: tmtime.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
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 := GenFilePV(tempKeyFile.Name(), tempStateFile.Name())
|
||||
|
||||
return privVal, tempKeyFile.Name(), tempStateFile.Name()
|
||||
}
|
||||
|
||||
+8
-13
@@ -22,19 +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,
|
||||
Extension: []byte("extension"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +79,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}, "1a760a74080110031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0608f49a8ded0532146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb03"},
|
||||
{"Vote Response", &privproto.SignedVoteResponse{Vote: *votepb, Error: nil}, "22760a74080110031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0608f49a8ded0532146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb03"},
|
||||
{"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"},
|
||||
|
||||
@@ -30,6 +30,8 @@ service ABCI {
|
||||
returns (ResponseApplySnapshotChunk);
|
||||
rpc PrepareProposal(RequestPrepareProposal) returns (ResponsePrepareProposal);
|
||||
rpc ProcessProposal(RequestProcessProposal) returns (ResponseProcessProposal);
|
||||
rpc ExtendVote(RequestExtendVote) returns (ResponseExtendVote);
|
||||
rpc VerifyVoteExtension(RequestVerifyVoteExtension) returns (ResponseVerifyVoteExtension);
|
||||
rpc FinalizeBlock(RequestFinalizeBlock) returns (ResponseFinalizeBlock);
|
||||
}
|
||||
|
||||
@@ -38,20 +40,22 @@ service ABCI {
|
||||
|
||||
message Request {
|
||||
oneof value {
|
||||
RequestEcho echo = 1;
|
||||
RequestFlush flush = 2;
|
||||
RequestInfo info = 3;
|
||||
RequestInitChain init_chain = 5;
|
||||
RequestQuery query = 6;
|
||||
RequestCheckTx check_tx = 8;
|
||||
RequestCommit commit = 11;
|
||||
RequestListSnapshots list_snapshots = 12;
|
||||
RequestOfferSnapshot offer_snapshot = 13;
|
||||
RequestLoadSnapshotChunk load_snapshot_chunk = 14;
|
||||
RequestApplySnapshotChunk apply_snapshot_chunk = 15;
|
||||
RequestPrepareProposal prepare_proposal = 16;
|
||||
RequestProcessProposal process_proposal = 17;
|
||||
RequestFinalizeBlock finalize_block = 20;
|
||||
RequestEcho echo = 1;
|
||||
RequestFlush flush = 2;
|
||||
RequestInfo info = 3;
|
||||
RequestInitChain init_chain = 5;
|
||||
RequestQuery query = 6;
|
||||
RequestCheckTx check_tx = 8;
|
||||
RequestCommit commit = 11;
|
||||
RequestListSnapshots list_snapshots = 12;
|
||||
RequestOfferSnapshot offer_snapshot = 13;
|
||||
RequestLoadSnapshotChunk load_snapshot_chunk = 14;
|
||||
RequestApplySnapshotChunk apply_snapshot_chunk = 15;
|
||||
RequestPrepareProposal prepare_proposal = 16;
|
||||
RequestProcessProposal process_proposal = 17;
|
||||
RequestExtendVote extend_vote = 18;
|
||||
RequestVerifyVoteExtension verify_vote_extension = 19;
|
||||
RequestFinalizeBlock finalize_block = 20;
|
||||
}
|
||||
reserved 4, 7, 9, 10; // SetOption, BeginBlock, DeliverTx, EndBlock
|
||||
}
|
||||
@@ -149,6 +153,20 @@ message RequestProcessProposal {
|
||||
bytes proposer_address = 8;
|
||||
}
|
||||
|
||||
// Extends a vote with application-side injection
|
||||
message RequestExtendVote {
|
||||
bytes hash = 1;
|
||||
int64 height = 2;
|
||||
}
|
||||
|
||||
// Verify the vote extension
|
||||
message RequestVerifyVoteExtension {
|
||||
bytes hash = 1;
|
||||
bytes validator_address = 2;
|
||||
int64 height = 3;
|
||||
bytes vote_extension = 4;
|
||||
}
|
||||
|
||||
message RequestFinalizeBlock {
|
||||
repeated bytes txs = 1;
|
||||
CommitInfo decided_last_commit = 2 [(gogoproto.nullable) = false];
|
||||
@@ -167,21 +185,23 @@ message RequestFinalizeBlock {
|
||||
|
||||
message Response {
|
||||
oneof value {
|
||||
ResponseException exception = 1;
|
||||
ResponseEcho echo = 2;
|
||||
ResponseFlush flush = 3;
|
||||
ResponseInfo info = 4;
|
||||
ResponseInitChain init_chain = 6;
|
||||
ResponseQuery query = 7;
|
||||
ResponseCheckTx check_tx = 9;
|
||||
ResponseCommit commit = 12;
|
||||
ResponseListSnapshots list_snapshots = 13;
|
||||
ResponseOfferSnapshot offer_snapshot = 14;
|
||||
ResponseLoadSnapshotChunk load_snapshot_chunk = 15;
|
||||
ResponseApplySnapshotChunk apply_snapshot_chunk = 16;
|
||||
ResponsePrepareProposal prepare_proposal = 17;
|
||||
ResponseProcessProposal process_proposal = 18;
|
||||
ResponseFinalizeBlock finalize_block = 21;
|
||||
ResponseException exception = 1;
|
||||
ResponseEcho echo = 2;
|
||||
ResponseFlush flush = 3;
|
||||
ResponseInfo info = 4;
|
||||
ResponseInitChain init_chain = 6;
|
||||
ResponseQuery query = 7;
|
||||
ResponseCheckTx check_tx = 9;
|
||||
ResponseCommit commit = 12;
|
||||
ResponseListSnapshots list_snapshots = 13;
|
||||
ResponseOfferSnapshot offer_snapshot = 14;
|
||||
ResponseLoadSnapshotChunk load_snapshot_chunk = 15;
|
||||
ResponseApplySnapshotChunk apply_snapshot_chunk = 16;
|
||||
ResponsePrepareProposal prepare_proposal = 17;
|
||||
ResponseProcessProposal process_proposal = 18;
|
||||
ResponseExtendVote extend_vote = 19;
|
||||
ResponseVerifyVoteExtension verify_vote_extension = 20;
|
||||
ResponseFinalizeBlock finalize_block = 21;
|
||||
}
|
||||
reserved 5, 8, 10, 11; // SetOption, BeginBlock, DeliverTx, EndBlock
|
||||
}
|
||||
@@ -299,6 +319,20 @@ message ResponseProcessProposal {
|
||||
}
|
||||
}
|
||||
|
||||
message ResponseExtendVote {
|
||||
bytes vote_extension = 1;
|
||||
}
|
||||
|
||||
message ResponseVerifyVoteExtension {
|
||||
VerifyStatus status = 1;
|
||||
|
||||
enum VerifyStatus {
|
||||
UNKNOWN = 0;
|
||||
ACCEPT = 1;
|
||||
REJECT = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ResponseFinalizeBlock {
|
||||
// set of block events emmitted as part of executing the block
|
||||
repeated Event events = 1
|
||||
@@ -323,6 +357,9 @@ 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 {
|
||||
// The round at which the block proposer decided in the previous height.
|
||||
int32 round = 1;
|
||||
@@ -377,29 +414,29 @@ message TxResult {
|
||||
//----------------------------------------
|
||||
// Blockchain Types
|
||||
|
||||
// Validator
|
||||
message Validator {
|
||||
bytes address = 1; // The first 20 bytes of SHA256(public key)
|
||||
// PubKey pub_key = 2 [(gogoproto.nullable)=false];
|
||||
int64 power = 3; // The voting power
|
||||
}
|
||||
|
||||
// ValidatorUpdate
|
||||
message ValidatorUpdate {
|
||||
tendermint.crypto.PublicKey pub_key = 1 [(gogoproto.nullable) = false];
|
||||
int64 power = 2;
|
||||
}
|
||||
|
||||
// VoteInfo
|
||||
message VoteInfo {
|
||||
Validator validator = 1 [(gogoproto.nullable) = false];
|
||||
bool signed_last_block = 2;
|
||||
}
|
||||
|
||||
message ExtendedVoteInfo {
|
||||
Validator validator = 1 [(gogoproto.nullable) = false];
|
||||
bool signed_last_block = 2;
|
||||
bytes vote_extension = 3; // Reserved for future use
|
||||
// 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 {
|
||||
|
||||
@@ -27,7 +27,6 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
// PublicKey defines the keys available for use with Tendermint Validators
|
||||
type PublicKey struct {
|
||||
// Types that are valid to be assigned to Sum:
|
||||
//
|
||||
// *PublicKey_Ed25519
|
||||
// *PublicKey_Secp256K1
|
||||
Sum isPublicKey_Sum `protobuf_oneof:"sum"`
|
||||
|
||||
@@ -68,7 +68,6 @@ func (m *Txs) GetTxs() [][]byte {
|
||||
|
||||
type Message struct {
|
||||
// Types that are valid to be assigned to Sum:
|
||||
//
|
||||
// *Message_Txs
|
||||
Sum isMessage_Sum `protobuf_oneof:"sum"`
|
||||
}
|
||||
|
||||
@@ -158,7 +158,6 @@ func (m *PacketMsg) GetData() []byte {
|
||||
|
||||
type Packet struct {
|
||||
// Types that are valid to be assigned to Sum:
|
||||
//
|
||||
// *Packet_PacketPing
|
||||
// *Packet_PacketPong
|
||||
// *Packet_PacketMsg
|
||||
|
||||
@@ -24,7 +24,6 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type Message struct {
|
||||
// Types that are valid to be assigned to Sum:
|
||||
//
|
||||
// *Message_SnapshotsRequest
|
||||
// *Message_SnapshotsResponse
|
||||
// *Message_ChunkRequest
|
||||
|
||||
@@ -225,12 +225,13 @@ 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"`
|
||||
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"`
|
||||
}
|
||||
|
||||
func (m *CanonicalVote) Reset() { *m = CanonicalVote{} }
|
||||
@@ -308,48 +309,130 @@ func (m *CanonicalVote) GetChainID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *CanonicalVote) GetVoteExtension() *VoteExtensionToSign {
|
||||
if m != nil {
|
||||
return m.VoteExtension
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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.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{
|
||||
// 487 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x53, 0x3d, 0x6f, 0xd3, 0x40,
|
||||
0x18, 0xce, 0xa5, 0x4e, 0xe2, 0x5c, 0x1b, 0x08, 0xa7, 0xaa, 0xb2, 0x22, 0x64, 0x5b, 0x1e, 0x90,
|
||||
0x59, 0x6c, 0xa9, 0x1d, 0xd8, 0x5d, 0x06, 0x82, 0x40, 0x94, 0x6b, 0xd5, 0x81, 0x25, 0xba, 0xd8,
|
||||
0x87, 0x6d, 0xe1, 0xf8, 0x4e, 0xf6, 0x65, 0xe8, 0xc2, 0x6f, 0xe8, 0xef, 0xe0, 0x97, 0x74, 0xec,
|
||||
0x08, 0x4b, 0x40, 0xce, 0x1f, 0x41, 0x77, 0x4e, 0xec, 0xa8, 0x01, 0x16, 0x10, 0xcb, 0xe9, 0xfd,
|
||||
0x78, 0xee, 0x79, 0x1f, 0x3d, 0xaf, 0x5e, 0x68, 0x0b, 0x9a, 0x47, 0xb4, 0x58, 0xa4, 0xb9, 0xf0,
|
||||
0xc5, 0x0d, 0xa7, 0xa5, 0x1f, 0x92, 0x9c, 0xe5, 0x69, 0x48, 0x32, 0x8f, 0x17, 0x4c, 0x30, 0x34,
|
||||
0x6e, 0x11, 0x9e, 0x42, 0x4c, 0x8e, 0x63, 0x16, 0x33, 0xd5, 0xf4, 0x65, 0x54, 0xe3, 0x26, 0x4f,
|
||||
0xf7, 0x98, 0xd4, 0xbb, 0xe9, 0x5a, 0x31, 0x63, 0x71, 0x46, 0x7d, 0x95, 0xcd, 0x97, 0x1f, 0x7d,
|
||||
0x91, 0x2e, 0x68, 0x29, 0xc8, 0x82, 0xd7, 0x00, 0xe7, 0x33, 0x1c, 0x9f, 0x6f, 0x27, 0x07, 0x19,
|
||||
0x0b, 0x3f, 0x4d, 0x5f, 0x22, 0x04, 0xb5, 0x84, 0x94, 0x89, 0x01, 0x6c, 0xe0, 0x1e, 0x61, 0x15,
|
||||
0xa3, 0x6b, 0xf8, 0x98, 0x93, 0x42, 0xcc, 0x4a, 0x2a, 0x66, 0x09, 0x25, 0x11, 0x2d, 0x8c, 0xae,
|
||||
0x0d, 0xdc, 0xc3, 0x53, 0xd7, 0x7b, 0x28, 0xd4, 0x6b, 0x08, 0x2f, 0x48, 0x21, 0x2e, 0xa9, 0x78,
|
||||
0xa5, 0xf0, 0x81, 0x76, 0xb7, 0xb2, 0x3a, 0x78, 0xc4, 0x77, 0x8b, 0x4e, 0x00, 0x4f, 0x7e, 0x0d,
|
||||
0x47, 0xc7, 0xb0, 0x27, 0x98, 0x20, 0x99, 0x92, 0x31, 0xc2, 0x75, 0xd2, 0x68, 0xeb, 0xb6, 0xda,
|
||||
0x9c, 0x6f, 0x5d, 0xf8, 0xa4, 0x25, 0x29, 0x18, 0x67, 0x25, 0xc9, 0xd0, 0x19, 0xd4, 0xa4, 0x1c,
|
||||
0xf5, 0xfd, 0xd1, 0xa9, 0xb5, 0x2f, 0xf3, 0x32, 0x8d, 0x73, 0x1a, 0xbd, 0x2d, 0xe3, 0xab, 0x1b,
|
||||
0x4e, 0xb1, 0x02, 0xa3, 0x13, 0xd8, 0x4f, 0x68, 0x1a, 0x27, 0x42, 0x0d, 0x18, 0xe3, 0x4d, 0x26,
|
||||
0xc5, 0x14, 0x6c, 0x99, 0x47, 0xc6, 0x81, 0x2a, 0xd7, 0x09, 0x7a, 0x0e, 0x87, 0x9c, 0x65, 0xb3,
|
||||
0xba, 0xa3, 0xd9, 0xc0, 0x3d, 0x08, 0x8e, 0xaa, 0x95, 0xa5, 0x5f, 0xbc, 0x7b, 0x83, 0x65, 0x0d,
|
||||
0xeb, 0x9c, 0x65, 0x2a, 0x42, 0xaf, 0xa1, 0x3e, 0x97, 0xf6, 0xce, 0xd2, 0xc8, 0xe8, 0x29, 0xe3,
|
||||
0x9c, 0x3f, 0x18, 0xb7, 0xd9, 0x44, 0x70, 0x58, 0xad, 0xac, 0xc1, 0x26, 0xc1, 0x03, 0x45, 0x30,
|
||||
0x8d, 0x50, 0x00, 0x87, 0xcd, 0x1a, 0x8d, 0xbe, 0x22, 0x9b, 0x78, 0xf5, 0xa2, 0xbd, 0xed, 0xa2,
|
||||
0xbd, 0xab, 0x2d, 0x22, 0xd0, 0xa5, 0xef, 0xb7, 0xdf, 0x2d, 0x80, 0xdb, 0x6f, 0xe8, 0x19, 0xd4,
|
||||
0xc3, 0x84, 0xa4, 0xb9, 0xd4, 0x33, 0xb0, 0x81, 0x3b, 0xac, 0x67, 0x9d, 0xcb, 0x9a, 0x9c, 0xa5,
|
||||
0x9a, 0xd3, 0xc8, 0xf9, 0xd2, 0x85, 0xa3, 0x46, 0xd6, 0x35, 0x13, 0xf4, 0x7f, 0xf8, 0xba, 0x6b,
|
||||
0x96, 0xf6, 0x2f, 0xcd, 0xea, 0xfd, 0xbd, 0x59, 0xfd, 0xdf, 0x9b, 0x15, 0xbc, 0xbf, 0xab, 0x4c,
|
||||
0x70, 0x5f, 0x99, 0xe0, 0x47, 0x65, 0x82, 0xdb, 0xb5, 0xd9, 0xb9, 0x5f, 0x9b, 0x9d, 0xaf, 0x6b,
|
||||
0xb3, 0xf3, 0xe1, 0x45, 0x9c, 0x8a, 0x64, 0x39, 0xf7, 0x42, 0xb6, 0xf0, 0x77, 0x0f, 0xb6, 0x0d,
|
||||
0xeb, 0xc3, 0x7e, 0x78, 0xcc, 0xf3, 0xbe, 0xaa, 0x9f, 0xfd, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x6d,
|
||||
0xdd, 0x12, 0x5d, 0x31, 0x04, 0x00, 0x00,
|
||||
// 550 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0x4d, 0x6f, 0xd3, 0x40,
|
||||
0x10, 0x8d, 0xd3, 0x34, 0x1f, 0x9b, 0xa6, 0x84, 0x55, 0x55, 0x99, 0xa8, 0xb2, 0x2d, 0x4b, 0x20,
|
||||
0x73, 0xb1, 0xa5, 0xf4, 0xc0, 0xdd, 0x05, 0x89, 0xa0, 0x22, 0xca, 0x36, 0xea, 0x81, 0x8b, 0xb5,
|
||||
0xb1, 0x17, 0xdb, 0xc2, 0xf1, 0x5a, 0xf6, 0xa6, 0xa2, 0x17, 0xf8, 0x0b, 0xfd, 0x59, 0x3d, 0xf6,
|
||||
0x08, 0x97, 0x80, 0x9c, 0x3f, 0xc1, 0x11, 0xed, 0x3a, 0xb1, 0x4d, 0x03, 0x48, 0x08, 0xc4, 0xc5,
|
||||
0x9a, 0x79, 0xf3, 0x3c, 0xf3, 0xf6, 0x8d, 0x76, 0x81, 0xc6, 0x48, 0xec, 0x91, 0x74, 0x1e, 0xc6,
|
||||
0xcc, 0x62, 0x57, 0x09, 0xc9, 0x2c, 0x17, 0xc7, 0x34, 0x0e, 0x5d, 0x1c, 0x99, 0x49, 0x4a, 0x19,
|
||||
0x85, 0xc3, 0x8a, 0x61, 0x0a, 0xc6, 0xe8, 0xc0, 0xa7, 0x3e, 0x15, 0x45, 0x8b, 0x47, 0x05, 0x6f,
|
||||
0x74, 0xb4, 0xd5, 0x49, 0x7c, 0xd7, 0x55, 0xd5, 0xa7, 0xd4, 0x8f, 0x88, 0x25, 0xb2, 0xd9, 0xe2,
|
||||
0xad, 0xc5, 0xc2, 0x39, 0xc9, 0x18, 0x9e, 0x27, 0x05, 0x41, 0xff, 0x00, 0x86, 0x27, 0x9b, 0xc9,
|
||||
0x76, 0x44, 0xdd, 0x77, 0x93, 0xa7, 0x10, 0x82, 0x56, 0x80, 0xb3, 0x40, 0x96, 0x34, 0xc9, 0xd8,
|
||||
0x43, 0x22, 0x86, 0x17, 0xe0, 0x5e, 0x82, 0x53, 0xe6, 0x64, 0x84, 0x39, 0x01, 0xc1, 0x1e, 0x49,
|
||||
0xe5, 0xa6, 0x26, 0x19, 0xfd, 0xb1, 0x61, 0xde, 0x15, 0x6a, 0x96, 0x0d, 0xcf, 0x70, 0xca, 0xce,
|
||||
0x09, 0x7b, 0x2e, 0xf8, 0x76, 0xeb, 0x66, 0xa9, 0x36, 0xd0, 0x20, 0xa9, 0x83, 0xba, 0x0d, 0x0e,
|
||||
0x7f, 0x4e, 0x87, 0x07, 0x60, 0x97, 0x51, 0x86, 0x23, 0x21, 0x63, 0x80, 0x8a, 0xa4, 0xd4, 0xd6,
|
||||
0xac, 0xb4, 0xe9, 0x9f, 0x9b, 0xe0, 0x7e, 0xd5, 0x24, 0xa5, 0x09, 0xcd, 0x70, 0x04, 0x8f, 0x41,
|
||||
0x8b, 0xcb, 0x11, 0xbf, 0xef, 0x8f, 0xd5, 0x6d, 0x99, 0xe7, 0xa1, 0x1f, 0x13, 0xef, 0x65, 0xe6,
|
||||
0x4f, 0xaf, 0x12, 0x82, 0x04, 0x19, 0x1e, 0x82, 0x76, 0x40, 0x42, 0x3f, 0x60, 0x62, 0xc0, 0x10,
|
||||
0xad, 0x33, 0x2e, 0x26, 0xa5, 0x8b, 0xd8, 0x93, 0x77, 0x04, 0x5c, 0x24, 0xf0, 0x31, 0xe8, 0x25,
|
||||
0x34, 0x72, 0x8a, 0x4a, 0x4b, 0x93, 0x8c, 0x1d, 0x7b, 0x2f, 0x5f, 0xaa, 0xdd, 0xb3, 0x57, 0xa7,
|
||||
0x88, 0x63, 0xa8, 0x9b, 0xd0, 0x48, 0x44, 0xf0, 0x05, 0xe8, 0xce, 0xb8, 0xbd, 0x4e, 0xe8, 0xc9,
|
||||
0xbb, 0xc2, 0x38, 0xfd, 0x37, 0xc6, 0xad, 0x37, 0x61, 0xf7, 0xf3, 0xa5, 0xda, 0x59, 0x27, 0xa8,
|
||||
0x23, 0x1a, 0x4c, 0x3c, 0x68, 0x83, 0x5e, 0xb9, 0x46, 0xb9, 0x2d, 0x9a, 0x8d, 0xcc, 0x62, 0xd1,
|
||||
0xe6, 0x66, 0xd1, 0xe6, 0x74, 0xc3, 0xb0, 0xbb, 0xdc, 0xf7, 0xeb, 0x2f, 0xaa, 0x84, 0xaa, 0xdf,
|
||||
0xe0, 0x23, 0xd0, 0x75, 0x03, 0x1c, 0xc6, 0x5c, 0x4f, 0x47, 0x93, 0x8c, 0x5e, 0x31, 0xeb, 0x84,
|
||||
0x63, 0x7c, 0x96, 0x28, 0x4e, 0x3c, 0xfd, 0x5b, 0x13, 0x0c, 0x4a, 0x59, 0x17, 0x94, 0x91, 0xff,
|
||||
0xe1, 0x6b, 0xdd, 0xac, 0xd6, 0xbf, 0x34, 0x6b, 0xf7, 0xef, 0xcd, 0x6a, 0xff, 0xda, 0x2c, 0x78,
|
||||
0x0a, 0xf6, 0x2f, 0x29, 0x23, 0x0e, 0x79, 0xcf, 0x48, 0x9c, 0x85, 0x34, 0x16, 0xd6, 0xf6, 0xc7,
|
||||
0x0f, 0xb7, 0xd5, 0x73, 0x2b, 0x9f, 0x6d, 0x68, 0x53, 0xca, 0x3d, 0x43, 0x83, 0xcb, 0x3a, 0xa8,
|
||||
0x7f, 0xac, 0x5d, 0x8d, 0x1f, 0xe8, 0xf0, 0x08, 0xf4, 0xaa, 0x11, 0xc5, 0x2d, 0xad, 0x80, 0x3f,
|
||||
0xf4, 0xfa, 0x41, 0xed, 0x6c, 0xdc, 0xeb, 0x5e, 0x79, 0x1c, 0xfb, 0xf5, 0x4d, 0xae, 0x48, 0xb7,
|
||||
0xb9, 0x22, 0x7d, 0xcd, 0x15, 0xe9, 0x7a, 0xa5, 0x34, 0x6e, 0x57, 0x4a, 0xe3, 0xd3, 0x4a, 0x69,
|
||||
0xbc, 0x79, 0xe2, 0x87, 0x2c, 0x58, 0xcc, 0x4c, 0x97, 0xce, 0xad, 0xfa, 0xfb, 0x53, 0x85, 0xc5,
|
||||
0x3b, 0x75, 0xf7, 0x6d, 0x9a, 0xb5, 0x05, 0x7e, 0xfc, 0x3d, 0x00, 0x00, 0xff, 0xff, 0x59, 0x81,
|
||||
0xfb, 0xaf, 0x00, 0x05, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *CanonicalBlockID) Marshal() (dAtA []byte, err error) {
|
||||
@@ -519,6 +602,18 @@ 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)
|
||||
@@ -526,12 +621,12 @@ func (m *CanonicalVote) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0x32
|
||||
}
|
||||
n4, err4 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):])
|
||||
if err4 != nil {
|
||||
return 0, err4
|
||||
n5, err5 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):])
|
||||
if err5 != nil {
|
||||
return 0, err5
|
||||
}
|
||||
i -= n4
|
||||
i = encodeVarintCanonical(dAtA, i, uint64(n4))
|
||||
i -= n5
|
||||
i = encodeVarintCanonical(dAtA, i, uint64(n5))
|
||||
i--
|
||||
dAtA[i] = 0x2a
|
||||
if m.BlockID != nil {
|
||||
@@ -566,6 +661,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
|
||||
@@ -664,6 +808,33 @@ func (m *CanonicalVote) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovCanonical(uint64(l))
|
||||
}
|
||||
if m.VoteExtension != nil {
|
||||
l = m.VoteExtension.Size()
|
||||
n += 1 + l + sovCanonical(uint64(l))
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1271,6 +1442,178 @@ 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)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCanonical
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
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 := skipCanonical(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthCanonical
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Extension = append(m.Extension[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Extension == nil {
|
||||
m.Extension = []byte{}
|
||||
}
|
||||
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
|
||||
skippy, err := skipCanonical(dAtA[iNdEx:])
|
||||
|
||||
@@ -34,4 +34,14 @@ message CanonicalVote {
|
||||
CanonicalBlockID block_id = 4 [(gogoproto.customname) = "BlockID"];
|
||||
google.protobuf.Timestamp timestamp = 5 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
string chain_id = 6 [(gogoproto.customname) = "ChainID"];
|
||||
VoteExtensionToSign vote_extension = 7;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
+685
-106
@@ -473,7 +473,15 @@ type Vote struct {
|
||||
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"`
|
||||
// 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{} }
|
||||
@@ -565,6 +573,119 @@ func (m *Vote) GetSignature() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Vote) GetExtension() []byte {
|
||||
if m != nil {
|
||||
return m.Extension
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Vote) GetExtensionSignature() []byte {
|
||||
if m != nil {
|
||||
return m.ExtensionSignature
|
||||
}
|
||||
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 {
|
||||
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 nil
|
||||
}
|
||||
|
||||
// Commit contains the evidence that a block was committed by a set of validators.
|
||||
type Commit struct {
|
||||
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
|
||||
@@ -577,7 +698,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{6}
|
||||
return fileDescriptor_d3a6e55e2345de56, []int{8}
|
||||
}
|
||||
func (m *Commit) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -636,17 +757,18 @@ 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"`
|
||||
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"`
|
||||
}
|
||||
|
||||
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{7}
|
||||
return fileDescriptor_d3a6e55e2345de56, []int{9}
|
||||
}
|
||||
func (m *CommitSig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -703,6 +825,13 @@ 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"`
|
||||
@@ -717,7 +846,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{8}
|
||||
return fileDescriptor_d3a6e55e2345de56, []int{10}
|
||||
}
|
||||
func (m *Proposal) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -804,7 +933,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{9}
|
||||
return fileDescriptor_d3a6e55e2345de56, []int{11}
|
||||
}
|
||||
func (m *SignedHeader) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -856,7 +985,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{10}
|
||||
return fileDescriptor_d3a6e55e2345de56, []int{12}
|
||||
}
|
||||
func (m *LightBlock) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -910,7 +1039,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{11}
|
||||
return fileDescriptor_d3a6e55e2345de56, []int{13}
|
||||
}
|
||||
func (m *BlockMeta) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -978,7 +1107,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{12}
|
||||
return fileDescriptor_d3a6e55e2345de56, []int{14}
|
||||
}
|
||||
func (m *TxProof) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1037,6 +1166,8 @@ 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")
|
||||
@@ -1049,90 +1180,97 @@ func init() {
|
||||
func init() { proto.RegisterFile("tendermint/types/types.proto", fileDescriptor_d3a6e55e2345de56) }
|
||||
|
||||
var fileDescriptor_d3a6e55e2345de56 = []byte{
|
||||
// 1314 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x4f, 0x6f, 0x1b, 0x45,
|
||||
0x14, 0xcf, 0xda, 0x9b, 0xd8, 0x7e, 0xb6, 0x13, 0x67, 0x95, 0xb6, 0xae, 0xdb, 0x38, 0x2b, 0x23,
|
||||
0x20, 0x2d, 0x68, 0x53, 0x52, 0xc4, 0x9f, 0x03, 0x07, 0xdb, 0x49, 0x5b, 0xab, 0x89, 0x63, 0xd6,
|
||||
0x6e, 0x11, 0x5c, 0x56, 0x6b, 0xef, 0xd4, 0x5e, 0xba, 0xde, 0x59, 0xed, 0x8c, 0x43, 0xd2, 0x4f,
|
||||
0x80, 0x72, 0xea, 0x89, 0x5b, 0x4e, 0x70, 0xe0, 0xce, 0x17, 0x40, 0x9c, 0x7a, 0xec, 0x0d, 0x2e,
|
||||
0x14, 0x94, 0x4a, 0x88, 0x8f, 0x81, 0xe6, 0x8f, 0xd7, 0xeb, 0x38, 0x86, 0xaa, 0xaa, 0xb8, 0x58,
|
||||
0x3b, 0xef, 0xfd, 0xde, 0xcc, 0x7b, 0xbf, 0xf7, 0x9b, 0x3f, 0x86, 0xeb, 0x14, 0xf9, 0x0e, 0x0a,
|
||||
0x87, 0xae, 0x4f, 0xb7, 0xe8, 0x71, 0x80, 0x88, 0xf8, 0x35, 0x82, 0x10, 0x53, 0xac, 0x15, 0x26,
|
||||
0x5e, 0x83, 0xdb, 0x4b, 0x6b, 0x7d, 0xdc, 0xc7, 0xdc, 0xb9, 0xc5, 0xbe, 0x04, 0xae, 0xb4, 0xd1,
|
||||
0xc7, 0xb8, 0xef, 0xa1, 0x2d, 0x3e, 0xea, 0x8e, 0x1e, 0x6d, 0x51, 0x77, 0x88, 0x08, 0xb5, 0x87,
|
||||
0x81, 0x04, 0xac, 0xc7, 0x96, 0xe9, 0x85, 0xc7, 0x01, 0xc5, 0x0c, 0x8b, 0x1f, 0x49, 0x77, 0x39,
|
||||
0xe6, 0x3e, 0x44, 0x21, 0x71, 0xb1, 0x1f, 0xcf, 0xa3, 0xa4, 0xcf, 0x64, 0x79, 0x68, 0x7b, 0xae,
|
||||
0x63, 0x53, 0x1c, 0x0a, 0x44, 0xe5, 0x53, 0xc8, 0xb7, 0xec, 0x90, 0xb6, 0x11, 0xbd, 0x87, 0x6c,
|
||||
0x07, 0x85, 0xda, 0x1a, 0x2c, 0x52, 0x4c, 0x6d, 0xaf, 0xa8, 0xe8, 0xca, 0x66, 0xde, 0x14, 0x03,
|
||||
0x4d, 0x03, 0x75, 0x60, 0x93, 0x41, 0x31, 0xa1, 0x2b, 0x9b, 0x39, 0x93, 0x7f, 0x57, 0x06, 0xa0,
|
||||
0xb2, 0x50, 0x16, 0xe1, 0xfa, 0x0e, 0x3a, 0x1a, 0x47, 0xf0, 0x01, 0xb3, 0x76, 0x8f, 0x29, 0x22,
|
||||
0x32, 0x44, 0x0c, 0xb4, 0x0f, 0x61, 0x91, 0xe7, 0x5f, 0x4c, 0xea, 0xca, 0x66, 0x76, 0xbb, 0x68,
|
||||
0xc4, 0x88, 0x12, 0xf5, 0x19, 0x2d, 0xe6, 0xaf, 0xa9, 0xcf, 0x5e, 0x6c, 0x2c, 0x98, 0x02, 0x5c,
|
||||
0xf1, 0x20, 0x55, 0xf3, 0x70, 0xef, 0x71, 0x63, 0x27, 0x4a, 0x44, 0x99, 0x24, 0xa2, 0xed, 0xc3,
|
||||
0x4a, 0x60, 0x87, 0xd4, 0x22, 0x88, 0x5a, 0x03, 0x5e, 0x05, 0x5f, 0x34, 0xbb, 0xbd, 0x61, 0x9c,
|
||||
0xef, 0x83, 0x31, 0x55, 0xac, 0x5c, 0x25, 0x1f, 0xc4, 0x8d, 0x95, 0xbf, 0x54, 0x58, 0x92, 0x64,
|
||||
0x7c, 0x06, 0x29, 0x49, 0x2b, 0x5f, 0x30, 0xbb, 0xbd, 0x1e, 0x9f, 0x51, 0xba, 0x8c, 0x3a, 0xf6,
|
||||
0x09, 0xf2, 0xc9, 0x88, 0xc8, 0xf9, 0xc6, 0x31, 0xda, 0x3b, 0x90, 0xee, 0x0d, 0x6c, 0xd7, 0xb7,
|
||||
0x5c, 0x87, 0x67, 0x94, 0xa9, 0x65, 0xcf, 0x5e, 0x6c, 0xa4, 0xea, 0xcc, 0xd6, 0xd8, 0x31, 0x53,
|
||||
0xdc, 0xd9, 0x70, 0xb4, 0xcb, 0xb0, 0x34, 0x40, 0x6e, 0x7f, 0x40, 0x39, 0x2d, 0x49, 0x53, 0x8e,
|
||||
0xb4, 0x4f, 0x40, 0x65, 0x82, 0x28, 0xaa, 0x7c, 0xed, 0x92, 0x21, 0xd4, 0x62, 0x8c, 0xd5, 0x62,
|
||||
0x74, 0xc6, 0x6a, 0xa9, 0xa5, 0xd9, 0xc2, 0x4f, 0xff, 0xd8, 0x50, 0x4c, 0x1e, 0xa1, 0xd5, 0x21,
|
||||
0xef, 0xd9, 0x84, 0x5a, 0x5d, 0x46, 0x1b, 0x5b, 0x7e, 0x91, 0x4f, 0x71, 0x75, 0x96, 0x10, 0x49,
|
||||
0xac, 0x4c, 0x3d, 0xcb, 0xa2, 0x84, 0xc9, 0xd1, 0x36, 0xa1, 0xc0, 0x27, 0xe9, 0xe1, 0xe1, 0xd0,
|
||||
0xa5, 0x16, 0xe7, 0x7d, 0x89, 0xf3, 0xbe, 0xcc, 0xec, 0x75, 0x6e, 0xbe, 0xc7, 0x3a, 0x70, 0x0d,
|
||||
0x32, 0x8e, 0x4d, 0x6d, 0x01, 0x49, 0x71, 0x48, 0x9a, 0x19, 0xb8, 0xf3, 0x5d, 0x58, 0x89, 0x54,
|
||||
0x47, 0x04, 0x24, 0x2d, 0x66, 0x99, 0x98, 0x39, 0xf0, 0x16, 0xac, 0xf9, 0xe8, 0x88, 0x5a, 0xe7,
|
||||
0xd1, 0x19, 0x8e, 0xd6, 0x98, 0xef, 0xe1, 0x74, 0xc4, 0xdb, 0xb0, 0xdc, 0x1b, 0x93, 0x2f, 0xb0,
|
||||
0xc0, 0xb1, 0xf9, 0xc8, 0xca, 0x61, 0x57, 0x21, 0x6d, 0x07, 0x81, 0x00, 0x64, 0x39, 0x20, 0x65,
|
||||
0x07, 0x01, 0x77, 0xdd, 0x84, 0x55, 0x5e, 0x63, 0x88, 0xc8, 0xc8, 0xa3, 0x72, 0x92, 0x1c, 0xc7,
|
||||
0xac, 0x30, 0x87, 0x29, 0xec, 0x1c, 0xfb, 0x16, 0xe4, 0xd1, 0xa1, 0xeb, 0x20, 0xbf, 0x87, 0x04,
|
||||
0x2e, 0xcf, 0x71, 0xb9, 0xb1, 0x91, 0x83, 0x6e, 0x40, 0x21, 0x08, 0x71, 0x80, 0x09, 0x0a, 0x2d,
|
||||
0xdb, 0x71, 0x42, 0x44, 0x48, 0x71, 0x59, 0xcc, 0x37, 0xb6, 0x57, 0x85, 0xb9, 0x52, 0x04, 0x75,
|
||||
0xc7, 0xa6, 0xb6, 0x56, 0x80, 0x24, 0x3d, 0x22, 0x45, 0x45, 0x4f, 0x6e, 0xe6, 0x4c, 0xf6, 0x59,
|
||||
0xf9, 0x3b, 0x01, 0xea, 0x43, 0x4c, 0x91, 0x76, 0x1b, 0x54, 0xd6, 0x26, 0xae, 0xbe, 0xe5, 0x8b,
|
||||
0xf4, 0xdc, 0x76, 0xfb, 0x3e, 0x72, 0xf6, 0x49, 0xbf, 0x73, 0x1c, 0x20, 0x93, 0x83, 0x63, 0x72,
|
||||
0x4a, 0x4c, 0xc9, 0x69, 0x0d, 0x16, 0x43, 0x3c, 0xf2, 0x1d, 0xae, 0xb2, 0x45, 0x53, 0x0c, 0xb4,
|
||||
0x5d, 0x48, 0x47, 0x2a, 0x51, 0xff, 0x4b, 0x25, 0x2b, 0x4c, 0x25, 0x4c, 0xc3, 0xd2, 0x60, 0xa6,
|
||||
0xba, 0x52, 0x2c, 0x35, 0xc8, 0x44, 0x87, 0x97, 0x54, 0xdb, 0xab, 0x09, 0x76, 0x12, 0xa6, 0xbd,
|
||||
0x07, 0xab, 0x51, 0xef, 0x23, 0xf2, 0x84, 0xe2, 0x0a, 0x91, 0x43, 0xb2, 0x37, 0x25, 0x2b, 0x4b,
|
||||
0x1c, 0x40, 0x29, 0x5e, 0xd7, 0x44, 0x56, 0x0d, 0x7e, 0x12, 0x5d, 0x87, 0x0c, 0x71, 0xfb, 0xbe,
|
||||
0x4d, 0x47, 0x21, 0x92, 0xca, 0x9b, 0x18, 0x2a, 0x3f, 0x2b, 0xb0, 0x24, 0x94, 0x1c, 0xe3, 0x4d,
|
||||
0xb9, 0x98, 0xb7, 0xc4, 0x3c, 0xde, 0x92, 0xaf, 0xcf, 0x5b, 0x15, 0x20, 0x4a, 0x86, 0x14, 0x55,
|
||||
0x3d, 0xb9, 0x99, 0xdd, 0xbe, 0x36, 0x3b, 0x91, 0x48, 0xb1, 0xed, 0xf6, 0xe5, 0x46, 0x8d, 0x05,
|
||||
0x55, 0x7e, 0x57, 0x20, 0x13, 0xf9, 0xb5, 0x2a, 0xe4, 0xc7, 0x79, 0x59, 0x8f, 0x3c, 0xbb, 0x2f,
|
||||
0xb5, 0xb3, 0x3e, 0x37, 0xb9, 0x3b, 0x9e, 0xdd, 0x37, 0xb3, 0x32, 0x1f, 0x36, 0xb8, 0xb8, 0x0f,
|
||||
0x89, 0x39, 0x7d, 0x98, 0x6a, 0x7c, 0xf2, 0xf5, 0x1a, 0x3f, 0xd5, 0x22, 0xf5, 0x7c, 0x8b, 0x7e,
|
||||
0x4a, 0x40, 0xba, 0xc5, 0xf7, 0x8e, 0xed, 0xfd, 0x1f, 0x3b, 0xe2, 0x1a, 0x64, 0x02, 0xec, 0x59,
|
||||
0xc2, 0xa3, 0x72, 0x4f, 0x3a, 0xc0, 0x9e, 0x39, 0xd3, 0xf6, 0xc5, 0x37, 0xb4, 0x5d, 0x96, 0xde,
|
||||
0x00, 0x6b, 0xa9, 0xf3, 0xac, 0x85, 0x90, 0x13, 0x54, 0xc8, 0xbb, 0xec, 0x16, 0xe3, 0x80, 0x5f,
|
||||
0x8e, 0xca, 0xec, 0xdd, 0x2b, 0xd2, 0x16, 0x48, 0x53, 0xe2, 0x58, 0x84, 0x38, 0xfa, 0xe5, 0x75,
|
||||
0x5a, 0x9c, 0x27, 0x4b, 0x53, 0xe2, 0x2a, 0xdf, 0x29, 0x00, 0x7b, 0x8c, 0x59, 0x5e, 0x2f, 0xbb,
|
||||
0x85, 0x08, 0x4f, 0xc1, 0x9a, 0x5a, 0xb9, 0x3c, 0xaf, 0x69, 0x72, 0xfd, 0x1c, 0x89, 0xe7, 0x5d,
|
||||
0x87, 0xfc, 0x44, 0x8c, 0x04, 0x8d, 0x93, 0xb9, 0x60, 0x92, 0xe8, 0x72, 0x68, 0x23, 0x6a, 0xe6,
|
||||
0x0e, 0x63, 0xa3, 0xca, 0x2f, 0x0a, 0x64, 0x78, 0x4e, 0xfb, 0x88, 0xda, 0x53, 0x3d, 0x54, 0x5e,
|
||||
0xbf, 0x87, 0xeb, 0x00, 0x62, 0x1a, 0xe2, 0x3e, 0x41, 0x52, 0x59, 0x19, 0x6e, 0x69, 0xbb, 0x4f,
|
||||
0x90, 0xf6, 0x51, 0x44, 0x78, 0xf2, 0xdf, 0x09, 0x97, 0x5b, 0x7a, 0x4c, 0xfb, 0x15, 0x48, 0xf9,
|
||||
0xa3, 0xa1, 0xc5, 0xae, 0x04, 0x55, 0xa8, 0xd5, 0x1f, 0x0d, 0x3b, 0x47, 0xa4, 0xf2, 0x35, 0xa4,
|
||||
0x3a, 0x47, 0xfc, 0x79, 0xc4, 0x24, 0x1a, 0x62, 0x2c, 0xef, 0x64, 0xf1, 0x16, 0x4a, 0x33, 0x03,
|
||||
0xbf, 0x82, 0x34, 0x50, 0xd9, 0xe5, 0x3b, 0x7e, 0xac, 0xb1, 0x6f, 0xcd, 0x78, 0xc5, 0x87, 0x97,
|
||||
0x7c, 0x72, 0xdd, 0xfc, 0x55, 0x81, 0x6c, 0xec, 0x7c, 0xd0, 0x3e, 0x80, 0x4b, 0xb5, 0xbd, 0x83,
|
||||
0xfa, 0x7d, 0xab, 0xb1, 0x63, 0xdd, 0xd9, 0xab, 0xde, 0xb5, 0x1e, 0x34, 0xef, 0x37, 0x0f, 0xbe,
|
||||
0x68, 0x16, 0x16, 0x4a, 0x97, 0x4f, 0x4e, 0x75, 0x2d, 0x86, 0x7d, 0xe0, 0x3f, 0xf6, 0xf1, 0x37,
|
||||
0xbe, 0xb6, 0x05, 0x6b, 0xd3, 0x21, 0xd5, 0x5a, 0x7b, 0xb7, 0xd9, 0x29, 0x28, 0xa5, 0x4b, 0x27,
|
||||
0xa7, 0xfa, 0x6a, 0x2c, 0xa2, 0xda, 0x25, 0xc8, 0xa7, 0xb3, 0x01, 0xf5, 0x83, 0xfd, 0xfd, 0x46,
|
||||
0xa7, 0x90, 0x98, 0x09, 0x90, 0x07, 0xf6, 0x0d, 0x58, 0x9d, 0x0e, 0x68, 0x36, 0xf6, 0x0a, 0xc9,
|
||||
0x92, 0x76, 0x72, 0xaa, 0x2f, 0xc7, 0xd0, 0x4d, 0xd7, 0x2b, 0xa5, 0xbf, 0xfd, 0xbe, 0xbc, 0xf0,
|
||||
0xe3, 0x0f, 0x65, 0x85, 0x55, 0x96, 0x9f, 0x3a, 0x23, 0xb4, 0xf7, 0xe1, 0x4a, 0xbb, 0x71, 0xb7,
|
||||
0xb9, 0xbb, 0x63, 0xed, 0xb7, 0xef, 0x5a, 0x9d, 0x2f, 0x5b, 0xbb, 0xb1, 0xea, 0x56, 0x4e, 0x4e,
|
||||
0xf5, 0xac, 0x2c, 0x69, 0x1e, 0xba, 0x65, 0xee, 0x3e, 0x3c, 0xe8, 0xec, 0x16, 0x14, 0x81, 0x6e,
|
||||
0x85, 0xe8, 0x10, 0x53, 0xc4, 0xd1, 0xb7, 0xe0, 0xea, 0x05, 0xe8, 0xa8, 0xb0, 0xd5, 0x93, 0x53,
|
||||
0x3d, 0xdf, 0x0a, 0x91, 0xd8, 0x3f, 0x3c, 0xc2, 0x80, 0xe2, 0x6c, 0xc4, 0x41, 0xeb, 0xa0, 0x5d,
|
||||
0xdd, 0x2b, 0xe8, 0xa5, 0xc2, 0xc9, 0xa9, 0x9e, 0x1b, 0x1f, 0x86, 0x0c, 0x3f, 0xa9, 0xac, 0xf6,
|
||||
0xf9, 0xb3, 0xb3, 0xb2, 0xf2, 0xfc, 0xac, 0xac, 0xfc, 0x79, 0x56, 0x56, 0x9e, 0xbe, 0x2c, 0x2f,
|
||||
0x3c, 0x7f, 0x59, 0x5e, 0xf8, 0xed, 0x65, 0x79, 0xe1, 0xab, 0x8f, 0xfb, 0x2e, 0x1d, 0x8c, 0xba,
|
||||
0x46, 0x0f, 0x0f, 0xb7, 0xe2, 0x7f, 0x09, 0x26, 0x9f, 0xe2, 0xaf, 0xc9, 0xf9, 0xbf, 0x0b, 0xdd,
|
||||
0x25, 0x6e, 0xbf, 0xfd, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4c, 0x78, 0x43, 0xdf, 0xef, 0x0c,
|
||||
0x00, 0x00,
|
||||
// 1435 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x6f, 0x1a, 0xd7,
|
||||
0x16, 0xf7, 0xc0, 0xd8, 0xc0, 0x81, 0xb1, 0xf1, 0x8d, 0x93, 0x60, 0x12, 0x63, 0x34, 0x4f, 0x79,
|
||||
0x71, 0xf2, 0x9e, 0x70, 0xea, 0x54, 0xfd, 0x58, 0xb4, 0x15, 0x60, 0x92, 0xa0, 0xd8, 0x98, 0x0e,
|
||||
0x24, 0x55, 0xbb, 0x19, 0x0d, 0x70, 0x0d, 0xd3, 0x0c, 0x73, 0x47, 0x33, 0x17, 0xd7, 0xce, 0x5f,
|
||||
0x50, 0x79, 0x95, 0x55, 0x77, 0x5e, 0xb5, 0x8b, 0x4a, 0x5d, 0x76, 0xd1, 0x6d, 0xd5, 0x55, 0x96,
|
||||
0xd9, 0xb5, 0xab, 0xb4, 0x72, 0xa4, 0xfe, 0x1d, 0xd5, 0xfd, 0x60, 0x18, 0x8c, 0xdd, 0x46, 0x51,
|
||||
0xd4, 0x0d, 0x9a, 0x7b, 0xce, 0xef, 0x9c, 0x7b, 0x3e, 0x7e, 0xf7, 0xdc, 0x0b, 0x5c, 0xa7, 0xd8,
|
||||
0xed, 0x61, 0x7f, 0x68, 0xbb, 0x74, 0x93, 0x1e, 0x79, 0x38, 0x10, 0xbf, 0x25, 0xcf, 0x27, 0x94,
|
||||
0xa0, 0xec, 0x44, 0x5b, 0xe2, 0xf2, 0xfc, 0x4a, 0x9f, 0xf4, 0x09, 0x57, 0x6e, 0xb2, 0x2f, 0x81,
|
||||
0xcb, 0xaf, 0xf7, 0x09, 0xe9, 0x3b, 0x78, 0x93, 0xaf, 0x3a, 0xa3, 0xfd, 0x4d, 0x6a, 0x0f, 0x71,
|
||||
0x40, 0xad, 0xa1, 0x27, 0x01, 0x6b, 0x91, 0x6d, 0xba, 0xfe, 0x91, 0x47, 0x09, 0xc3, 0x92, 0x7d,
|
||||
0xa9, 0x2e, 0x44, 0xd4, 0x07, 0xd8, 0x0f, 0x6c, 0xe2, 0x46, 0xe3, 0xc8, 0x17, 0x67, 0xa2, 0x3c,
|
||||
0xb0, 0x1c, 0xbb, 0x67, 0x51, 0xe2, 0x0b, 0x84, 0xfe, 0x21, 0x68, 0x4d, 0xcb, 0xa7, 0x2d, 0x4c,
|
||||
0x1f, 0x60, 0xab, 0x87, 0x7d, 0xb4, 0x02, 0xf3, 0x94, 0x50, 0xcb, 0xc9, 0x29, 0x45, 0x65, 0x43,
|
||||
0x33, 0xc4, 0x02, 0x21, 0x50, 0x07, 0x56, 0x30, 0xc8, 0xc5, 0x8a, 0xca, 0x46, 0xc6, 0xe0, 0xdf,
|
||||
0xfa, 0x00, 0x54, 0x66, 0xca, 0x2c, 0x6c, 0xb7, 0x87, 0x0f, 0xc7, 0x16, 0x7c, 0xc1, 0xa4, 0x9d,
|
||||
0x23, 0x8a, 0x03, 0x69, 0x22, 0x16, 0xe8, 0x5d, 0x98, 0xe7, 0xf1, 0xe7, 0xe2, 0x45, 0x65, 0x23,
|
||||
0xbd, 0x95, 0x2b, 0x45, 0x0a, 0x25, 0xf2, 0x2b, 0x35, 0x99, 0xbe, 0xa2, 0x3e, 0x7f, 0xb9, 0x3e,
|
||||
0x67, 0x08, 0xb0, 0xee, 0x40, 0xa2, 0xe2, 0x90, 0xee, 0x93, 0xfa, 0x76, 0x18, 0x88, 0x32, 0x09,
|
||||
0x04, 0xed, 0xc2, 0x92, 0x67, 0xf9, 0xd4, 0x0c, 0x30, 0x35, 0x07, 0x3c, 0x0b, 0xbe, 0x69, 0x7a,
|
||||
0x6b, 0xbd, 0x74, 0xb6, 0x0f, 0xa5, 0xa9, 0x64, 0xe5, 0x2e, 0x9a, 0x17, 0x15, 0xea, 0x7f, 0xaa,
|
||||
0xb0, 0x20, 0x8b, 0xf1, 0x11, 0x24, 0x64, 0x59, 0xf9, 0x86, 0xe9, 0xad, 0xb5, 0xa8, 0x47, 0xa9,
|
||||
0x2a, 0x55, 0x89, 0x1b, 0x60, 0x37, 0x18, 0x05, 0xd2, 0xdf, 0xd8, 0x06, 0xfd, 0x17, 0x92, 0xdd,
|
||||
0x81, 0x65, 0xbb, 0xa6, 0xdd, 0xe3, 0x11, 0xa5, 0x2a, 0xe9, 0xd3, 0x97, 0xeb, 0x89, 0x2a, 0x93,
|
||||
0xd5, 0xb7, 0x8d, 0x04, 0x57, 0xd6, 0x7b, 0xe8, 0x0a, 0x2c, 0x0c, 0xb0, 0xdd, 0x1f, 0x50, 0x5e,
|
||||
0x96, 0xb8, 0x21, 0x57, 0xe8, 0x03, 0x50, 0x19, 0x21, 0x72, 0x2a, 0xdf, 0x3b, 0x5f, 0x12, 0x6c,
|
||||
0x29, 0x8d, 0xd9, 0x52, 0x6a, 0x8f, 0xd9, 0x52, 0x49, 0xb2, 0x8d, 0x9f, 0xfd, 0xbe, 0xae, 0x18,
|
||||
0xdc, 0x02, 0x55, 0x41, 0x73, 0xac, 0x80, 0x9a, 0x1d, 0x56, 0x36, 0xb6, 0xfd, 0x3c, 0x77, 0xb1,
|
||||
0x3a, 0x5b, 0x10, 0x59, 0x58, 0x19, 0x7a, 0x9a, 0x59, 0x09, 0x51, 0x0f, 0x6d, 0x40, 0x96, 0x3b,
|
||||
0xe9, 0x92, 0xe1, 0xd0, 0xa6, 0x26, 0xaf, 0xfb, 0x02, 0xaf, 0xfb, 0x22, 0x93, 0x57, 0xb9, 0xf8,
|
||||
0x01, 0xeb, 0xc0, 0x35, 0x48, 0xf5, 0x2c, 0x6a, 0x09, 0x48, 0x82, 0x43, 0x92, 0x4c, 0xc0, 0x95,
|
||||
0x37, 0x61, 0x29, 0x64, 0x5d, 0x20, 0x20, 0x49, 0xe1, 0x65, 0x22, 0xe6, 0xc0, 0x3b, 0xb0, 0xe2,
|
||||
0xe2, 0x43, 0x6a, 0x9e, 0x45, 0xa7, 0x38, 0x1a, 0x31, 0xdd, 0xe3, 0x69, 0x8b, 0x1b, 0xb0, 0xd8,
|
||||
0x1d, 0x17, 0x5f, 0x60, 0x81, 0x63, 0xb5, 0x50, 0xca, 0x61, 0xab, 0x90, 0xb4, 0x3c, 0x4f, 0x00,
|
||||
0xd2, 0x1c, 0x90, 0xb0, 0x3c, 0x8f, 0xab, 0x6e, 0xc3, 0x32, 0xcf, 0xd1, 0xc7, 0xc1, 0xc8, 0xa1,
|
||||
0xd2, 0x49, 0x86, 0x63, 0x96, 0x98, 0xc2, 0x10, 0x72, 0x8e, 0xfd, 0x0f, 0x68, 0xf8, 0xc0, 0xee,
|
||||
0x61, 0xb7, 0x8b, 0x05, 0x4e, 0xe3, 0xb8, 0xcc, 0x58, 0xc8, 0x41, 0xb7, 0x20, 0xeb, 0xf9, 0xc4,
|
||||
0x23, 0x01, 0xf6, 0x4d, 0xab, 0xd7, 0xf3, 0x71, 0x10, 0xe4, 0x16, 0x85, 0xbf, 0xb1, 0xbc, 0x2c,
|
||||
0xc4, 0x7a, 0x0e, 0xd4, 0x6d, 0x8b, 0x5a, 0x28, 0x0b, 0x71, 0x7a, 0x18, 0xe4, 0x94, 0x62, 0x7c,
|
||||
0x23, 0x63, 0xb0, 0x4f, 0xfd, 0xa7, 0x38, 0xa8, 0x8f, 0x09, 0xc5, 0xe8, 0x2e, 0xa8, 0xac, 0x4d,
|
||||
0x9c, 0x7d, 0x8b, 0xe7, 0xf1, 0xb9, 0x65, 0xf7, 0x5d, 0xdc, 0xdb, 0x0d, 0xfa, 0xed, 0x23, 0x0f,
|
||||
0x1b, 0x1c, 0x1c, 0xa1, 0x53, 0x6c, 0x8a, 0x4e, 0x2b, 0x30, 0xef, 0x93, 0x91, 0xdb, 0xe3, 0x2c,
|
||||
0x9b, 0x37, 0xc4, 0x02, 0xd5, 0x20, 0x19, 0xb2, 0x44, 0xfd, 0x27, 0x96, 0x2c, 0x31, 0x96, 0x30,
|
||||
0x0e, 0x4b, 0x81, 0x91, 0xe8, 0x48, 0xb2, 0x54, 0x20, 0x15, 0x0e, 0x2f, 0xc9, 0xb6, 0xd7, 0x23,
|
||||
0xec, 0xc4, 0x0c, 0xfd, 0x0f, 0x96, 0xc3, 0xde, 0x87, 0xc5, 0x13, 0x8c, 0xcb, 0x86, 0x0a, 0x59,
|
||||
0xbd, 0x29, 0x5a, 0x99, 0x62, 0x00, 0x25, 0x78, 0x5e, 0x13, 0x5a, 0xd5, 0xf9, 0x24, 0xba, 0x0e,
|
||||
0xa9, 0xc0, 0xee, 0xbb, 0x16, 0x1d, 0xf9, 0x58, 0x32, 0x6f, 0x22, 0x60, 0x5a, 0x7c, 0x48, 0xb1,
|
||||
0xcb, 0x0f, 0xb9, 0x60, 0xda, 0x44, 0x80, 0x36, 0xe1, 0x52, 0xb8, 0x30, 0x27, 0x5e, 0x04, 0xcb,
|
||||
0x50, 0xa8, 0x6a, 0x8d, 0x35, 0xfa, 0x11, 0x68, 0xac, 0x71, 0xb5, 0xd0, 0xc3, 0x4d, 0xc8, 0x32,
|
||||
0xee, 0xf1, 0xe3, 0x41, 0x09, 0xf7, 0x21, 0x87, 0x97, 0x66, 0x79, 0x1e, 0xeb, 0x7f, 0x9b, 0x30,
|
||||
0x73, 0xf4, 0x09, 0x5c, 0x0f, 0x81, 0x01, 0x76, 0xf6, 0x4d, 0x6b, 0x44, 0x07, 0xd8, 0xa5, 0x76,
|
||||
0xd7, 0xa2, 0xb6, 0xdb, 0x97, 0x73, 0x74, 0x55, 0x1a, 0xb5, 0xb0, 0xb3, 0x5f, 0x9e, 0x02, 0xe8,
|
||||
0x1f, 0xc3, 0xa5, 0xa9, 0xad, 0xa5, 0xdf, 0xd7, 0x0d, 0x40, 0xff, 0x59, 0x81, 0x05, 0x71, 0xa6,
|
||||
0x23, 0x0c, 0x52, 0xce, 0x67, 0x50, 0xec, 0x22, 0x06, 0xc5, 0xdf, 0x9c, 0x41, 0x65, 0x80, 0xb0,
|
||||
0xc2, 0x41, 0x4e, 0x2d, 0xc6, 0x37, 0xd2, 0x5b, 0xd7, 0x66, 0x1d, 0x89, 0x10, 0x5b, 0x76, 0x5f,
|
||||
0x8e, 0xac, 0x88, 0x91, 0xfe, 0x43, 0x0c, 0x52, 0xa1, 0x1e, 0x95, 0x41, 0x1b, 0xc7, 0x65, 0xee,
|
||||
0x3b, 0x56, 0x5f, 0x9e, 0xa2, 0xb5, 0x0b, 0x83, 0xbb, 0xe7, 0x58, 0x7d, 0x23, 0x2d, 0xe3, 0x61,
|
||||
0x8b, 0xf3, 0x19, 0x19, 0xbb, 0x80, 0x91, 0x53, 0x47, 0x20, 0xfe, 0x66, 0x47, 0x60, 0x8a, 0xac,
|
||||
0xea, 0x59, 0xb2, 0xee, 0xc0, 0xe2, 0x01, 0xa1, 0xd8, 0x9c, 0x30, 0x56, 0x9c, 0xb4, 0x1b, 0xb3,
|
||||
0x29, 0x9d, 0x43, 0x05, 0x43, 0x3b, 0x88, 0x0a, 0xf5, 0x1f, 0x63, 0x90, 0x6c, 0xf2, 0x99, 0x64,
|
||||
0x39, 0xff, 0xc6, 0xa4, 0xb9, 0x06, 0x29, 0x8f, 0x38, 0xa6, 0xd0, 0xa8, 0x5c, 0x93, 0xf4, 0x88,
|
||||
0x63, 0xcc, 0x90, 0x68, 0xfe, 0x2d, 0x8d, 0xa1, 0x85, 0xb7, 0xd0, 0x83, 0xc4, 0x99, 0x1e, 0xe8,
|
||||
0x3e, 0x64, 0x44, 0x29, 0xe4, 0x1b, 0xe1, 0x0e, 0xab, 0x01, 0x7f, 0x74, 0x28, 0xb3, 0x6f, 0x1a,
|
||||
0x11, 0xb6, 0x40, 0x1a, 0x12, 0xc7, 0x2c, 0xc4, 0x95, 0x2a, 0x9f, 0x29, 0xb9, 0x8b, 0x48, 0x6e,
|
||||
0x48, 0x9c, 0xfe, 0x8d, 0x02, 0xb0, 0xc3, 0x2a, 0xcb, 0xf3, 0x65, 0xb7, 0x7b, 0xc0, 0x43, 0x30,
|
||||
0xa7, 0x76, 0x2e, 0x5c, 0xd4, 0x34, 0xb9, 0x7f, 0x26, 0x88, 0xc6, 0x5d, 0x05, 0x6d, 0x42, 0xed,
|
||||
0x00, 0x8f, 0x83, 0x39, 0xc7, 0x49, 0x78, 0xe9, 0xb6, 0x30, 0x35, 0x32, 0x07, 0x91, 0x95, 0xfe,
|
||||
0x8b, 0x02, 0x29, 0x1e, 0xd3, 0x2e, 0xa6, 0xd6, 0x54, 0x0f, 0x95, 0x37, 0xef, 0xe1, 0x1a, 0x80,
|
||||
0x70, 0x13, 0xd8, 0x4f, 0xb1, 0x64, 0x56, 0x8a, 0x4b, 0x5a, 0xf6, 0x53, 0x8c, 0xde, 0x0b, 0x0b,
|
||||
0x1e, 0xff, 0xfb, 0x82, 0xcb, 0x01, 0x31, 0x2e, 0xfb, 0x55, 0x48, 0xb8, 0xa3, 0xa1, 0xc9, 0xae,
|
||||
0x5a, 0x55, 0xb0, 0xd5, 0x1d, 0x0d, 0xdb, 0x87, 0x81, 0xfe, 0x25, 0x24, 0xda, 0x87, 0xfc, 0xd9,
|
||||
0xc9, 0x28, 0xea, 0x13, 0x22, 0xdf, 0x3a, 0x62, 0x4a, 0x26, 0x99, 0x80, 0x5f, 0xed, 0x08, 0x54,
|
||||
0x36, 0x45, 0xc7, 0x8f, 0x60, 0xf6, 0x8d, 0x4a, 0xaf, 0xf9, 0xa0, 0x95, 0x4f, 0xd9, 0xdb, 0xbf,
|
||||
0x2a, 0x90, 0x8e, 0x4c, 0x1b, 0xf4, 0x0e, 0x5c, 0xae, 0xec, 0xec, 0x55, 0x1f, 0x9a, 0xf5, 0x6d,
|
||||
0xf3, 0xde, 0x4e, 0xf9, 0xbe, 0xf9, 0xa8, 0xf1, 0xb0, 0xb1, 0xf7, 0x59, 0x23, 0x3b, 0x97, 0xbf,
|
||||
0x72, 0x7c, 0x52, 0x44, 0x11, 0xec, 0x23, 0xf7, 0x89, 0x4b, 0xbe, 0x62, 0x77, 0xd2, 0xca, 0xb4,
|
||||
0x49, 0xb9, 0xd2, 0xaa, 0x35, 0xda, 0x59, 0x25, 0x7f, 0xf9, 0xf8, 0xa4, 0xb8, 0x1c, 0xb1, 0x28,
|
||||
0x77, 0x02, 0xec, 0xd2, 0x59, 0x83, 0xea, 0xde, 0xee, 0x6e, 0xbd, 0x9d, 0x8d, 0xcd, 0x18, 0xc8,
|
||||
0xf1, 0x7f, 0x0b, 0x96, 0xa7, 0x0d, 0x1a, 0xf5, 0x9d, 0x6c, 0x3c, 0x8f, 0x8e, 0x4f, 0x8a, 0x8b,
|
||||
0x11, 0x74, 0xc3, 0x76, 0xf2, 0xc9, 0xaf, 0xbf, 0x2d, 0xcc, 0x7d, 0xff, 0x5d, 0x41, 0x61, 0x99,
|
||||
0x69, 0x53, 0x33, 0x02, 0xfd, 0x1f, 0xae, 0xb6, 0xea, 0xf7, 0x1b, 0xb5, 0x6d, 0x73, 0xb7, 0x75,
|
||||
0xdf, 0x6c, 0x7f, 0xde, 0xac, 0x45, 0xb2, 0x5b, 0x3a, 0x3e, 0x29, 0xa6, 0x65, 0x4a, 0x17, 0xa1,
|
||||
0x9b, 0x46, 0xed, 0xf1, 0x5e, 0xbb, 0x96, 0x55, 0x04, 0xba, 0xe9, 0x63, 0x36, 0xc0, 0x38, 0xfa,
|
||||
0x0e, 0xac, 0x9e, 0x83, 0x0e, 0x13, 0x5b, 0x3e, 0x3e, 0x29, 0x6a, 0x4d, 0x1f, 0x8b, 0xf3, 0xc3,
|
||||
0x2d, 0x4a, 0x90, 0x9b, 0xb5, 0xd8, 0x6b, 0xee, 0xb5, 0xca, 0x3b, 0xd9, 0x62, 0x3e, 0x7b, 0x7c,
|
||||
0x52, 0xcc, 0x8c, 0x87, 0x21, 0xc3, 0x4f, 0x32, 0xab, 0x7c, 0xfa, 0xfc, 0xb4, 0xa0, 0xbc, 0x38,
|
||||
0x2d, 0x28, 0x7f, 0x9c, 0x16, 0x94, 0x67, 0xaf, 0x0a, 0x73, 0x2f, 0x5e, 0x15, 0xe6, 0x7e, 0x7b,
|
||||
0x55, 0x98, 0xfb, 0xe2, 0xfd, 0xbe, 0x4d, 0x07, 0xa3, 0x4e, 0xa9, 0x4b, 0x86, 0x9b, 0xd1, 0xbf,
|
||||
0x5a, 0x93, 0x4f, 0xf1, 0x97, 0xef, 0xec, 0xdf, 0xb0, 0xce, 0x02, 0x97, 0xdf, 0xfd, 0x2b, 0x00,
|
||||
0x00, 0xff, 0xff, 0x4f, 0xab, 0x7f, 0x9d, 0x47, 0x0e, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *PartSetHeader) Marshal() (dAtA []byte, err error) {
|
||||
@@ -1433,6 +1571,20 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
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
|
||||
}
|
||||
if len(m.Signature) > 0 {
|
||||
i -= len(m.Signature)
|
||||
copy(dAtA[i:], m.Signature)
|
||||
@@ -1488,6 +1640,73 @@ 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)
|
||||
@@ -1565,6 +1784,18 @@ 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)
|
||||
@@ -1572,12 +1803,12 @@ func (m *CommitSig) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
n9, err9 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):])
|
||||
if err9 != nil {
|
||||
return 0, err9
|
||||
n10, err10 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):])
|
||||
if err10 != nil {
|
||||
return 0, err10
|
||||
}
|
||||
i -= n9
|
||||
i = encodeVarintTypes(dAtA, i, uint64(n9))
|
||||
i -= n10
|
||||
i = encodeVarintTypes(dAtA, i, uint64(n10))
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
if len(m.ValidatorAddress) > 0 {
|
||||
@@ -1622,12 +1853,12 @@ func (m *Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i--
|
||||
dAtA[i] = 0x3a
|
||||
}
|
||||
n10, err10 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):])
|
||||
if err10 != nil {
|
||||
return 0, err10
|
||||
n11, err11 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Timestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Timestamp):])
|
||||
if err11 != nil {
|
||||
return 0, err11
|
||||
}
|
||||
i -= n10
|
||||
i = encodeVarintTypes(dAtA, i, uint64(n10))
|
||||
i -= n11
|
||||
i = encodeVarintTypes(dAtA, i, uint64(n11))
|
||||
i--
|
||||
dAtA[i] = 0x32
|
||||
{
|
||||
@@ -2022,6 +2253,44 @@ func (m *Vote) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
}
|
||||
l = len(m.Extension)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
}
|
||||
l = len(m.ExtensionSignature)
|
||||
if l > 0 {
|
||||
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)
|
||||
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)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTypes(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -2067,6 +2336,10 @@ 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
|
||||
}
|
||||
|
||||
@@ -3362,6 +3635,276 @@ func (m *Vote) Unmarshal(dAtA []byte) error {
|
||||
m.Signature = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 9:
|
||||
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 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.Extension = append(m.Extension[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Extension == nil {
|
||||
m.Extension = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 10:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ExtensionSignature", 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.ExtensionSignature = append(m.ExtensionSignature[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.ExtensionSignature == nil {
|
||||
m.ExtensionSignature = []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 *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)
|
||||
}
|
||||
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{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AppDataSelfAuthenticating", 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.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{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipTypes(dAtA[iNdEx:])
|
||||
@@ -3687,6 +4230,42 @@ 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:])
|
||||
|
||||
@@ -101,7 +101,27 @@ 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;
|
||||
}
|
||||
|
||||
// VoteExtension is app-defined additional information to the validator votes.
|
||||
message VoteExtension {
|
||||
bytes app_data_to_sign = 1;
|
||||
bytes app_data_self_authenticating = 2;
|
||||
}
|
||||
|
||||
// VoteExtensionToSign is a subset of VoteExtension that is signed by the validators private key.
|
||||
// VoteExtensionToSign is extracted from an existing VoteExtension.
|
||||
message VoteExtensionToSign {
|
||||
bytes app_data_to_sign = 1;
|
||||
}
|
||||
|
||||
// Commit contains the evidence that a block was committed by a set of validators.
|
||||
@@ -119,6 +139,7 @@ message CommitSig {
|
||||
google.protobuf.Timestamp timestamp = 3
|
||||
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
|
||||
bytes signature = 4;
|
||||
VoteExtensionToSign vote_extension = 5;
|
||||
}
|
||||
|
||||
message Proposal {
|
||||
|
||||
@@ -20,6 +20,8 @@ type AppConnConsensus interface {
|
||||
InitChain(context.Context, *types.RequestInitChain) (*types.ResponseInitChain, error)
|
||||
PrepareProposal(context.Context, *types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error)
|
||||
ProcessProposal(context.Context, *types.RequestProcessProposal) (*types.ResponseProcessProposal, error)
|
||||
ExtendVote(context.Context, *types.RequestExtendVote) (*types.ResponseExtendVote, error)
|
||||
VerifyVoteExtension(context.Context, *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error)
|
||||
FinalizeBlock(context.Context, *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error)
|
||||
Commit(context.Context) (*types.ResponseCommit, error)
|
||||
}
|
||||
@@ -87,6 +89,16 @@ func (app *appConnConsensus) ProcessProposal(ctx context.Context, req *types.Req
|
||||
return app.appConn.ProcessProposal(ctx, req)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) ExtendVote(ctx context.Context, req *types.RequestExtendVote) (*types.ResponseExtendVote, error) {
|
||||
defer addTimeSample(app.metrics.MethodTimingSeconds.With("method", "deliver_tx", "type", "async"))()
|
||||
return app.appConn.ExtendVote(ctx, req)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) VerifyVoteExtension(ctx context.Context, req *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) {
|
||||
defer addTimeSample(app.metrics.MethodTimingSeconds.With("method", "deliver_tx", "type", "async"))()
|
||||
return app.appConn.VerifyVoteExtension(ctx, req)
|
||||
}
|
||||
|
||||
func (app *appConnConsensus) FinalizeBlock(ctx context.Context, req *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
|
||||
defer addTimeSample(app.metrics.MethodTimingSeconds.With("method", "deliver_tx", "type", "async"))()
|
||||
return app.appConn.FinalizeBlock(ctx, req)
|
||||
|
||||
@@ -52,6 +52,29 @@ func (_m *AppConnConsensus) Error() error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// ExtendVote provides a mock function with given fields: _a0, _a1
|
||||
func (_m *AppConnConsensus) ExtendVote(_a0 context.Context, _a1 *types.RequestExtendVote) (*types.ResponseExtendVote, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *types.ResponseExtendVote
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.RequestExtendVote) *types.ResponseExtendVote); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseExtendVote)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.RequestExtendVote) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// FinalizeBlock provides a mock function with given fields: _a0, _a1
|
||||
func (_m *AppConnConsensus) FinalizeBlock(_a0 context.Context, _a1 *types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
@@ -144,6 +167,29 @@ func (_m *AppConnConsensus) ProcessProposal(_a0 context.Context, _a1 *types.Requ
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// VerifyVoteExtension provides a mock function with given fields: _a0, _a1
|
||||
func (_m *AppConnConsensus) VerifyVoteExtension(_a0 context.Context, _a1 *types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *types.ResponseVerifyVoteExtension
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.RequestVerifyVoteExtension) *types.ResponseVerifyVoteExtension); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.ResponseVerifyVoteExtension)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.RequestVerifyVoteExtension) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewAppConnConsensus interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
|
||||
@@ -91,6 +91,11 @@ func (_m *AppConnMempool) Flush(_a0 context.Context) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetResponseCallback provides a mock function with given fields: _a0
|
||||
func (_m *AppConnMempool) SetResponseCallback(_a0 abcicli.Callback) {
|
||||
_m.Called(_a0)
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewAppConnMempool interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
|
||||
+62
-5
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
|
||||
"github.com/tendermint/tendermint/libs/fail"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -293,6 +294,39 @@ func (blockExec *BlockExecutor) ApplyBlock(
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (blockExec *BlockExecutor) ExtendVote(vote *types.Vote) ([]byte, error) {
|
||||
req := abci.RequestExtendVote{
|
||||
Hash: vote.BlockID.Hash,
|
||||
Height: vote.Height,
|
||||
}
|
||||
|
||||
resp, err := blockExec.proxyApp.ExtendVote(context.TODO(), &req)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("ExtendVote call failed: %w", err))
|
||||
}
|
||||
return resp.VoteExtension, nil
|
||||
}
|
||||
|
||||
func (blockExec *BlockExecutor) VerifyVoteExtension(vote *types.Vote) error {
|
||||
req := abci.RequestVerifyVoteExtension{
|
||||
Hash: vote.BlockID.Hash,
|
||||
ValidatorAddress: vote.ValidatorAddress,
|
||||
Height: vote.Height,
|
||||
VoteExtension: vote.Extension,
|
||||
}
|
||||
|
||||
resp, err := blockExec.proxyApp.VerifyVoteExtension(context.TODO(), &req)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("VerifyVoteExtension call failed: %w", err))
|
||||
}
|
||||
|
||||
if !resp.IsAccepted() {
|
||||
return types.ErrVoteInvalidExtension
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Commit locks the mempool, runs the ABCI Commit message, and updates the
|
||||
// mempool.
|
||||
// It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any).
|
||||
@@ -384,16 +418,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{
|
||||
@@ -473,7 +530,7 @@ func updateState(
|
||||
|
||||
nextVersion := state.Version
|
||||
|
||||
// NOTE: the AppHash has not been populated.
|
||||
// NOTE: the AppHash and the VoteExtension has not been populated.
|
||||
// It will be filled on state.Save.
|
||||
return State{
|
||||
Version: nextVersion,
|
||||
|
||||
+14
-12
@@ -178,11 +178,13 @@ func TestFinalizeBlockValidators(t *testing.T) {
|
||||
commitSig0 = types.NewCommitSigForBlock(
|
||||
[]byte("Signature1"),
|
||||
state.Validators.Validators[0].Address,
|
||||
now)
|
||||
now,
|
||||
)
|
||||
commitSig1 = types.NewCommitSigForBlock(
|
||||
[]byte("Signature2"),
|
||||
state.Validators.Validators[1].Address,
|
||||
now)
|
||||
now,
|
||||
)
|
||||
absentSig = types.NewCommitSigAbsent()
|
||||
)
|
||||
|
||||
@@ -711,9 +713,9 @@ func TestEmptyPrepareProposal(t *testing.T) {
|
||||
blockStore,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
commit, votes, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
_, err = blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
_, err = blockExec.CreateProposalBlock(height, state, commit, pa, votes)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -754,9 +756,9 @@ func TestPrepareProposalTxsAllIncluded(t *testing.T) {
|
||||
blockStore,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
commit, votes, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, votes)
|
||||
require.NoError(t, err)
|
||||
|
||||
for i, tx := range block.Data.Txs {
|
||||
@@ -807,9 +809,9 @@ func TestPrepareProposalReorderTxs(t *testing.T) {
|
||||
blockStore,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
commit, votes, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, votes)
|
||||
require.NoError(t, err)
|
||||
for i, tx := range block.Data.Txs {
|
||||
require.Equal(t, txs[i], tx)
|
||||
@@ -862,10 +864,10 @@ func TestPrepareProposalErrorOnTooManyTxs(t *testing.T) {
|
||||
blockStore,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
commit, votes, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, votes)
|
||||
require.Nil(t, block)
|
||||
require.ErrorContains(t, err, "transaction data size exceeds maximum")
|
||||
|
||||
@@ -912,10 +914,10 @@ func TestPrepareProposalErrorOnPrepareProposalError(t *testing.T) {
|
||||
blockStore,
|
||||
)
|
||||
pa, _ := state.Validators.GetByIndex(0)
|
||||
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
commit, votes, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
|
||||
require.NoError(t, err)
|
||||
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil)
|
||||
block, err := blockExec.CreateProposalBlock(height, state, commit, pa, votes)
|
||||
require.Nil(t, block)
|
||||
require.ErrorContains(t, err, "an injected error")
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ func makeAndCommitGoodBlock(
|
||||
}
|
||||
|
||||
// Simulate a lastCommit for this block from all validators for the next height
|
||||
commit, err := makeValidCommit(height, blockID, state.Validators, privVals)
|
||||
commit, _, err := makeValidCommit(height, blockID, state.Validators, privVals)
|
||||
if err != nil {
|
||||
return state, types.BlockID{}, nil, err
|
||||
}
|
||||
@@ -88,17 +88,19 @@ func makeValidCommit(
|
||||
blockID types.BlockID,
|
||||
vals *types.ValidatorSet,
|
||||
privVals map[string]types.PrivValidator,
|
||||
) (*types.Commit, error) {
|
||||
sigs := make([]types.CommitSig, 0)
|
||||
) (*types.Commit, []*types.Vote, error) {
|
||||
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 := types.MakeVote(height, blockID, vals, privVals[val.Address.String()], chainID, time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
sigs = append(sigs, vote.CommitSig())
|
||||
sigs[i] = vote.CommitSig()
|
||||
votes[i] = vote
|
||||
}
|
||||
return types.NewCommit(height, 0, blockID, sigs), nil
|
||||
return types.NewCommit(height, 0, blockID, sigs), votes, nil
|
||||
}
|
||||
|
||||
func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) {
|
||||
|
||||
+156
-6
@@ -4,20 +4,28 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
const appVersion = 1
|
||||
const (
|
||||
appVersion = 1
|
||||
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
|
||||
@@ -282,8 +290,69 @@ func (app *Application) ApplySnapshotChunk(_ context.Context, req *abci.RequestA
|
||||
return &abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil
|
||||
}
|
||||
|
||||
// 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(
|
||||
_ context.Context, req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) {
|
||||
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++
|
||||
}
|
||||
|
||||
if app.cfg.PrepareProposalDelay != 0 {
|
||||
time.Sleep(app.cfg.PrepareProposalDelay)
|
||||
}
|
||||
|
||||
// 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.
|
||||
txs := make([][]byte, len(req.Txs)+1)
|
||||
for i, tx := range req.Txs {
|
||||
if strings.HasPrefix(string(tx), extTxPrefix) {
|
||||
continue
|
||||
}
|
||||
txs[i] = tx
|
||||
totalBytes += int64(len(tx))
|
||||
}
|
||||
if totalBytes+int64(len(extTx)) < req.MaxTxBytes {
|
||||
txs[len(req.Txs)] = 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{Txs: txs}, nil
|
||||
}
|
||||
// None of the transactions are modified by this application.
|
||||
txs := make([][]byte, 0, len(req.Txs))
|
||||
var totalBytes int64
|
||||
for _, tx := range req.Txs {
|
||||
@@ -294,10 +363,6 @@ func (app *Application) PrepareProposal(
|
||||
txs = append(txs, tx)
|
||||
}
|
||||
|
||||
if app.cfg.PrepareProposalDelay != 0 {
|
||||
time.Sleep(app.cfg.PrepareProposalDelay)
|
||||
}
|
||||
|
||||
return &abci.ResponsePrepareProposal{Txs: txs}, nil
|
||||
}
|
||||
|
||||
@@ -305,10 +370,19 @@ func (app *Application) PrepareProposal(
|
||||
// It accepts any proposal that does not contain a malformed transaction.
|
||||
func (app *Application) ProcessProposal(_ context.Context, req *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) {
|
||||
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}, nil
|
||||
}
|
||||
// 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}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if app.cfg.ProcessProposalDelay != 0 {
|
||||
@@ -318,6 +392,66 @@ func (app *Application) ProcessProposal(_ context.Context, req *abci.RequestProc
|
||||
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil
|
||||
}
|
||||
|
||||
// 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(_ context.Context, req *abci.RequestExtendVote) (*abci.ResponseExtendVote, error) {
|
||||
// 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{}, nil
|
||||
}
|
||||
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],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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(_ context.Context, req *abci.RequestVerifyVoteExtension) (*abci.ResponseVerifyVoteExtension, error) {
|
||||
// We allow vote extensions to be optional
|
||||
if len(req.VoteExtension) == 0 {
|
||||
return &abci.ResponseVerifyVoteExtension{
|
||||
Status: abci.ResponseVerifyVoteExtension_ACCEPT,
|
||||
}, nil
|
||||
}
|
||||
if req.Height != int64(app.state.Height)+1 {
|
||||
panic(fmt.Errorf(
|
||||
"got unexpected height in VerifyVoteExtension request; expected %d, actual %d",
|
||||
app.state.Height, req.Height,
|
||||
))
|
||||
}
|
||||
|
||||
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,
|
||||
}, nil
|
||||
}
|
||||
app.logger.Info("verified vote extension value", "req", req, "num", num)
|
||||
return &abci.ResponseVerifyVoteExtension{
|
||||
Status: abci.ResponseVerifyVoteExtension_ACCEPT,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (app *Application) Rollback() error {
|
||||
return app.state.Rollback()
|
||||
}
|
||||
@@ -352,3 +486,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
|
||||
}
|
||||
|
||||
@@ -59,6 +59,18 @@ func (app *SyncApplication) ProcessProposal(ctx context.Context, req *abci.Reque
|
||||
return app.app.ProcessProposal(ctx, req)
|
||||
}
|
||||
|
||||
func (app *SyncApplication) ExtendVote(ctx context.Context, req *abci.RequestExtendVote) (*abci.ResponseExtendVote, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
return app.app.ExtendVote(ctx, req)
|
||||
}
|
||||
|
||||
func (app *SyncApplication) VerifyVoteExtension(ctx context.Context, req *abci.RequestVerifyVoteExtension) (*abci.ResponseVerifyVoteExtension, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
return app.app.VerifyVoteExtension(ctx, req)
|
||||
}
|
||||
|
||||
func (app *SyncApplication) FinalizeBlock(ctx context.Context, req *abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) {
|
||||
app.mtx.Lock()
|
||||
defer app.mtx.Unlock()
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -38,6 +39,7 @@ func TestApp_Hash(t *testing.T) {
|
||||
testNode(t, func(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")
|
||||
@@ -102,3 +104,18 @@ func TestApp_Tx(t *testing.T) {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestApp_VoteExtensions(t *testing.T) {
|
||||
testNode(t, func(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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -286,6 +286,7 @@ func (th *TestHarness) TestSignVote() error {
|
||||
return newTestHarnessError(ErrTestSignVoteFailed, err, fmt.Sprintf("voteType=%d", voteType))
|
||||
}
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
th.logger.Debug("Signed vote", "vote", vote)
|
||||
// validate the contents of the vote
|
||||
if err := vote.ValidateBasic(); err != nil {
|
||||
|
||||
+2
-2
@@ -243,7 +243,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())
|
||||
}
|
||||
|
||||
@@ -526,7 +526,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)
|
||||
|
||||
|
||||
+14
-1
@@ -52,7 +52,8 @@ func CanonicalizeProposal(chainID string, proposal *tmproto.Proposal) tmproto.Ca
|
||||
}
|
||||
|
||||
// CanonicalizeVote transforms the given Vote to a CanonicalVote, which does
|
||||
// not contain ValidatorIndex and ValidatorAddress fields.
|
||||
// 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,
|
||||
@@ -64,6 +65,18 @@ func CanonicalizeVote(chainID string, vote *tmproto.Vote) tmproto.CanonicalVote
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
||||
// CanonicalTime can be used to stringify time in a canonical way.
|
||||
func CanonicalTime(t time.Time) string {
|
||||
// Note that sending time over amino resets it to
|
||||
|
||||
@@ -251,6 +251,7 @@ func makeVote(
|
||||
require.NoError(t, err)
|
||||
|
||||
v.Signature = vpb.Signature
|
||||
v.ExtensionSignature = vpb.ExtensionSignature
|
||||
return v
|
||||
}
|
||||
|
||||
|
||||
@@ -77,11 +77,17 @@ func (pv MockPV) SignVote(chainID string, vote *tmproto.Vote) error {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ func signAddVote(privVal PrivValidator, vote *Vote, voteSet *VoteSet) (signed bo
|
||||
return false, err
|
||||
}
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
return voteSet.AddVote(vote)
|
||||
}
|
||||
|
||||
@@ -77,6 +78,7 @@ func MakeVote(
|
||||
}
|
||||
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
|
||||
return vote, nil
|
||||
}
|
||||
@@ -99,3 +101,13 @@ func MakeBlock(height int64, txs []Tx, lastCommit *Commit, evidence []Evidence)
|
||||
block.fillHeader()
|
||||
return block
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@ func TestValidatorSet_VerifyCommit_CheckAllSignatures(t *testing.T) {
|
||||
err = vals[3].SignVote("CentaurusA", v)
|
||||
require.NoError(t, err)
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
commit.Signatures[3] = vote.CommitSig()
|
||||
|
||||
err = valSet.VerifyCommit(chainID, blockID, h, commit)
|
||||
@@ -174,6 +175,7 @@ func TestValidatorSet_VerifyCommitLight_ReturnsAsSoonAsMajorityOfVotingPowerSign
|
||||
err = vals[3].SignVote("CentaurusA", v)
|
||||
require.NoError(t, err)
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
commit.Signatures[3] = vote.CommitSig()
|
||||
|
||||
err = valSet.VerifyCommitLight(chainID, blockID, h, commit)
|
||||
@@ -198,6 +200,7 @@ func TestValidatorSet_VerifyCommitLightTrusting_ReturnsAsSoonAsTrustLevelOfVotin
|
||||
err = vals[2].SignVote("CentaurusA", v)
|
||||
require.NoError(t, err)
|
||||
vote.Signature = v.Signature
|
||||
vote.ExtensionSignature = v.ExtensionSignature
|
||||
commit.Signatures[2] = vote.CommitSig()
|
||||
|
||||
err = valSet.VerifyCommitLightTrusting(chainID, commit, tmmath.Fraction{Numerator: 1, Denominator: 3})
|
||||
|
||||
+55
-19
@@ -24,6 +24,7 @@ var (
|
||||
ErrVoteInvalidBlockHash = errors.New("invalid block hash")
|
||||
ErrVoteNonDeterministicSignature = errors.New("non-deterministic signature")
|
||||
ErrVoteNil = errors.New("nil vote")
|
||||
ErrVoteInvalidExtension = errors.New("invalid vote extension")
|
||||
)
|
||||
|
||||
type ErrVoteConflictingVotes struct {
|
||||
@@ -48,14 +49,16 @@ type Address = crypto.Address
|
||||
// Vote represents a prevote, precommit, or commit vote from validators for
|
||||
// consensus.
|
||||
type Vote struct {
|
||||
Type tmproto.SignedMsgType `json:"type"`
|
||||
Height int64 `json:"height"`
|
||||
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"`
|
||||
Type tmproto.SignedMsgType `json:"type"`
|
||||
Height int64 `json:"height"`
|
||||
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.
|
||||
@@ -83,7 +86,7 @@ func (vote *Vote) CommitSig() CommitSig {
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -100,6 +103,21 @@ 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
|
||||
return &voteCopy
|
||||
@@ -115,7 +133,8 @@ func (vote *Vote) Copy() *Vote {
|
||||
// 6. type string
|
||||
// 7. first 6 bytes of block hash
|
||||
// 8. first 6 bytes of signature
|
||||
// 9. timestamp
|
||||
// 9. first 6 bytes of vote extension
|
||||
// 10. timestamp
|
||||
func (vote *Vote) String() string {
|
||||
if vote == nil {
|
||||
return nilVoteStr
|
||||
@@ -131,7 +150,7 @@ func (vote *Vote) String() string {
|
||||
panic("Unknown vote type")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}",
|
||||
return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X %X @ %s}",
|
||||
vote.ValidatorIndex,
|
||||
tmbytes.Fingerprint(vote.ValidatorAddress),
|
||||
vote.Height,
|
||||
@@ -140,6 +159,7 @@ func (vote *Vote) String() string {
|
||||
typeString,
|
||||
tmbytes.Fingerprint(vote.BlockID.Hash),
|
||||
tmbytes.Fingerprint(vote.Signature),
|
||||
tmbytes.Fingerprint(vote.Extension),
|
||||
CanonicalTime(vote.Timestamp),
|
||||
)
|
||||
}
|
||||
@@ -152,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
|
||||
}
|
||||
|
||||
@@ -198,6 +224,12 @@ func (vote *Vote) ValidateBasic() error {
|
||||
return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -209,14 +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,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,6 +291,8 @@ func VoteFromProto(pv *tmproto.Vote) (*Vote, error) {
|
||||
vote.ValidatorAddress = pv.ValidatorAddress
|
||||
vote.ValidatorIndex = pv.ValidatorIndex
|
||||
vote.Signature = pv.Signature
|
||||
vote.Extension = pv.Extension
|
||||
vote.ExtensionSignature = pv.ExtensionSignature
|
||||
|
||||
return vote, vote.ValidateBasic()
|
||||
}
|
||||
|
||||
@@ -118,6 +118,7 @@ func TestVoteSet_AddVote_Bad(t *testing.T) {
|
||||
t.Errorf("expected VoteSet.Add to fail, wrong type")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestVoteSet_2_3Majority(t *testing.T) {
|
||||
|
||||
+97
-2
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/libs/protoio"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
)
|
||||
|
||||
func examplePrevote() *Vote {
|
||||
@@ -127,6 +128,27 @@ func TestVoteSignBytesTestVectors(t *testing.T) {
|
||||
0x32,
|
||||
0xd, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64}, // chainID
|
||||
},
|
||||
// containing vote extension
|
||||
5: {
|
||||
"test_chain_id", &Vote{
|
||||
Height: 1,
|
||||
Round: 1,
|
||||
Extension: []byte("extension"),
|
||||
},
|
||||
[]byte{
|
||||
0x2e, // length
|
||||
0x11, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||
0x19, // (field_number << 3) | wire_type
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||
// remaning fields:
|
||||
0x2a, // (field_number << 3) | wire_type
|
||||
0xb, 0x8, 0x80, 0x92, 0xb8, 0xc3, 0x98, 0xfe, 0xff, 0xff, 0xff, 0x1, // timestamp
|
||||
// (field_number << 3) | wire_type
|
||||
0x32,
|
||||
0xd, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, // chainID
|
||||
}, // chainID
|
||||
},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
v := tc.vote.ToProto()
|
||||
@@ -177,6 +199,79 @@ 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) {
|
||||
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()
|
||||
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("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
|
||||
@@ -219,13 +314,13 @@ func TestVoteVerify(t *testing.T) {
|
||||
|
||||
func TestVoteString(t *testing.T) {
|
||||
str := examplePrecommit().String()
|
||||
expected := `Vote{56789:6AF1F4111082 12345/02/SIGNED_MSG_TYPE_PRECOMMIT(Precommit) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
expected := `Vote{56789:6AF1F4111082 12345/02/SIGNED_MSG_TYPE_PRECOMMIT(Precommit) 8B01023386C3 000000000000 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
if str != expected {
|
||||
t.Errorf("got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str)
|
||||
}
|
||||
|
||||
str2 := examplePrevote().String()
|
||||
expected = `Vote{56789:6AF1F4111082 12345/02/SIGNED_MSG_TYPE_PREVOTE(Prevote) 8B01023386C3 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
expected = `Vote{56789:6AF1F4111082 12345/02/SIGNED_MSG_TYPE_PREVOTE(Prevote) 8B01023386C3 000000000000 000000000000 @ 2017-12-25T03:00:01.234Z}` //nolint:lll //ignore line length for tests
|
||||
if str2 != expected {
|
||||
t.Errorf("got unexpected string for Vote. Expected:\n%v\nGot:\n%v", expected, str2)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user