Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADR-016: Add versions to Block and State #2644

Merged
merged 9 commits into from
Oct 17, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ BREAKING CHANGES:
* [rpc] \#2298 `/abci_query` takes `prove` argument instead of `trusted` and switches the default
behaviour to `prove=false`
* [privval] \#2459 Split `SocketPVMsg`s implementations into Request and Response, where the Response may contain a error message (returned by the remote signer)
* [state] \#2644 Add Version field to State, breaking the format of State as
encoded on disk.

* Apps
* [abci] \#2298 ResponseQuery.Proof is now a structured merkle.Proof, not just
arbitrary bytes
* [abci] \#2644 Add Version to Header and shift all fields by one

* Go API
* [node] Remove node.RunForever
Expand All @@ -25,7 +28,8 @@ BREAKING CHANGES:
* [crypto/merkle & lite] \#2298 Various changes to accomodate General Merkle trees
* [crypto/merkle] \#2595 Remove all Hasher objects in favor of byte slices
* [crypto/merkle] \#2635 merkle.SimpleHashFromTwoHashes is no longer exported
* [types] \#2598 `VoteTypeXxx` are now
* [types] \#2598 `VoteTypeXxx` are now of type `SignedMsgType byte` and named `XxxType`, eg. `PrevoteType`,
`PrecommitType`.

* Blockchain Protocol
* [types] Update SignBytes for `Vote`/`Proposal`/`Heartbeat`:
Expand All @@ -34,7 +38,9 @@ BREAKING CHANGES:
* \#2598 Change `Type` field fromt `string` to `byte` and use new
`SignedMsgType` to enumerate.
* [types] \#2512 Remove the pubkey field from the validator hash
* [types] \#2644 Add Version struct to Header
* [state] \#2587 Require block.Time of the fist block to be genesis time
* [state] \#2644 Require block.Version to match state.Version

* P2P Protocol

Expand Down
863 changes: 576 additions & 287 deletions abci/types/types.pb.go

Large diffs are not rendered by default.

37 changes: 22 additions & 15 deletions abci/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -231,31 +231,38 @@ message LastCommitInfo {

message Header {
// basic block info
string chain_id = 1 [(gogoproto.customname)="ChainID"];
int64 height = 2;
google.protobuf.Timestamp time = 3 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true];
int64 num_txs = 4;
int64 total_txs = 5;
Version version = 1 [(gogoproto.nullable)=false];
string chain_id = 2 [(gogoproto.customname)="ChainID"];
int64 height = 3;
google.protobuf.Timestamp time = 4 [(gogoproto.nullable)=false, (gogoproto.stdtime)=true];
int64 num_txs = 5;
int64 total_txs = 6;

// prev block info
BlockID last_block_id = 6 [(gogoproto.nullable)=false];
BlockID last_block_id = 7 [(gogoproto.nullable)=false];

// hashes of block data
bytes last_commit_hash = 7; // commit from validators from the last block
bytes data_hash = 8; // transactions
bytes last_commit_hash = 8; // commit from validators from the last block
bytes data_hash = 9; // transactions

// hashes from the app output from the prev block
bytes validators_hash = 9; // validators for the current block
bytes next_validators_hash = 10; // validators for the next block
bytes consensus_hash = 11; // consensus params for current block
bytes app_hash = 12; // state after txs from the previous block
bytes last_results_hash = 13;// root hash of all results from the txs from the previous block
bytes validators_hash = 10; // validators for the current block
bytes next_validators_hash = 11; // validators for the next block
bytes consensus_hash = 12; // consensus params for current block
bytes app_hash = 13; // state after txs from the previous block
bytes last_results_hash = 14;// root hash of all results from the txs from the previous block

// consensus info
bytes evidence_hash = 14; // evidence included in the block
bytes proposer_address = 15; // original proposer of the block
bytes evidence_hash = 15; // evidence included in the block
bytes proposer_address = 16; // original proposer of the block
}

message Version {
uint64 Block = 1;
uint64 App = 2;
}


message BlockID {
bytes hash = 1;
PartSetHeader parts_header = 2 [(gogoproto.nullable)=false];
Expand Down
124 changes: 124 additions & 0 deletions abci/types/typespb_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions docs/spec/abci/abci.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ Commit are included in the header of the next block.
### Header

- **Fields**:
- `Version (Version)`: Version of the blockchain and the application
- `ChainID (string)`: ID of the blockchain
- `Height (int64)`: Height of the block in the chain
- `Time (google.protobuf.Timestamp)`: Time of the block. It is the proposer's
Expand All @@ -363,6 +364,15 @@ Commit are included in the header of the next block.
- Provides the proposer of the current block, for use in proposer-based
reward mechanisms.

### Version

- **Fields**:
- `Block (uint64)`: Protocol version of the blockchain data structures.
- `App (uint64)`: Protocol version of the application.
- **Usage**:
- Block version should be static in the life of a blockchain.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Does that mean a block version can only be upgraded / changed via a fork?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the idea for now. We can probably relax it somewhat later but needs more work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely think this can be relaxed #postlaunch. My intuition is that only changes to the merkle tree structure absolutely require going back to genesis files, from a block version pov. Header formats and Block Structures can be changed in a live-upgrade, but probably shouldn't be due to how it would break a ton of other things.

- App version may be updated over time by the application.

### Validator

- **Fields**:
Expand Down
24 changes: 24 additions & 0 deletions docs/spec/blockchain/blockchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The Tendermint blockchains consists of a short list of basic data types:

- `Block`
- `Header`
- `Version`
- `BlockID`
- `Time`
- `Data` (for transactions)
Expand Down Expand Up @@ -38,6 +39,7 @@ the data in the current block, the previous block, and the results returned by t
```go
type Header struct {
// basic block info
Version Version
ChainID string
Height int64
Time Time
Expand Down Expand Up @@ -65,6 +67,19 @@ type Header struct {

Further details on each of these fields is described below.

## Version

The `Version` contains the protocol version for the blockchain and the
application as two `uint64` values:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to duplicate type information imho

Suggested change
application as two `uint64` values:
application:


```go
type Version struct {
Block uint64
App uint64
}
```


## BlockID

The `BlockID` contains two distinct Merkle roots of the block.
Expand Down Expand Up @@ -200,6 +215,15 @@ See [here](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockc

A Header is valid if its corresponding fields are valid.

### Version

```
block.Version.Block == state.Version.Block
block.Version.App == state.Version.App
```

The block version must match the state version.

### ChainID

```
Expand Down
1 change: 1 addition & 0 deletions docs/spec/blockchain/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ validation.

```go
type State struct {
Version Version
LastResults []Result
AppHash []byte

Expand Down
9 changes: 9 additions & 0 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,15 @@ func NewNode(config *cfg.Config,
// reload the state (it may have been updated by the handshake)
state = sm.LoadState(stateDB)

if state.Version.Consensus.Block != version.BlockProtocol {
return nil, fmt.Errorf(
"Block version of the software does not match that of the state.\n"+
"Got version.BlockProtocol=%v, state.Version.Consensus.Block=%v",
version.BlockProtocol,
state.Version.Consensus.Block,
)
}

// If an address is provided, listen on the socket for a
// connection from an external signing process.
if config.PrivValidatorListenAddr != "" {
Expand Down
4 changes: 4 additions & 0 deletions state/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,13 @@ func updateState(
lastHeightParamsChanged = header.Height + 1
}

// TODO: allow app to upgrade version
nextVersion := state.Version

// NOTE: the AppHash has not been populated.
// It will be filled on state.Save.
return State{
Version: nextVersion,
ChainID: state.ChainID,
LastBlockHeight: header.Height,
LastBlockTotalTx: state.LastBlockTotalTx + header.NumTxs,
Expand Down