diff --git a/internal/eventbus/event_bus.go b/internal/eventbus/event_bus.go index 2a7c032b3..1d2d510e3 100644 --- a/internal/eventbus/event_bus.go +++ b/internal/eventbus/event_bus.go @@ -50,13 +50,6 @@ func (b *EventBus) NumClientSubscriptions(clientID string) int { return b.pubsub.NumClientSubscriptions(clientID) } -// Deprecated: Use SubscribeWithArgs instead. -func (b *EventBus) Subscribe(ctx context.Context, - clientID string, query *tmquery.Query, capacities ...int) (Subscription, error) { - - return b.pubsub.Subscribe(ctx, clientID, query, capacities...) -} - func (b *EventBus) SubscribeWithArgs(ctx context.Context, args tmpubsub.SubscribeArgs) (Subscription, error) { return b.pubsub.SubscribeWithArgs(ctx, args) } diff --git a/internal/pubsub/pubsub.go b/internal/pubsub/pubsub.go index 707f9cb13..df2dd90e3 100644 --- a/internal/pubsub/pubsub.go +++ b/internal/pubsub/pubsub.go @@ -153,26 +153,6 @@ func BufferCapacity(cap int) Option { // BufferCapacity returns capacity of the publication queue. func (s *Server) BufferCapacity() int { return cap(s.queue) } -// Subscribe creates a subscription for the given client ID and query. -// If len(capacities) > 0, its first value is used as the queue capacity. -// -// Deprecated: Use SubscribeWithArgs. This method will be removed in v0.36. -func (s *Server) Subscribe(ctx context.Context, clientID string, query *query.Query, capacities ...int) (*Subscription, error) { - args := SubscribeArgs{ - ClientID: clientID, - Query: query, - Limit: 1, - } - if len(capacities) > 0 { - args.Limit = capacities[0] - if len(capacities) > 1 { - args.Quota = capacities[1] - } - // bounds are checked below - } - return s.SubscribeWithArgs(ctx, args) -} - // Observe registers an observer function that will be called synchronously // with each published message matching any of the given queries, prior to it // being forwarded to any subscriber. If no queries are specified, all diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index f3521d24d..6ee25c658 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -21,26 +21,26 @@ import "gogoproto/gogo.proto"; message Request { oneof value { - RequestEcho echo = 1; - RequestFlush flush = 2; - RequestInfo info = 3; - RequestInitChain init_chain = 4; - RequestQuery query = 5; - RequestBeginBlock begin_block = 6 [deprecated = true]; - RequestCheckTx check_tx = 7; - RequestDeliverTx deliver_tx = 8 [deprecated = true]; - RequestEndBlock end_block = 9 [deprecated = true]; - RequestCommit commit = 10; - RequestListSnapshots list_snapshots = 11; - RequestOfferSnapshot offer_snapshot = 12; - RequestLoadSnapshotChunk load_snapshot_chunk = 13; - RequestApplySnapshotChunk apply_snapshot_chunk = 14; - RequestPrepareProposal prepare_proposal = 15; - RequestProcessProposal process_proposal = 16; - RequestFinalizeBlock finalize_block = 19; + RequestEcho echo = 1; + RequestFlush flush = 2; + RequestInfo info = 3; + RequestInitChain init_chain = 4; + RequestQuery query = 5; + RequestBeginBlock begin_block = 6 [deprecated = true]; + RequestCheckTx check_tx = 7; + RequestDeliverTx deliver_tx = 8 [deprecated = true]; + RequestEndBlock end_block = 9 [deprecated = true]; + RequestCommit commit = 10; + RequestListSnapshots list_snapshots = 11; + RequestOfferSnapshot offer_snapshot = 12; + RequestLoadSnapshotChunk load_snapshot_chunk = 13; + RequestApplySnapshotChunk apply_snapshot_chunk = 14; + RequestPrepareProposal prepare_proposal = 15; + RequestProcessProposal process_proposal = 16; + RequestExtendVote extend_vote = 17; + RequestVerifyVoteExtension verify_vote_extension = 18; + RequestFinalizeBlock finalize_block = 19; } - reserved 17; // Placeholder for RequestExtendVote in v0.37 - reserved 18; // Placeholder for RequestVerifyVoteExtension in v0.37 } message RequestEcho { @@ -75,7 +75,7 @@ message RequestQuery { message RequestBeginBlock { bytes hash = 1; tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; - LastCommitInfo last_commit_info = 3 [(gogoproto.nullable) = false]; + CommitInfo last_commit_info = 3 [(gogoproto.nullable) = false]; repeated Evidence byzantine_validators = 4 [(gogoproto.nullable) = false]; } @@ -127,9 +127,9 @@ message RequestPrepareProposal { tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; // txs is an array of transactions that will be included in a block, // sent to the app for possible modifications. - repeated bytes txs = 3; - LastCommitInfo last_commit_info = 4 [(gogoproto.nullable) = false]; - repeated Evidence byzantine_validators = 5 [(gogoproto.nullable) = false]; + repeated bytes txs = 3; + ExtendedCommitInfo local_last_commit = 4 [(gogoproto.nullable) = false]; + repeated Evidence byzantine_validators = 5 [(gogoproto.nullable) = false]; // the modified transactions cannot exceed this size. int64 max_tx_bytes = 6; } @@ -138,15 +138,29 @@ message RequestProcessProposal { bytes hash = 1; tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; repeated bytes txs = 3; - LastCommitInfo last_commit_info = 4 [(gogoproto.nullable) = false]; + CommitInfo proposed_last_commit = 4 [(gogoproto.nullable) = false]; repeated Evidence byzantine_validators = 5 [(gogoproto.nullable) = false]; } +// 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 { bytes hash = 1; tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; repeated bytes txs = 3; - LastCommitInfo last_commit_info = 4 [(gogoproto.nullable) = false]; + CommitInfo decided_last_commit = 4 [(gogoproto.nullable) = false]; repeated Evidence byzantine_validators = 5 [(gogoproto.nullable) = false]; } @@ -155,27 +169,27 @@ message RequestFinalizeBlock { message Response { oneof value { - ResponseException exception = 1; - ResponseEcho echo = 2; - ResponseFlush flush = 3; - ResponseInfo info = 4; - ResponseInitChain init_chain = 5; - ResponseQuery query = 6; - ResponseBeginBlock begin_block = 7 [deprecated = true]; - ResponseCheckTx check_tx = 8; - ResponseDeliverTx deliver_tx = 9 [deprecated = true]; - ResponseEndBlock end_block = 10 [deprecated = true]; - ResponseCommit commit = 11; - ResponseListSnapshots list_snapshots = 12; - ResponseOfferSnapshot offer_snapshot = 13; - ResponseLoadSnapshotChunk load_snapshot_chunk = 14; - ResponseApplySnapshotChunk apply_snapshot_chunk = 15; - ResponsePrepareProposal prepare_proposal = 16; - ResponseProcessProposal process_proposal = 17; - ResponseFinalizeBlock finalize_block = 20; + ResponseException exception = 1; + ResponseEcho echo = 2; + ResponseFlush flush = 3; + ResponseInfo info = 4; + ResponseInitChain init_chain = 5; + ResponseQuery query = 6; + ResponseBeginBlock begin_block = 7 [deprecated = true]; + ResponseCheckTx check_tx = 8; + ResponseDeliverTx deliver_tx = 9 [deprecated = true]; + ResponseEndBlock end_block = 10 [deprecated = true]; + ResponseCommit commit = 11; + ResponseListSnapshots list_snapshots = 12; + ResponseOfferSnapshot offer_snapshot = 13; + ResponseLoadSnapshotChunk load_snapshot_chunk = 14; + ResponseApplySnapshotChunk apply_snapshot_chunk = 15; + ResponsePrepareProposal prepare_proposal = 16; + ResponseProcessProposal process_proposal = 17; + ResponseExtendVote extend_vote = 18; + ResponseVerifyVoteExtension verify_vote_extension = 19; + ResponseFinalizeBlock finalize_block = 20; } - reserved 18; // Placeholder for ResponseExtendVote in v0.37 - reserved 19; // Placeholder for ResponseVerifyVoteExtension in v0.37 } // nondeterministic @@ -308,7 +322,7 @@ message ResponsePrepareProposal { repeated ExecTxResult tx_results = 4; repeated ValidatorUpdate validator_updates = 5; tendermint.types.ConsensusParams consensus_param_updates = 6; - reserved 7; // Placeholder for app_signed_updates in v0.37 + repeated bytes app_signed_updates = 7; } message ResponseProcessProposal { @@ -319,6 +333,14 @@ message ResponseProcessProposal { tendermint.types.ConsensusParams consensus_param_updates = 5; } +message ResponseExtendVote { + bytes vote_extension = 1; +} + +message ResponseVerifyVoteExtension { + bool accept = 1; +} + message ResponseFinalizeBlock { repeated Event block_events = 1 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; @@ -332,11 +354,16 @@ message ResponseFinalizeBlock { //---------------------------------------- // Misc. -message LastCommitInfo { +message CommitInfo { int32 round = 1; repeated VoteInfo votes = 2 [(gogoproto.nullable) = false]; } +message ExtendedCommitInfo { + int32 round = 1; + repeated ExtendedVoteInfo votes = 2 [(gogoproto.nullable) = false]; +} + // Event allows application developers to attach additional information to // ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. // Later, transactions may be queried using these events. @@ -410,8 +437,23 @@ message ValidatorUpdate { message VoteInfo { Validator validator = 1 [(gogoproto.nullable) = false]; bool signed_last_block = 2; - reserved 3; // Placeholder for tendermint_signed_extension in v0.37 - reserved 4; // Placeholder for app_signed_extension in v0.37 +} + +// ExtendedVoteInfo +message ExtendedVoteInfo { + Validator validator = 1 [(gogoproto.nullable) = false]; + bool signed_last_block = 2; + bytes vote_extension = 3; +} + +// CanonicalVoteExtension +// TODO: move this to core Tendermint data structures +message CanonicalVoteExtension { + bytes extension = 1; + int64 height = 2; + int32 round = 3; + string chain_id = 4; + bytes address = 5; } enum EvidenceType { @@ -462,5 +504,7 @@ service ABCIApplication { rpc ApplySnapshotChunk(RequestApplySnapshotChunk) 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); } diff --git a/spec/abci++/README.md b/spec/abci++/README.md index b8b75f46b..f720dae4e 100644 --- a/spec/abci++/README.md +++ b/spec/abci++/README.md @@ -20,8 +20,7 @@ for handling all ABCI++ methods. Thus, Tendermint always sends the `Request*` messages and receives the `Response*` messages in return. -All ABCI++ messages and methods are defined in -[protocol buffers](https://github.com/tendermint/tendermint/blob/master/proto/spec/abci/types.proto). +All ABCI++ messages and methods are defined in [protocol buffers](../../proto/tendermint/abci/types.proto). This allows Tendermint to run with applications written in many programming languages. This specification is split as follows: diff --git a/spec/abci++/abci++_basic_concepts_002_draft.md b/spec/abci++/abci++_basic_concepts_002_draft.md index f2fda37dc..1d5171baa 100644 --- a/spec/abci++/abci++_basic_concepts_002_draft.md +++ b/spec/abci++/abci++_basic_concepts_002_draft.md @@ -206,8 +206,9 @@ the local process is the proposer of the round. When Tendermint's consensus is about to send a non-`nil` precommit message, it calls method `ExtendVote`, which gives the Application the opportunity to include non-deterministic data, opaque to Tendermint, that will be attached to the precommit -message. The data, called _vote extension_, will also be part of the proposed block -in the next height, along with the vote it is extending. +message. The data, called _vote extension_, will also be made available to the +application in the next height, along with the vote it is extending, in the rounds +where the local process is the proposer. The vote extension data is split into two parts, one signed by Tendermint as part of the vote data structure, and the other (optionally) signed by the Application. diff --git a/spec/abci++/abci++_methods_002_draft.md b/spec/abci++/abci++_methods_002_draft.md index ccd6c2207..833ddae31 100644 --- a/spec/abci++/abci++_methods_002_draft.md +++ b/spec/abci++/abci++_methods_002_draft.md @@ -290,15 +290,10 @@ title: Methods | hash | bytes | The block header's hash of the block to propose. Present for convenience (can be derived from the block header). | 1 | | header | [Header](../core/data_structures.md#header) | The header of the block to propose. | 2 | | txs | repeated bytes | Preliminary list of transactions that have been picked as part of the block to propose. | 3 | - | last_commit_info | [LastCommitInfo](#lastcommitinfo) | Info about the last commit, including the round, the validator list, and which ones signed the last block. | 4 | + | local_last_commit | [ExtendedCommitInfo](#extendedcommitinfo) | Info about the last commit, obtained locally from Tendermint's data structures. | 4 | | byzantine_validators | repeated [Evidence](#evidence) | List of evidence of validators that acted maliciously. | 5 | | max_tx_bytes | int64 | Currently configured maximum size in bytes taken by the modified transactions. | 6 | ->**TODO**: Add the changes needed in LastCommitInfo for vote extensions - ->**TODO**: DISCUSS: We need to make clear whether a proposer is also running the logic of a non-proposer node (in particular "ProcessProposal") -From the App's perspective, they'll probably skip ProcessProposal - * **Response**: | Name | Type | Description | Field Number | @@ -340,7 +335,7 @@ From the App's perspective, they'll probably skip ProcessProposal for blocks `H+1`, and `H+2`. Heights following a validator update are affected in the following way: * `H`: `NextValidatorsHash` includes the new `validator_updates` value. * `H+1`: The validator set change takes effect and `ValidatorsHash` is updated. - * `H+2`: `last_commit_info` is changed to include the altered validator set. + * `H+2`: `local_last_commit` now includes the altered validator set. * `ResponseFinalizeBlock.consensus_param_updates` returned for block `H` apply to the consensus params for block `H+1` even if the change is agreed in block `H`. For more information on the consensus parameters, @@ -414,7 +409,7 @@ Note that, if _p_ has a non-`nil` _validValue_, Tendermint will use it as propos | hash | bytes | The block header's hash of the proposed block. Present for convenience (can be derived from the block header). | 1 | | header | [Header](../core/data_structures.md#header) | The proposed block's header. | 2 | | txs | repeated bytes | List of transactions that have been picked as part of the proposed block. | 3 | - | last_commit_info | [LastCommitInfo](#lastcommitinfo) | Info about the last commit, including the round , the validator list, and which ones signed the last block. | 4 | + | proposed_last_commit | [CommitInfo](#commitinfo) | Info about the last commit, obtained from the information in the proposed block. | 4 | | byzantine_validators | repeated [Evidence](#evidence) | List of evidence of validators that acted maliciously. | 5 | * **Response**: @@ -495,18 +490,17 @@ When a validator _p_ enters Tendermint consensus round _r_, height _h_, in which * **Response**: - | Name | Type | Description | Field Number | - |-------------------|-------|---------------------------------------------------------------------|--------------| - | app_signed | bytes | Optional information signed by the Application (not by Tendermint). | 1 | - | tendermint_signed | bytes | Optional information signed by Tendermint. | 2 | + | Name | Type | Description | Field Number | + |-------------------|-------|-----------------------------------------------|--------------| + | vote_extension | bytes | Optional information signed by by Tendermint. | 1 | * **Usage**: - * Both `ResponseExtendVote.app_signed` and `ResponseExtendVote.tendermint_signed` are optional information that will - be attached to the Precommit message. + * `ResponseExtendVote.vote_extension` is optional information that, if present, will be signed by Tendermint and + attached to the Precommit message. * `RequestExtendVote.hash` corresponds to the hash of a proposed block that was made available to the application in a previous call to `ProcessProposal` or `PrepareProposal` for the current height. - * `ResponseExtendVote.app_signed` and `ResponseExtendVote.tendermint_signed` will always be attached to a non-`nil` - Precommit message. If Tendermint is to precommit `nil`, it will not call `RequestExtendVote`. + * `ResponseExtendVote.vote_extension` will only be attached to a non-`nil` Precommit message. If Tendermint is to + precommit `nil`, it will not call `RequestExtendVote`. * The Application logic that creates the extension can be non-deterministic. #### When does Tendermint call it? @@ -520,11 +514,18 @@ then _p_'s Tendermint locks _v_ and sends a Precommit message in the following 1. _p_'s Tendermint sets _lockedValue_ and _validValue_ to _v_, and sets _lockedRound_ and _validRound_ to _r_ 2. _p_'s Tendermint calls `RequestExtendVote` with _id(v)_ (`RequestExtendVote.hash`). The call is synchronous. -3. The Application returns an array of bytes, `ResponseExtendVote.extension`, which is not interpreted by Tendermint. -4. _p_'s Tendermint includes `ResponseExtendVote.extension` as a new field in the Precommit message. -5. _p_'s Tendermint signs and broadcasts the Precommit message. - -In the cases when _p_'s Tendermint is to broadcast `precommit nil` messages (either _2f+1_ `prevote nil` messages received, or _timeoutPrevote_ triggered), _p_'s Tendermint does **not** call `RequestExtendVote` and will include an empty byte array as vote extension in the `precommit nil` message. +3. The Application optionally returns an array of bytes, `ResponseExtendVote.extension`, which is not interpreted by Tendermint. +4. _p_'s Tendermint includes `ResponseExtendVote.extension` in a field of type [CanonicalVoteExtension](#canonicalvoteextension), + it then populates the other fields in [CanonicalVoteExtension](#canonicalvoteextension), and signs the populated + data structure. +5. _p_'s Tendermint constructs and signs the [CanonicalVote](../core/data_structures.md#canonicalvote) structure. +6. _p_'s Tendermint constructs the Precommit message (i.e. [Vote](../core/data_structures.md#vote) structure) + using [CanonicalVoteExtension](#canonicalvoteextension) and [CanonicalVote](../core/data_structures.md#canonicalvote). +7. _p_'s Tendermint broadcasts the Precommit message. + +In the cases when _p_'s Tendermint is to broadcast `precommit nil` messages (either _2f+1_ `prevote nil` messages received, +or _timeoutPrevote_ triggered), _p_'s Tendermint does **not** call `RequestExtendVote` and will not include +a [CanonicalVoteExtension](#canonicalvoteextension) field in the `precommit nil` message. ### VerifyVoteExtension @@ -534,11 +535,10 @@ In the cases when _p_'s Tendermint is to broadcast `precommit nil` messages (eit | Name | Type | Description | Field Number | |-------------------|-------|------------------------------------------------------------------------------------------|--------------| - | app_signed | bytes | Optional information signed by the Application (not by Tendermint). | 1 | - | tendermint_signed | bytes | Optional information signed by Tendermint. | 2 | - | hash | bytes | The header hash of the propsed block that the vote extension refers to. | 3 | - | validator_address | bytes | [Address](../core/data_structures.md#address) of the validator that signed the extension | 4 | - | height | int64 | Height of the block (for sanity check). | 5 | + | hash | bytes | The header hash of the propsed block that the vote extension refers to. | 1 | + | validator_address | bytes | [Address](../core/data_structures.md#address) of the validator that signed the extension | 2 | + | height | int64 | Height of the block (for sanity check). | 3 | + | vote_extension | bytes | Optional information signed by Tendermint. | 4 | * **Response**: @@ -566,11 +566,8 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou 2. The Application returns _accept_ or _reject_ via `ResponseVerifyVoteExtension.accept`. 3. If the Application returns * _accept_, _p_'s Tendermint will keep the received vote, together with its corresponding - vote extension in its internal data structures. It will be used to: - * calculate field _LastCommitHash_ in the header of the block proposed for height _h + 1_ - (in the rounds where _p_ will be proposer). - * populate _LastCommitInfo_ in calls to `RequestPrepareProposal`, `RequestProcessProposal`, - and `RequestFinalizeBlock` in height _h + 1_. + vote extension in its internal data structures. It will be used to populate the [ExtendedCommitInfo](#extendedcommitinfo) + structure in calls to `RequestPrepareProposal`, in rounds of height _h + 1_ where _p_ is the proposer. * _reject_, _p_'s Tendermint will deem the Precommit message invalid and discard it. ### FinalizeBlock @@ -579,13 +576,13 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou * **Request**: - | Name | Type | Description | Field Number | - |----------------------|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------|--------------| - | hash | bytes | The block header's hash. Present for convenience (can be derived from the block header). | 1 | - | header | [Header](../core/data_structures.md#header) | The block header. | 2 | - | txs | repeated bytes | List of transactions committed as part of the block. | 3 | - | last_commit_info | [LastCommitInfo](#lastcommitinfo) | Info about the last commit, including the round, and the list of validators and which ones signed the last block. | 4 | - | byzantine_validators | repeated [Evidence](#evidence) | List of evidence of validators that acted maliciously. | 5 | + | Name | Type | Description | Field Number | + |----------------------|---------------------------------------------|------------------------------------------------------------------------------------------|--------------| + | hash | bytes | The block header's hash. Present for convenience (can be derived from the block header). | 1 | + | header | [Header](../core/data_structures.md#header) | The block header. | 2 | + | txs | repeated bytes | List of transactions committed as part of the block. | 3 | + | decided_last_commit | [CommitInfo](#commitinfo) | Info about the last commit, obtained from the block that was just decided. | 4 | + | byzantine_validators | repeated [Evidence](#evidence) | List of evidence of validators that acted maliciously. | 5 | * **Response**: @@ -603,7 +600,7 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou * This method is equivalent to the call sequence `BeginBlock`, [`DeliverTx`], `EndBlock`, `Commit` in the previous version of ABCI. * The header exactly matches the Tendermint header of the proposed block. - * The Application can use `RequestFinalizeBlock.last_commit_info` and `RequestFinalizeBlock.byzantine_validators` + * The Application can use `RequestFinalizeBlock.decided_last_commit` and `RequestFinalizeBlock.byzantine_validators` to determine rewards and punishments for the validators. * The application must execute the transactions in full, in the order they appear in `RequestFinalizeBlock.txs`, before returning control to Tendermint. Alternatively, it can commit the candidate state corresponding to the same block @@ -619,7 +616,7 @@ from this condition, but not sure), and _p_ receives a Precommit message for rou for blocks `H+1`, `H+2`, and `H+3`. Heights following a validator update are affected in the following way: - Height `H+1`: `NextValidatorsHash` includes the new `validator_updates` value. - Height `H+2`: The validator set change takes effect and `ValidatorsHash` is updated. - - Height `H+3`: `last_commit_info` is changed to include the altered validator set. + - Height `H+3`: `decided_last_commit` now includes the altered validator set. * `ResponseFinalizeBlock.consensus_param_updates` returned for block `H` apply to the consensus params for block `H+1`. For more information on the consensus parameters, see the [application spec entry on consensus parameters](../abci/apps.md#consensus-parameters). @@ -728,25 +725,16 @@ Most of the data structures used in ABCI are shared [common data structures](../ | DUPLICATE_VOTE | 1 | | LIGHT_CLIENT_ATTACK | 2 | -### LastCommitInfo - -* **Fields**: - - | Name | Type | Description | Field Number | - |-------|--------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------------| - | round | int32 | Commit round. Reflects the total amount of rounds it took to come to consensus for the current block. | 1 | - | votes | repeated [VoteInfo](#voteinfo) | List of validators addresses in the last validator set with their voting power and whether or not they signed a vote. | 2 | - ### ConsensusParams * **Fields**: | Name | Type | Description | Field Number | |-----------|---------------------------------------------------------------|------------------------------------------------------------------------------|--------------| - | block | [BlockParams](../core/data_structures.md#blockparams) | Parameters limiting the size of a block and time between consecutive blocks. | 1 | + | block | [BlockParams](../core/data_structures.md#blockparams) | Parameters limiting the size of a block and time between consecutive blocks. | 1 | | evidence | [EvidenceParams](../core/data_structures.md#evidenceparams) | Parameters limiting the validity of evidence of byzantine behaviour. | 2 | | validator | [ValidatorParams](../core/data_structures.md#validatorparams) | Parameters limiting the types of public keys validators can use. | 3 | - | version | [VersionsParams](../core/data_structures.md#versionparams) | The ABCI application version. | 4 | + | version | [VersionsParams](../core/data_structures.md#versionparams) | The ABCI application version. | 4 | ### ProofOps @@ -790,18 +778,47 @@ Most of the data structures used in ABCI are shared [common data structures](../ * **Fields**: - | Name | Type | Description | Field Number | - |-----------------------------|-------------------------|---------------------------------------------------------------|--------------| - | validator | [Validator](#validator) | A validator | 1 | - | signed_last_block | bool | Indicates whether or not the validator signed the last block | 2 | - | tendermint_signed_extension | bytes | Indicates whether or not the validator signed the last block | 3 | - | app_signed_extension | bytes | Indicates whether or not the validator signed the last block | 3 | + | Name | Type | Description | Field Number | + |-----------------------------|-------------------------|----------------------------------------------------------------|--------------| + | validator | [Validator](#validator) | The validator that sent the vote. | 1 | + | signed_last_block | bool | Indicates whether or not the validator signed the last block. | 2 | * **Usage**: - * Indicates whether a validator signed the last block, allowing for rewards - based on validator availability - * `tendermint_signed_extension` conveys the part of the validator's vote extension that was signed by Tendermint. - * `app_signed_extension` conveys the optional *app_signed* part of the validator's vote extension. + * Indicates whether a validator signed the last block, allowing for rewards based on validator availability. + * This information is typically extracted from a proposed or decided block. + +### ExtendedVoteInfo + +* **Fields**: + + | Name | Type | Description | Field Number | + |-------------------|-------------------------|------------------------------------------------------------------------------|--------------| + | validator | [Validator](#validator) | The validator that sent the vote. | 1 | + | signed_last_block | bool | Indicates whether or not the validator signed the last block. | 2 | + | vote_extension | bytes | Non-deterministic extension provided by the sending validator's Application. | 3 | + +* **Usage**: + * Indicates whether a validator signed the last block, allowing for rewards based on validator availability. + * This information is extracted from Tendermint's data structures in the local process. + * `vote_extension` contains the sending validator's vote extension, which is signed by Tendermint. It can be empty + +### CommitInfo + +* **Fields**: + + | Name | Type | Description | Field Number | + |-------|--------------------------------|----------------------------------------------------------------------------------------------|--------------| + | round | int32 | Commit round. Reflects the round at which the block proposer decided in the previous height. | 1 | + | votes | repeated [VoteInfo](#voteinfo) | List of validators' addresses in the last validator set with their voting information. | 2 | + +### ExtendedCommitInfo + +* **Fields**: + + | Name | Type | Description | Field Number | + |-------|------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|--------------| + | round | int32 | Commit round. Reflects the round at which the block proposer decided in the previous height. | 1 | + | votes | repeated [ExtendedVoteInfo](#extendedvoteinfo) | List of validators' addresses in the last validator set with their voting information, including vote extensions. | 2 | ### ExecTxResult @@ -843,3 +860,23 @@ Most of the data structures used in ABCI are shared [common data structures](../ |------------|-----------------------|------------------------------------------------------------------|--------------| | action | [TxAction](#txaction) | What should Tendermint do with this transaction? | 1 | | tx | bytes | Transaction contents | 2 | + +### CanonicalVoteExtension + +>**TODO**: This protobuf message definition is not part of the ABCI++ interface, but rather belongs to the +> Precommit message which is broadcast via P2P. So it is to be moved to the relevant section of the spec. + +* **Fields**: + + | Name | Type | Description | Field Number | + |-----------|--------|--------------------------------------------------------------------------------------------|--------------| + | extension | bytes | Vote extension provided by the Application. | 1 | + | height | int64 | Height in which the extension was provided. | 2 | + | round | int32 | Round in which the extension was provided. | 3 | + | chain_id | string | ID of the blockchain running consensus. | 4 | + | address | bytes | [Address](../core/data_structures.md#address) of the validator that provided the extension | 5 | + +* **Usage**: + * Tendermint is to sign the whole data structure and attach it to a Precommit message + * Upon reception, Tendermint validates the sender's signature and sanity-checks the values of `height`, `round`, and `chain_id`. + Then it sends `extension` to the Application via `RequestVerifyVoteExtension` for verification. diff --git a/spec/abci++/abci++_tmint_expected_behavior_002_draft.md b/spec/abci++/abci++_tmint_expected_behavior_002_draft.md index c408d0ab4..18669a479 100644 --- a/spec/abci++/abci++_tmint_expected_behavior_002_draft.md +++ b/spec/abci++/abci++_tmint_expected_behavior_002_draft.md @@ -10,7 +10,8 @@ title: Tendermint's expected behavior This section describes what the Application can expect from Tendermint. The Tendermint consensus algorithm is designed to protect safety under any network conditions, as long as -less than 1/3 of validators' voting power is byzantine. Most of the time, though, the network will behave synchronously and there will be no byzantine process. In these frequent, benign conditions: +less than 1/3 of validators' voting power is byzantine. Most of the time, though, the network will behave +synchronously and there will be no byzantine process. In these frequent, benign conditions: * Tendermint will decide in round 0; * `PrepareProposal` will be called exactly once at the proposer process of round 0, height _h_; diff --git a/spec/core/data_structures.md b/spec/core/data_structures.md index d8cc96e28..0aca40519 100644 --- a/spec/core/data_structures.md +++ b/spec/core/data_structures.md @@ -230,17 +230,20 @@ enum BlockIDFlag { A vote is a signed message from a validator for a particular block. The vote includes information about the validator signing it. When stored in the blockchain or propagated over the network, votes are encoded in Protobuf. - -| Name | Type | Description | Validation | -|------------------|---------------------------------|---------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------| -| Type | [SignedMsgType](#signedmsgtype) | Either prevote or precommit. [SignedMsgType](#signedmsgtype) | A Vote is valid if its corresponding fields are included in the enum [signedMsgType](#signedmsgtype) | -| Height | uint64 | Height for which this vote was created for | Must be > 0 | -| Round | int32 | Round that the commit corresponds to. | Must be > 0 | -| BlockID | [BlockID](#blockid) | The blockID of the corresponding block. | [BlockID](#blockid) | -| Timestamp | [Time](#Time) | Timestamp represents the time at which a validator signed. | [Time](#time) | -| ValidatorAddress | slice of bytes (`[]byte`) | Address of the validator | Length must be equal to 20 | -| ValidatorIndex | int32 | Index at a specific block height that corresponds to the Index of the validator in the set. | must be > 0 | -| Signature | slice of bytes (`[]byte`) | Signature by the validator if they participated in consensus for the associated bock. | Length of signature must be > 0 and < 64 | +The vote extension is not part of the [`CanonicalVote`](#canonicalvote). + +| Name | Type | Description | Validation | +|--------------------|---------------------------------|---------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------| +| Type | [SignedMsgType](#signedmsgtype) | Either prevote or precommit. [SignedMsgType](#signedmsgtype) | A Vote is valid if its corresponding fields are included in the enum [signedMsgType](#signedmsgtype) | +| Height | uint64 | Height for which this vote was created. | Must be > 0 | +| Round | int32 | Round that the commit corresponds to. | Must be > 0 | +| BlockID | [BlockID](#blockid) | The blockID of the corresponding block. | [BlockID](#blockid) | +| Timestamp | [Time](#Time) | The time at which a validator signed. | [Time](#time) | +| ValidatorAddress | slice of bytes (`[]byte`) | Address of the validator | Length must be equal to 20 | +| ValidatorIndex | int32 | Index at a specific block height that corresponds to the Index of the validator in the set. | must be > 0 | +| Signature | slice of bytes (`[]byte`) | Signature by the validator if they participated in consensus for the associated bock. | Length of signature must be > 0 and < 64 | +| Extension | slice of bytes (`[]byte`) | The vote extension provided by the Application. Only valid for precommit messages. | Length must be 0 if Type != `SIGNED_MSG_TYPE_PRECOMMIT` | +| ExtensionSignature | slice of bytes (`[]byte`) | Signature by the validator if they participated in consensus for the associated bock. | Length must be 0 if Type != `SIGNED_MSG_TYPE_PRECOMMIT`; else length must be > 0 and < 64 | ## CanonicalVote @@ -250,7 +253,7 @@ the fields. ```proto message CanonicalVote { SignedMsgType type = 1; - fixed64 height = 2; + fixed64 height = 2; sfixed64 round = 3; CanonicalBlockID block_id = 4; google.protobuf.Timestamp timestamp = 5;