Browse Source

genesis: add support for arbitrary initial height (#5191)

Adds a genesis parameter `initial_height` which specifies the initial block height, as well as ABCI `RequestInitChain.InitialHeight` to pass it to the ABCI application, and `State.InitialHeight` to keep track of the initial height throughout the code. Fixes #2543, based on [RFC-002](https://github.com/tendermint/spec/pull/119). Spec changes in https://github.com/tendermint/spec/pull/135.
pull/5231/head
Erik Grinaker 4 years ago
committed by GitHub
parent
commit
cc247c091b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 556 additions and 318 deletions
  1. +3
    -0
      CHANGELOG_PENDING.md
  2. +9
    -0
      UPGRADING.md
  3. +204
    -168
      abci/types/types.pb.go
  4. +4
    -0
      cmd/tendermint/commands/testnet.go
  5. +1
    -0
      config/toml.go
  6. +8
    -5
      consensus/common_test.go
  7. +31
    -3
      consensus/reactor.go
  8. +44
    -3
      consensus/reactor_test.go
  9. +23
    -7
      consensus/replay.go
  10. +2
    -1
      consensus/replay_test.go
  11. +35
    -26
      consensus/state.go
  12. +2
    -2
      consensus/state_test.go
  13. +1
    -0
      evidence/pool_test.go
  14. +2
    -1
      node/node.go
  15. +1
    -0
      proto/tendermint/abci/types.proto
  16. +85
    -49
      proto/tendermint/state/types.pb.go
  17. +2
    -1
      proto/tendermint/state/types.proto
  18. +1
    -1
      rpc/core/env.go
  19. +11
    -6
      state/execution.go
  20. +2
    -2
      state/execution_test.go
  21. +13
    -8
      state/state.go
  22. +13
    -8
      state/store.go
  23. +1
    -0
      state/store_test.go
  24. +15
    -5
      state/validation.go
  25. +16
    -9
      statesync/stateprovider.go
  26. +2
    -4
      types/block.go
  27. +7
    -0
      types/genesis.go
  28. +18
    -9
      types/genesis_test.go

+ 3
- 0
CHANGELOG_PENDING.md View File

@ -16,10 +16,13 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
- [evidence] [\#5181](https://github.com/tendermint/tendermint/pull/5181) Phantom validator evidence was removed (also from abci) (@cmwaters) - [evidence] [\#5181](https://github.com/tendermint/tendermint/pull/5181) Phantom validator evidence was removed (also from abci) (@cmwaters)
- [merkle] [\#5193](https://github.com/tendermint/tendermint/pull/5193) `HashFromByteSlices` and `ProofsFromByteSlices` now return a hash for empty inputs, following RFC6962 (@erikgrinaker) - [merkle] [\#5193](https://github.com/tendermint/tendermint/pull/5193) `HashFromByteSlices` and `ProofsFromByteSlices` now return a hash for empty inputs, following RFC6962 (@erikgrinaker)
- [crypto] [\#5214] Change `GenPrivKeySecp256k1` to `GenPrivKeyFromSecret` to be consistent with other keys - [crypto] [\#5214] Change `GenPrivKeySecp256k1` to `GenPrivKeyFromSecret` to be consistent with other keys
- [state] [\#5191](https://github.com/tendermint/tendermint/pull/5191/files) Add `State.InitialHeight` field to record initial block height, must be `1` (not `0`) to start from 1 (@erikgrinaker)
### FEATURES: ### FEATURES:
- [abci] [\#5174](https://github.com/tendermint/tendermint/pull/5174) Add amnesia evidence and remove mock and potential amnesia evidence from abci (@cmwaters) - [abci] [\#5174](https://github.com/tendermint/tendermint/pull/5174) Add amnesia evidence and remove mock and potential amnesia evidence from abci (@cmwaters)
- [abci] [\#5191](https://github.com/tendermint/tendermint/pull/5191/files) Add `InitChain.InitialHeight` field giving the initial block height (@erikgrinaker)
- [genesis] [\#5191](https://github.com/tendermint/tendermint/pull/5191/files) Add `initial_height` field to specify the initial chain height (defaults to `1`) (@erikgrinaker)
### IMPROVEMENTS: ### IMPROVEMENTS:


+ 9
- 0
UPGRADING.md View File

@ -32,6 +32,9 @@ if you want to learn more & support it (with cosmos-sdk you get it
`KV.Pair` has been replaced with `abci.EventAttribute`. `EventAttribute.Index` `KV.Pair` has been replaced with `abci.EventAttribute`. `EventAttribute.Index`
field allows ABCI applications to dictate which events should be indexed. field allows ABCI applications to dictate which events should be indexed.
The blockchain can now start from an arbitrary initial height, provided to the
application via `RequestInitChain.InitialHeight`.
### P2P Protocol ### P2P Protocol
The default codec is now proto3, not amino. Check out the [TODO]() for The default codec is now proto3, not amino. Check out the [TODO]() for
@ -137,6 +140,12 @@ functions) and `Client` object, which represents the complete light client.
RPC client can be found in `/rpc` directory. HTTP(S) proxy is located in RPC client can be found in `/rpc` directory. HTTP(S) proxy is located in
`/proxy` directory. `/proxy` directory.
### State
A field `State.InitialHeight` has been added to record the initial chain height, which must be `1`
(not `0`) if starting from height `1`. This can be configured via the genesis field
`initial_height`.
## v0.33.4 ## v0.33.4
### Go API ### Go API


+ 204
- 168
abci/types/types.pb.go View File

@ -585,6 +585,7 @@ type RequestInitChain struct {
ConsensusParams *ConsensusParams `protobuf:"bytes,3,opt,name=consensus_params,json=consensusParams,proto3" json:"consensus_params,omitempty"` ConsensusParams *ConsensusParams `protobuf:"bytes,3,opt,name=consensus_params,json=consensusParams,proto3" json:"consensus_params,omitempty"`
Validators []ValidatorUpdate `protobuf:"bytes,4,rep,name=validators,proto3" json:"validators"` Validators []ValidatorUpdate `protobuf:"bytes,4,rep,name=validators,proto3" json:"validators"`
AppStateBytes []byte `protobuf:"bytes,5,opt,name=app_state_bytes,json=appStateBytes,proto3" json:"app_state_bytes,omitempty"` AppStateBytes []byte `protobuf:"bytes,5,opt,name=app_state_bytes,json=appStateBytes,proto3" json:"app_state_bytes,omitempty"`
InitialHeight int64 `protobuf:"varint,6,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height,omitempty"`
} }
func (m *RequestInitChain) Reset() { *m = RequestInitChain{} } func (m *RequestInitChain) Reset() { *m = RequestInitChain{} }
@ -655,6 +656,13 @@ func (m *RequestInitChain) GetAppStateBytes() []byte {
return nil return nil
} }
func (m *RequestInitChain) GetInitialHeight() int64 {
if m != nil {
return m.InitialHeight
}
return 0
}
type RequestQuery struct { type RequestQuery struct {
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
@ -3162,174 +3170,175 @@ func init() {
func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) }
var fileDescriptor_252557cfdd89a31a = []byte{ var fileDescriptor_252557cfdd89a31a = []byte{
// 2663 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x3b, 0x77, 0x1b, 0xc7,
0x15, 0xc6, 0xfb, 0x71, 0x49, 0x3c, 0x38, 0xa2, 0x65, 0x68, 0x25, 0x91, 0xf2, 0xea, 0xd8, 0xb1,
0x64, 0x9b, 0x4c, 0xa8, 0x23, 0x45, 0x8a, 0x9d, 0xd8, 0x04, 0x0c, 0x05, 0xb4, 0x64, 0x92, 0x19,
0x52, 0x72, 0x5e, 0xd6, 0x7a, 0x81, 0x1d, 0x02, 0x6b, 0x01, 0xbb, 0x6b, 0xec, 0x80, 0x22, 0x5d,
0xc6, 0x49, 0xa3, 0x34, 0x4e, 0x97, 0xc6, 0x5d, 0x7e, 0x44, 0xaa, 0x34, 0x69, 0x5c, 0xba, 0x4c,
0xa5, 0xe4, 0x48, 0x27, 0x4d, 0xfe, 0x40, 0xca, 0xe4, 0xcc, 0x63, 0x5f, 0x00, 0x16, 0x00, 0xed,
0x74, 0xe9, 0xe6, 0x71, 0xef, 0x1d, 0xdc, 0xd9, 0xb9, 0xdf, 0xfd, 0xe6, 0x0e, 0xe0, 0x22, 0x25,
0x96, 0x41, 0x86, 0x03, 0xd3, 0xa2, 0x9b, 0x7a, 0xbb, 0x63, 0x6e, 0xd2, 0x53, 0x87, 0xb8, 0x1b,
0xce, 0xd0, 0xa6, 0x36, 0xaa, 0x04, 0x93, 0x1b, 0x6c, 0x52, 0xb9, 0x1c, 0x92, 0xee, 0x0c, 0x4f,
0x1d, 0x6a, 0x6f, 0x3a, 0x43, 0xdb, 0x3e, 0x12, 0xf2, 0xca, 0xa5, 0xd0, 0x34, 0xb7, 0x13, 0xb6,
0x16, 0x99, 0x95, 0xca, 0x8f, 0xc9, 0xa9, 0x37, 0x7b, 0x79, 0x42, 0xd7, 0xd1, 0x87, 0xfa, 0xc0,
0x9b, 0x5e, 0xef, 0xda, 0x76, 0xb7, 0x4f, 0x36, 0x79, 0xaf, 0x3d, 0x3a, 0xda, 0xa4, 0xe6, 0x80,
0xb8, 0x54, 0x1f, 0x38, 0x52, 0x60, 0xb5, 0x6b, 0x77, 0x6d, 0xde, 0xdc, 0x64, 0x2d, 0x31, 0xaa,
0xfe, 0xa1, 0x00, 0x79, 0x4c, 0x3e, 0x1b, 0x11, 0x97, 0xa2, 0x2d, 0xc8, 0x90, 0x4e, 0xcf, 0xae,
0x25, 0xaf, 0x24, 0x5f, 0x5f, 0xda, 0xba, 0xb4, 0x31, 0xe6, 0xdc, 0x86, 0x94, 0x6b, 0x76, 0x7a,
0x76, 0x2b, 0x81, 0xb9, 0x2c, 0xba, 0x09, 0xd9, 0xa3, 0xfe, 0xc8, 0xed, 0xd5, 0x52, 0x5c, 0xe9,
0x72, 0x9c, 0xd2, 0x5d, 0x26, 0xd4, 0x4a, 0x60, 0x21, 0xcd, 0x96, 0x32, 0xad, 0x23, 0xbb, 0x96,
0x9e, 0xbd, 0xd4, 0x8e, 0x75, 0xc4, 0x97, 0x62, 0xb2, 0xa8, 0x0e, 0xe0, 0x12, 0xaa, 0xd9, 0x0e,
0x35, 0x6d, 0xab, 0x96, 0xe1, 0x9a, 0xaf, 0xc4, 0x69, 0x1e, 0x10, 0xba, 0xc7, 0x05, 0x5b, 0x09,
0x5c, 0x74, 0xbd, 0x0e, 0xb3, 0x61, 0x5a, 0x26, 0xd5, 0x3a, 0x3d, 0xdd, 0xb4, 0x6a, 0xd9, 0xd9,
0x36, 0x76, 0x2c, 0x93, 0x36, 0x98, 0x20, 0xb3, 0x61, 0x7a, 0x1d, 0xe6, 0xf2, 0x67, 0x23, 0x32,
0x3c, 0xad, 0xe5, 0x66, 0xbb, 0xfc, 0x33, 0x26, 0xc4, 0x5c, 0xe6, 0xd2, 0xa8, 0x09, 0x4b, 0x6d,
0xd2, 0x35, 0x2d, 0xad, 0xdd, 0xb7, 0x3b, 0x8f, 0x6b, 0x79, 0xae, 0xac, 0xc6, 0x29, 0xd7, 0x99,
0x68, 0x9d, 0x49, 0xb6, 0x12, 0x18, 0xda, 0x7e, 0x0f, 0xbd, 0x03, 0x85, 0x4e, 0x8f, 0x74, 0x1e,
0x6b, 0xf4, 0xa4, 0x56, 0xe0, 0x36, 0xd6, 0xe3, 0x6c, 0x34, 0x98, 0xdc, 0xe1, 0x49, 0x2b, 0x81,
0xf3, 0x1d, 0xd1, 0x64, 0xfe, 0x1b, 0xa4, 0x6f, 0x1e, 0x93, 0x21, 0xd3, 0x2f, 0xce, 0xf6, 0xff,
0x7d, 0x21, 0xc9, 0x2d, 0x14, 0x0d, 0xaf, 0x83, 0xde, 0x85, 0x22, 0xb1, 0x0c, 0xe9, 0x06, 0x70,
0x13, 0x57, 0x62, 0xcf, 0x8a, 0x65, 0x78, 0x4e, 0x14, 0x88, 0x6c, 0xa3, 0xdb, 0x90, 0xeb, 0xd8,
0x83, 0x81, 0x49, 0x6b, 0x4b, 0x5c, 0x7b, 0x2d, 0xd6, 0x01, 0x2e, 0xd5, 0x4a, 0x60, 0x29, 0x8f,
0x76, 0xa1, 0xdc, 0x37, 0x5d, 0xaa, 0xb9, 0x96, 0xee, 0xb8, 0x3d, 0x9b, 0xba, 0xb5, 0x65, 0x6e,
0xe1, 0xd5, 0x38, 0x0b, 0xf7, 0x4d, 0x97, 0x1e, 0x78, 0xc2, 0xad, 0x04, 0x2e, 0xf5, 0xc3, 0x03,
0xcc, 0x9e, 0x7d, 0x74, 0x44, 0x86, 0xbe, 0xc1, 0x5a, 0x69, 0xb6, 0xbd, 0x3d, 0x26, 0xed, 0xe9,
0x33, 0x7b, 0x76, 0x78, 0x00, 0xfd, 0x0a, 0xce, 0xf5, 0x6d, 0xdd, 0xf0, 0xcd, 0x69, 0x9d, 0xde,
0xc8, 0x7a, 0x5c, 0x2b, 0x73, 0xa3, 0xd7, 0x62, 0x7f, 0xa4, 0xad, 0x1b, 0x9e, 0x89, 0x06, 0x53,
0x68, 0x25, 0xf0, 0x4a, 0x7f, 0x7c, 0x10, 0x3d, 0x82, 0x55, 0xdd, 0x71, 0xfa, 0xa7, 0xe3, 0xd6,
0x2b, 0xdc, 0xfa, 0xf5, 0x38, 0xeb, 0xdb, 0x4c, 0x67, 0xdc, 0x3c, 0xd2, 0x27, 0x46, 0xeb, 0x79,
0xc8, 0x1e, 0xeb, 0xfd, 0x11, 0x51, 0xbf, 0x07, 0x4b, 0xa1, 0x50, 0x47, 0x35, 0xc8, 0x0f, 0x88,
0xeb, 0xea, 0x5d, 0xc2, 0x91, 0xa1, 0x88, 0xbd, 0xae, 0x5a, 0x86, 0xe5, 0x70, 0x78, 0xab, 0x03,
0x5f, 0x91, 0x05, 0x2e, 0x53, 0x3c, 0x26, 0x43, 0x97, 0x45, 0xab, 0x54, 0x94, 0x5d, 0x74, 0x15,
0x4a, 0xfc, 0xf8, 0x68, 0xde, 0x3c, 0x43, 0x8f, 0x0c, 0x5e, 0xe6, 0x83, 0x0f, 0xa5, 0xd0, 0x3a,
0x2c, 0x39, 0x5b, 0x8e, 0x2f, 0x92, 0xe6, 0x22, 0xe0, 0x6c, 0x39, 0x52, 0x40, 0xfd, 0x11, 0x54,
0xc7, 0xa3, 0x1d, 0x55, 0x21, 0xfd, 0x98, 0x9c, 0xca, 0xf5, 0x58, 0x13, 0xad, 0x4a, 0xb7, 0xf8,
0x1a, 0x45, 0x2c, 0x7d, 0xfc, 0x53, 0xca, 0x57, 0xf6, 0xc3, 0x1c, 0xdd, 0x86, 0x0c, 0x43, 0x4d,
0x09, 0x80, 0xca, 0x86, 0x80, 0xd4, 0x0d, 0x0f, 0x52, 0x37, 0x0e, 0x3d, 0x48, 0xad, 0x17, 0xbe,
0x7e, 0xb6, 0x9e, 0xf8, 0xf2, 0xef, 0xeb, 0x49, 0xcc, 0x35, 0xd0, 0x05, 0x16, 0x95, 0xba, 0x69,
0x69, 0xa6, 0x21, 0xd7, 0xc9, 0xf3, 0xfe, 0x8e, 0x81, 0xee, 0x41, 0xb5, 0x63, 0x5b, 0x2e, 0xb1,
0xdc, 0x91, 0xab, 0x09, 0xc8, 0x96, 0xb0, 0x37, 0x19, 0x35, 0x0d, 0x4f, 0x70, 0x9f, 0xcb, 0xe1,
0x4a, 0x27, 0x3a, 0x80, 0xee, 0x02, 0x1c, 0xeb, 0x7d, 0xd3, 0xd0, 0xa9, 0x3d, 0x74, 0x6b, 0x99,
0x2b, 0xe9, 0xa9, 0x66, 0x1e, 0x7a, 0x22, 0x0f, 0x1c, 0x43, 0xa7, 0xa4, 0x9e, 0x61, 0xbf, 0x16,
0x87, 0x34, 0xd1, 0x6b, 0x50, 0xd1, 0x1d, 0x47, 0x73, 0xa9, 0x4e, 0x89, 0xd6, 0x3e, 0xa5, 0xc4,
0xe5, 0x60, 0xb8, 0x8c, 0x4b, 0xba, 0xe3, 0x1c, 0xb0, 0xd1, 0x3a, 0x1b, 0x54, 0x0d, 0xff, 0x0b,
0x73, 0x34, 0x43, 0x08, 0x32, 0x86, 0x4e, 0x75, 0xbe, 0x43, 0xcb, 0x98, 0xb7, 0xd9, 0x98, 0xa3,
0xd3, 0x9e, 0xf4, 0x9b, 0xb7, 0xd1, 0x79, 0xc8, 0xf5, 0x88, 0xd9, 0xed, 0x51, 0xee, 0x6a, 0x1a,
0xcb, 0x1e, 0xfb, 0x18, 0xce, 0xd0, 0x3e, 0x26, 0x1c, 0xbe, 0x0b, 0x58, 0x74, 0xd4, 0xdf, 0xa6,
0x60, 0x65, 0x02, 0xf7, 0x98, 0xdd, 0x9e, 0xee, 0xf6, 0xbc, 0xb5, 0x58, 0x1b, 0xdd, 0x62, 0x76,
0x75, 0x83, 0x0c, 0x65, 0xbe, 0xa9, 0x85, 0x7d, 0x17, 0xb9, 0xb4, 0xc5, 0xe7, 0xa5, 0xcf, 0x52,
0x1a, 0xed, 0x41, 0xb5, 0xaf, 0xbb, 0x54, 0x13, 0x38, 0xa2, 0x85, 0x72, 0xcf, 0x24, 0x7a, 0xde,
0xd7, 0x3d, 0xe4, 0x61, 0xa7, 0x58, 0x1a, 0x2a, 0xf7, 0x23, 0xa3, 0x08, 0xc3, 0x6a, 0xfb, 0xf4,
0x73, 0xdd, 0xa2, 0xa6, 0x45, 0xb4, 0x89, 0x4f, 0x72, 0x61, 0xc2, 0x68, 0xf3, 0xd8, 0x34, 0x88,
0xd5, 0xf1, 0xbe, 0xc5, 0x39, 0x5f, 0xd9, 0xff, 0x56, 0xae, 0x8a, 0xa1, 0x1c, 0x45, 0x6e, 0x54,
0x86, 0x14, 0x3d, 0x91, 0x1b, 0x90, 0xa2, 0x27, 0xe8, 0xfb, 0x90, 0x61, 0x4e, 0x72, 0xe7, 0xcb,
0x53, 0xd2, 0xa6, 0xd4, 0x3b, 0x3c, 0x75, 0x08, 0xe6, 0x92, 0xaa, 0xea, 0x1f, 0x73, 0x1f, 0xcd,
0xc7, 0xad, 0xaa, 0xd7, 0xa0, 0x32, 0x06, 0xd7, 0xa1, 0xef, 0x97, 0x0c, 0x7f, 0x3f, 0xb5, 0x02,
0xa5, 0x08, 0x36, 0xab, 0xe7, 0x61, 0x75, 0x1a, 0xd4, 0xaa, 0x3d, 0x7f, 0x3c, 0x02, 0x99, 0xe8,
0x26, 0x14, 0x7c, 0xac, 0x15, 0x61, 0x36, 0xb9, 0x57, 0x9e, 0x30, 0xf6, 0x45, 0x59, 0x7c, 0xb1,
0xf3, 0xca, 0xcf, 0x43, 0x8a, 0xff, 0xf0, 0xbc, 0xee, 0x38, 0x2d, 0xdd, 0xed, 0xa9, 0x9f, 0x40,
0x2d, 0x0e, 0x47, 0xc7, 0xdc, 0xc8, 0xf8, 0xc7, 0xf0, 0x3c, 0xe4, 0x8e, 0xec, 0xe1, 0x40, 0xa7,
0xdc, 0x58, 0x09, 0xcb, 0x1e, 0x3b, 0x9e, 0x02, 0x53, 0xd3, 0x7c, 0x58, 0x74, 0x54, 0x0d, 0x2e,
0xc4, 0x62, 0x29, 0x53, 0x31, 0x2d, 0x83, 0x88, 0xfd, 0x2c, 0x61, 0xd1, 0x09, 0x0c, 0x89, 0x1f,
0x2b, 0x3a, 0x6c, 0x59, 0x97, 0xfb, 0xca, 0xed, 0x17, 0xb1, 0xec, 0xa9, 0xff, 0x2c, 0x40, 0x01,
0x13, 0xd7, 0x61, 0xc1, 0x8e, 0xea, 0x50, 0x24, 0x27, 0x1d, 0x22, 0x58, 0x4e, 0x32, 0x96, 0x25,
0x08, 0xe9, 0xa6, 0x27, 0xc9, 0x52, 0xb4, 0xaf, 0x86, 0x6e, 0x48, 0x26, 0x17, 0x4f, 0xca, 0xa4,
0x7a, 0x98, 0xca, 0xdd, 0xf2, 0xa8, 0x5c, 0x3a, 0x36, 0x2b, 0x0b, 0xad, 0x31, 0x2e, 0x77, 0x43,
0x72, 0xb9, 0xcc, 0x9c, 0xc5, 0x22, 0x64, 0xae, 0x11, 0x21, 0x73, 0xd9, 0x39, 0x6e, 0xc6, 0xb0,
0xb9, 0x46, 0x84, 0xcd, 0xe5, 0xe6, 0x18, 0x89, 0xa1, 0x73, 0xb7, 0x3c, 0x3a, 0x97, 0x9f, 0xe3,
0xf6, 0x18, 0x9f, 0xbb, 0x1b, 0xe5, 0x73, 0x82, 0x8b, 0x5d, 0x8d, 0xd5, 0x8e, 0x25, 0x74, 0x3f,
0x0e, 0x11, 0xba, 0x62, 0x2c, 0x9b, 0x12, 0x46, 0xa6, 0x30, 0xba, 0x46, 0x84, 0xd1, 0xc1, 0x9c,
0x3d, 0x88, 0xa1, 0x74, 0xef, 0x85, 0x29, 0xdd, 0x52, 0x2c, 0x2b, 0x94, 0x87, 0x66, 0x1a, 0xa7,
0xbb, 0xe3, 0x73, 0xba, 0xe5, 0x58, 0x52, 0x2a, 0x7d, 0x18, 0x27, 0x75, 0x7b, 0x13, 0xa4, 0x4e,
0x90, 0xb0, 0xd7, 0x62, 0x4d, 0xcc, 0x61, 0x75, 0x7b, 0x13, 0xac, 0xae, 0x3c, 0xc7, 0xe0, 0x1c,
0x5a, 0xf7, 0xeb, 0xe9, 0xb4, 0x2e, 0x9e, 0x78, 0xc9, 0x9f, 0xb9, 0x18, 0xaf, 0xd3, 0x62, 0x78,
0x5d, 0x95, 0x9b, 0x7f, 0x23, 0xd6, 0xfc, 0xd9, 0x89, 0xdd, 0x35, 0x96, 0x66, 0xc7, 0x80, 0x83,
0x41, 0x15, 0x19, 0x0e, 0xed, 0xa1, 0xe4, 0x4c, 0xa2, 0xa3, 0xbe, 0xce, 0x12, 0x7f, 0x00, 0x12,
0x33, 0x48, 0x20, 0x4f, 0x09, 0x21, 0x60, 0x50, 0xff, 0x9c, 0x0c, 0x74, 0x79, 0xae, 0x0c, 0x93,
0x86, 0xa2, 0x24, 0x0d, 0x21, 0x6e, 0x98, 0x8a, 0x72, 0xc3, 0x75, 0x58, 0x62, 0x50, 0x3f, 0x46,
0xfb, 0x74, 0xc7, 0xa3, 0x7d, 0xe8, 0x3a, 0xac, 0xf0, 0x5c, 0x2e, 0x18, 0xa4, 0xc4, 0xf7, 0x0c,
0x4f, 0x53, 0x15, 0x36, 0x21, 0x0e, 0xa7, 0x00, 0xfa, 0xb7, 0xe0, 0x5c, 0x48, 0xd6, 0x4f, 0x21,
0x82, 0xeb, 0x54, 0x7d, 0xe9, 0x6d, 0x99, 0x4b, 0x3e, 0x0c, 0x36, 0x28, 0xa0, 0x94, 0x08, 0x32,
0x1d, 0xdb, 0x20, 0x12, 0xe0, 0x79, 0x9b, 0xd1, 0xcc, 0xbe, 0xdd, 0x95, 0x30, 0xce, 0x9a, 0x4c,
0xca, 0x47, 0xc1, 0xa2, 0x00, 0x39, 0xf5, 0xaf, 0xc9, 0xc0, 0x5e, 0xc0, 0x32, 0xa7, 0x11, 0xc2,
0xe4, 0xff, 0x86, 0x10, 0xa6, 0xbe, 0x35, 0x21, 0x0c, 0x27, 0xd8, 0x74, 0x34, 0xc1, 0xfe, 0x3b,
0x19, 0x7c, 0x61, 0x9f, 0x05, 0x7e, 0xbb, 0x1d, 0x09, 0xb2, 0x65, 0x96, 0x7f, 0x2f, 0x99, 0x2d,
0x25, 0x69, 0xcf, 0xf1, 0x75, 0xa3, 0xa4, 0x3d, 0x2f, 0xf2, 0x27, 0xef, 0xa0, 0xdb, 0x50, 0xe4,
0xd5, 0x14, 0xcd, 0x76, 0x5c, 0x09, 0xb8, 0x17, 0xc3, 0xbe, 0x8a, 0xa2, 0xc9, 0xc6, 0x3e, 0x93,
0xd9, 0x73, 0x5c, 0x5c, 0x70, 0x64, 0x2b, 0x44, 0x04, 0x8a, 0x11, 0x3e, 0x7a, 0x09, 0x8a, 0xec,
0xd7, 0xbb, 0x8e, 0xde, 0x21, 0x1c, 0x3c, 0x8b, 0x38, 0x18, 0x50, 0x1f, 0x01, 0x9a, 0x84, 0x6f,
0xd4, 0x82, 0x1c, 0x39, 0x26, 0x16, 0x65, 0x5f, 0x8d, 0x6d, 0xf7, 0xf9, 0x29, 0x64, 0x8f, 0x58,
0xb4, 0x5e, 0x63, 0x9b, 0xfc, 0xaf, 0x67, 0xeb, 0x55, 0x21, 0xfd, 0xa6, 0x3d, 0x30, 0x29, 0x19,
0x38, 0xf4, 0x14, 0x4b, 0x7d, 0xf5, 0x8b, 0x14, 0x63, 0x5e, 0x11, 0x68, 0x9f, 0xba, 0xb7, 0x5e,
0x00, 0xa5, 0x42, 0xac, 0x7b, 0xb1, 0xfd, 0x5e, 0x03, 0xe8, 0xea, 0xae, 0xf6, 0x44, 0xb7, 0x28,
0x31, 0xe4, 0xa6, 0x87, 0x46, 0x90, 0x02, 0x05, 0xd6, 0x1b, 0xb9, 0xc4, 0xe0, 0xdb, 0x9f, 0xc6,
0x7e, 0x3f, 0xe4, 0x67, 0xfe, 0xbb, 0xf9, 0x19, 0xdd, 0xe5, 0xc2, 0xf8, 0x2e, 0xff, 0x2e, 0x15,
0x44, 0x49, 0x40, 0x52, 0xff, 0xff, 0xf6, 0xe1, 0xf7, 0xfc, 0x4a, 0x1a, 0xcd, 0xb1, 0xe8, 0x00,
0x56, 0xfc, 0x28, 0xd5, 0x46, 0x3c, 0x7a, 0xbd, 0x73, 0xb7, 0x68, 0x98, 0x57, 0x8f, 0xa3, 0xc3,
0x2e, 0xfa, 0x39, 0xbc, 0x3c, 0x86, 0x40, 0xbe, 0xe9, 0xd4, 0x82, 0x40, 0xf4, 0x52, 0x14, 0x88,
0x3c, 0xcb, 0xc1, 0x5e, 0xa5, 0xbf, 0x63, 0x6c, 0xec, 0xb0, 0xcb, 0x50, 0x98, 0x31, 0x4c, 0xfd,
0xfa, 0x57, 0xa1, 0x34, 0x24, 0x94, 0x5d, 0xbc, 0x23, 0xd7, 0xcd, 0x65, 0x31, 0x28, 0x92, 0x80,
0xba, 0x0f, 0x2f, 0x4d, 0x65, 0x0e, 0xe8, 0x87, 0x50, 0x0c, 0x48, 0x47, 0x32, 0xe6, 0xe6, 0xe6,
0xdf, 0x46, 0x02, 0x59, 0xf5, 0x2f, 0xc9, 0xc0, 0x64, 0xf4, 0x7e, 0xd3, 0x84, 0xdc, 0x90, 0xb8,
0xa3, 0xbe, 0xb8, 0x71, 0x94, 0xb7, 0xde, 0x5a, 0x8c, 0x73, 0xb0, 0xd1, 0x51, 0x9f, 0x62, 0xa9,
0xac, 0x3e, 0x82, 0x9c, 0x18, 0x41, 0x4b, 0x90, 0x7f, 0xb0, 0x7b, 0x6f, 0x77, 0xef, 0xa3, 0xdd,
0x6a, 0x02, 0x01, 0xe4, 0xb6, 0x1b, 0x8d, 0xe6, 0xfe, 0x61, 0x35, 0x89, 0x8a, 0x90, 0xdd, 0xae,
0xef, 0xe1, 0xc3, 0x6a, 0x8a, 0x0d, 0xe3, 0xe6, 0x07, 0xcd, 0xc6, 0x61, 0x35, 0x8d, 0x56, 0xa0,
0x24, 0xda, 0xda, 0xdd, 0x3d, 0xfc, 0xe1, 0xf6, 0x61, 0x35, 0x13, 0x1a, 0x3a, 0x68, 0xee, 0xbe,
0xdf, 0xc4, 0xd5, 0xac, 0xfa, 0x03, 0x76, 0xa5, 0x89, 0x61, 0x29, 0xc1, 0xe5, 0x25, 0x19, 0xba,
0xbc, 0xa8, 0x7f, 0x4c, 0x81, 0x12, 0x4f, 0x3d, 0xd0, 0x07, 0x63, 0x8e, 0x6f, 0x9d, 0x81, 0xb7,
0x8c, 0x79, 0x8f, 0x5e, 0x85, 0xf2, 0x90, 0x1c, 0x11, 0xda, 0xe9, 0x09, 0x2a, 0x24, 0x12, 0x5b,
0x09, 0x97, 0xe4, 0x28, 0x57, 0x72, 0x85, 0xd8, 0xa7, 0xa4, 0x43, 0x35, 0x71, 0x8f, 0x12, 0x87,
0xae, 0xc8, 0xc4, 0xd8, 0xe8, 0x81, 0x18, 0x54, 0x3f, 0x39, 0xd3, 0x5e, 0x16, 0x21, 0x8b, 0x9b,
0x87, 0xf8, 0x17, 0xd5, 0x34, 0x42, 0x50, 0xe6, 0x4d, 0xed, 0x60, 0x77, 0x7b, 0xff, 0xa0, 0xb5,
0xc7, 0xf6, 0xf2, 0x1c, 0x54, 0xbc, 0xbd, 0xf4, 0x06, 0xb3, 0xea, 0x7f, 0x92, 0x50, 0x19, 0x0b,
0x10, 0xb4, 0x05, 0x59, 0x41, 0xa7, 0xe3, 0xaa, 0xe9, 0x3c, 0xbe, 0x65, 0x34, 0x09, 0x51, 0xf4,
0x0e, 0x14, 0x88, 0xac, 0x13, 0x4c, 0x0b, 0x44, 0x51, 0xdf, 0xf0, 0x2a, 0x09, 0x52, 0xd5, 0xd7,
0x40, 0xef, 0x42, 0xd1, 0x8f, 0x74, 0x79, 0x87, 0x7b, 0x65, 0x52, 0xdd, 0xc7, 0x08, 0xa9, 0x1f,
0xe8, 0xa0, 0x3b, 0x01, 0x27, 0xcb, 0x4c, 0x92, 0x78, 0xa9, 0x2e, 0x04, 0xa4, 0xb2, 0x27, 0xaf,
0x36, 0x60, 0x29, 0xe4, 0x0f, 0xba, 0x08, 0xc5, 0x81, 0x7e, 0x22, 0x0b, 0x4b, 0xa2, 0x82, 0x50,
0x18, 0xe8, 0x27, 0xbc, 0xa6, 0x84, 0x5e, 0x86, 0x3c, 0x9b, 0xec, 0xea, 0x02, 0x6d, 0xd2, 0x38,
0x37, 0xd0, 0x4f, 0x7e, 0xaa, 0xbb, 0xea, 0xc7, 0x50, 0x8e, 0xd6, 0x5e, 0xd8, 0x49, 0x1c, 0xda,
0x23, 0xcb, 0xe0, 0x36, 0xb2, 0x58, 0x74, 0xd0, 0x4d, 0xc8, 0x1e, 0xdb, 0x02, 0xac, 0xa6, 0x87,
0xec, 0x43, 0x9b, 0x92, 0x50, 0xed, 0x46, 0x48, 0xab, 0x9f, 0x43, 0x96, 0x83, 0x0f, 0x03, 0x12,
0x5e, 0x45, 0x91, 0x7c, 0x94, 0xb5, 0xd1, 0xc7, 0x00, 0x3a, 0xa5, 0x43, 0xb3, 0x3d, 0x0a, 0x0c,
0xaf, 0x4f, 0x07, 0xaf, 0x6d, 0x4f, 0xae, 0x7e, 0x49, 0xa2, 0xd8, 0x6a, 0xa0, 0x1a, 0x42, 0xb2,
0x90, 0x41, 0x75, 0x17, 0xca, 0x51, 0xdd, 0x70, 0xa1, 0x72, 0x79, 0x4a, 0xa1, 0xd2, 0xe7, 0x3c,
0x3e, 0x63, 0x4a, 0x8b, 0x8a, 0x19, 0xef, 0xa8, 0x4f, 0x93, 0x50, 0x38, 0x3c, 0x91, 0xc7, 0x3a,
0xa6, 0x58, 0x13, 0xa8, 0xa6, 0xc2, 0xa5, 0x09, 0x51, 0xfd, 0x49, 0xfb, 0x35, 0xa5, 0xf7, 0xfc,
0xc0, 0xcd, 0x2c, 0x7a, 0x79, 0xf4, 0x8a, 0x6b, 0x12, 0xac, 0xde, 0x86, 0xa2, 0x7f, 0xaa, 0x18,
0xb1, 0xd7, 0x0d, 0x63, 0x48, 0x5c, 0x57, 0xfa, 0xe6, 0x75, 0x79, 0xed, 0xcf, 0x7e, 0x22, 0x8b,
0x1f, 0x69, 0x2c, 0x3a, 0xaa, 0x01, 0x95, 0xb1, 0xb4, 0x85, 0xde, 0x86, 0xbc, 0x33, 0x6a, 0x6b,
0xde, 0xf6, 0x8c, 0x05, 0x8f, 0x47, 0xf2, 0x46, 0xed, 0xbe, 0xd9, 0xb9, 0x47, 0x4e, 0xbd, 0x1f,
0xe3, 0x8c, 0xda, 0xf7, 0xc4, 0x2e, 0x8a, 0x55, 0x52, 0xe1, 0x55, 0x8e, 0xa1, 0xe0, 0x1d, 0x0a,
0xf4, 0x93, 0x70, 0x9c, 0x78, 0xa5, 0xde, 0xd8, 0x54, 0x2a, 0xcd, 0x87, 0xc2, 0xe4, 0x3a, 0xac,
0xb8, 0x66, 0xd7, 0x22, 0x86, 0x16, 0x5c, 0x2d, 0xf8, 0x6a, 0x05, 0x5c, 0x11, 0x13, 0xf7, 0xbd,
0x7b, 0x85, 0xfa, 0x2c, 0x09, 0x05, 0x2f, 0x60, 0xa7, 0x9e, 0xbb, 0xc8, 0x8f, 0x49, 0x9d, 0xfd,
0xc7, 0xc4, 0x15, 0x5a, 0xbd, 0x52, 0x76, 0xe6, 0xcc, 0xa5, 0xec, 0x37, 0x01, 0x51, 0x9b, 0xea,
0x7d, 0xed, 0xd8, 0xa6, 0xa6, 0xd5, 0xd5, 0xc4, 0x6e, 0x0a, 0xca, 0x54, 0xe5, 0x33, 0x0f, 0xf9,
0xc4, 0x3e, 0xdf, 0xd8, 0xdf, 0x24, 0xa1, 0xe0, 0x27, 0xbf, 0xb3, 0x96, 0xdb, 0xce, 0x43, 0x4e,
0xe2, 0xbb, 0xa8, 0xb7, 0xc9, 0x9e, 0x5f, 0xf9, 0xcd, 0x84, 0x2a, 0xbf, 0x0a, 0x14, 0x06, 0x84,
0xea, 0x9c, 0x01, 0x88, 0xeb, 0x9b, 0xdf, 0xbf, 0x7e, 0x07, 0x96, 0x42, 0x95, 0x4f, 0x16, 0x5a,
0xbb, 0xcd, 0x8f, 0xaa, 0x09, 0x25, 0xff, 0xf4, 0xab, 0x2b, 0xe9, 0x5d, 0xf2, 0x84, 0x1d, 0x4a,
0xdc, 0x6c, 0xb4, 0x9a, 0x8d, 0x7b, 0xd5, 0xa4, 0xb2, 0xf4, 0xf4, 0xab, 0x2b, 0x79, 0x4c, 0x78,
0x01, 0x65, 0xeb, 0x0b, 0x80, 0xca, 0x76, 0xbd, 0xb1, 0xc3, 0x92, 0x92, 0xd9, 0xd1, 0x65, 0x59,
0x29, 0xc3, 0xef, 0xbc, 0x33, 0x5f, 0x40, 0x95, 0xd9, 0x55, 0x35, 0x74, 0x17, 0xb2, 0xfc, 0x3a,
0x8c, 0x66, 0x3f, 0x89, 0x2a, 0x73, 0xca, 0x6c, 0xec, 0xc7, 0xf0, 0x53, 0x3b, 0xf3, 0x8d, 0x54,
0x99, 0x5d, 0x75, 0x43, 0x18, 0x8a, 0xc1, 0x7d, 0x76, 0xfe, 0x9b, 0xa9, 0xb2, 0x40, 0x25, 0x8e,
0xd9, 0x0c, 0xd8, 0xfa, 0xfc, 0x37, 0x44, 0x65, 0x01, 0x5c, 0x41, 0xf7, 0x21, 0xef, 0xdd, 0x83,
0xe6, 0xbd, 0x6a, 0x2a, 0x73, 0xab, 0x64, 0xec, 0x13, 0x88, 0xfb, 0xea, 0xec, 0x27, 0x5a, 0x65,
0x4e, 0xc9, 0x0f, 0xed, 0x40, 0x4e, 0x52, 0xd0, 0x39, 0x2f, 0x95, 0xca, 0xbc, 0xaa, 0x17, 0xdb,
0xb4, 0xa0, 0x10, 0x30, 0xff, 0xe1, 0x59, 0x59, 0xa0, 0x9a, 0x89, 0x1e, 0x00, 0x84, 0x6e, 0xa7,
0x0b, 0xbc, 0x28, 0x2b, 0x8b, 0x54, 0x29, 0xd1, 0x1e, 0x14, 0xfc, 0x5b, 0xc8, 0xdc, 0xf7, 0x5d,
0x65, 0x7e, 0xb9, 0x10, 0x3d, 0x82, 0x52, 0x94, 0x7e, 0x2f, 0xf6, 0x6a, 0xab, 0x2c, 0x58, 0x07,
0x64, 0xf6, 0xa3, 0x5c, 0x7c, 0xb1, 0x57, 0x5c, 0x65, 0xc1, 0xb2, 0x20, 0xfa, 0x14, 0x56, 0x26,
0xb9, 0xf2, 0xe2, 0x8f, 0xba, 0xca, 0x19, 0x0a, 0x85, 0x68, 0x00, 0x68, 0x0a, 0xc7, 0x3e, 0xc3,
0x1b, 0xaf, 0x72, 0x96, 0xba, 0x61, 0xbd, 0xf9, 0xf5, 0xf3, 0xb5, 0xe4, 0x37, 0xcf, 0xd7, 0x92,
0xff, 0x78, 0xbe, 0x96, 0xfc, 0xf2, 0xc5, 0x5a, 0xe2, 0x9b, 0x17, 0x6b, 0x89, 0xbf, 0xbd, 0x58,
0x4b, 0xfc, 0xf2, 0x8d, 0xae, 0x49, 0x7b, 0xa3, 0xf6, 0x46, 0xc7, 0x1e, 0x6c, 0x86, 0xff, 0x80,
0x32, 0xed, 0x4f, 0x31, 0xed, 0x1c, 0x4f, 0x2f, 0x37, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x5f,
0xba, 0xe8, 0xf8, 0x34, 0x23, 0x00, 0x00,
// 2681 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4b, 0x73, 0x1b, 0xc7,
0x11, 0xc6, 0xfb, 0xd1, 0x24, 0x1e, 0x1c, 0xd1, 0x32, 0xbc, 0x92, 0x48, 0x79, 0x55, 0x72, 0x2c,
0xd9, 0x26, 0x13, 0xaa, 0xa4, 0x48, 0xb1, 0x13, 0x9b, 0x80, 0xa1, 0x80, 0x96, 0x4c, 0x32, 0x4b,
0x4a, 0xce, 0xcb, 0x5a, 0x0f, 0xb0, 0x43, 0x60, 0x2d, 0x60, 0x77, 0x8d, 0x1d, 0x50, 0xa4, 0x8f,
0x71, 0x72, 0x51, 0x2e, 0xce, 0x2d, 0x17, 0xff, 0x8f, 0x9c, 0x72, 0xc9, 0xc5, 0x55, 0xb9, 0xf8,
0x98, 0x93, 0x92, 0x92, 0x2a, 0x97, 0xfc, 0x81, 0x1c, 0x93, 0x9a, 0xc7, 0xbe, 0x00, 0x2c, 0x00,
0xda, 0xb9, 0xe5, 0x36, 0xd3, 0xdb, 0xdd, 0x8b, 0xe9, 0x9d, 0xfe, 0xe6, 0xeb, 0x1e, 0xc0, 0x05,
0x4a, 0x2c, 0x83, 0x0c, 0x07, 0xa6, 0x45, 0x37, 0x71, 0xbb, 0x63, 0x6e, 0xd2, 0x53, 0x87, 0xb8,
0x1b, 0xce, 0xd0, 0xa6, 0x36, 0xaa, 0x04, 0x0f, 0x37, 0xd8, 0x43, 0xe5, 0x52, 0x48, 0xbb, 0x33,
0x3c, 0x75, 0xa8, 0xbd, 0xe9, 0x0c, 0x6d, 0xfb, 0x48, 0xe8, 0x2b, 0x17, 0x43, 0x8f, 0xb9, 0x9f,
0xb0, 0xb7, 0xc8, 0x53, 0x69, 0xfc, 0x98, 0x9c, 0x7a, 0x4f, 0x2f, 0x4d, 0xd8, 0x3a, 0x78, 0x88,
0x07, 0xde, 0xe3, 0xf5, 0xae, 0x6d, 0x77, 0xfb, 0x64, 0x93, 0xcf, 0xda, 0xa3, 0xa3, 0x4d, 0x6a,
0x0e, 0x88, 0x4b, 0xf1, 0xc0, 0x91, 0x0a, 0xab, 0x5d, 0xbb, 0x6b, 0xf3, 0xe1, 0x26, 0x1b, 0x09,
0xa9, 0xfa, 0x87, 0x02, 0xe4, 0x35, 0xf2, 0xd9, 0x88, 0xb8, 0x14, 0x6d, 0x41, 0x86, 0x74, 0x7a,
0x76, 0x2d, 0x79, 0x39, 0xf9, 0xfa, 0xd2, 0xd6, 0xc5, 0x8d, 0xb1, 0xc5, 0x6d, 0x48, 0xbd, 0x66,
0xa7, 0x67, 0xb7, 0x12, 0x1a, 0xd7, 0x45, 0x37, 0x21, 0x7b, 0xd4, 0x1f, 0xb9, 0xbd, 0x5a, 0x8a,
0x1b, 0x5d, 0x8a, 0x33, 0xba, 0xcb, 0x94, 0x5a, 0x09, 0x4d, 0x68, 0xb3, 0x57, 0x99, 0xd6, 0x91,
0x5d, 0x4b, 0xcf, 0x7e, 0xd5, 0x8e, 0x75, 0xc4, 0x5f, 0xc5, 0x74, 0x51, 0x1d, 0xc0, 0x25, 0x54,
0xb7, 0x1d, 0x6a, 0xda, 0x56, 0x2d, 0xc3, 0x2d, 0x5f, 0x8d, 0xb3, 0x3c, 0x20, 0x74, 0x8f, 0x2b,
0xb6, 0x12, 0x5a, 0xd1, 0xf5, 0x26, 0xcc, 0x87, 0x69, 0x99, 0x54, 0xef, 0xf4, 0xb0, 0x69, 0xd5,
0xb2, 0xb3, 0x7d, 0xec, 0x58, 0x26, 0x6d, 0x30, 0x45, 0xe6, 0xc3, 0xf4, 0x26, 0x6c, 0xc9, 0x9f,
0x8d, 0xc8, 0xf0, 0xb4, 0x96, 0x9b, 0xbd, 0xe4, 0x9f, 0x31, 0x25, 0xb6, 0x64, 0xae, 0x8d, 0x9a,
0xb0, 0xd4, 0x26, 0x5d, 0xd3, 0xd2, 0xdb, 0x7d, 0xbb, 0xf3, 0xb8, 0x96, 0xe7, 0xc6, 0x6a, 0x9c,
0x71, 0x9d, 0xa9, 0xd6, 0x99, 0x66, 0x2b, 0xa1, 0x41, 0xdb, 0x9f, 0xa1, 0x77, 0xa0, 0xd0, 0xe9,
0x91, 0xce, 0x63, 0x9d, 0x9e, 0xd4, 0x0a, 0xdc, 0xc7, 0x7a, 0x9c, 0x8f, 0x06, 0xd3, 0x3b, 0x3c,
0x69, 0x25, 0xb4, 0x7c, 0x47, 0x0c, 0xd9, 0xfa, 0x0d, 0xd2, 0x37, 0x8f, 0xc9, 0x90, 0xd9, 0x17,
0x67, 0xaf, 0xff, 0x7d, 0xa1, 0xc9, 0x3d, 0x14, 0x0d, 0x6f, 0x82, 0xde, 0x85, 0x22, 0xb1, 0x0c,
0xb9, 0x0c, 0xe0, 0x2e, 0x2e, 0xc7, 0xee, 0x15, 0xcb, 0xf0, 0x16, 0x51, 0x20, 0x72, 0x8c, 0x6e,
0x43, 0xae, 0x63, 0x0f, 0x06, 0x26, 0xad, 0x2d, 0x71, 0xeb, 0xb5, 0xd8, 0x05, 0x70, 0xad, 0x56,
0x42, 0x93, 0xfa, 0x68, 0x17, 0xca, 0x7d, 0xd3, 0xa5, 0xba, 0x6b, 0x61, 0xc7, 0xed, 0xd9, 0xd4,
0xad, 0x2d, 0x73, 0x0f, 0x57, 0xe3, 0x3c, 0xdc, 0x37, 0x5d, 0x7a, 0xe0, 0x29, 0xb7, 0x12, 0x5a,
0xa9, 0x1f, 0x16, 0x30, 0x7f, 0xf6, 0xd1, 0x11, 0x19, 0xfa, 0x0e, 0x6b, 0xa5, 0xd9, 0xfe, 0xf6,
0x98, 0xb6, 0x67, 0xcf, 0xfc, 0xd9, 0x61, 0x01, 0xfa, 0x15, 0x9c, 0xeb, 0xdb, 0xd8, 0xf0, 0xdd,
0xe9, 0x9d, 0xde, 0xc8, 0x7a, 0x5c, 0x2b, 0x73, 0xa7, 0xd7, 0x62, 0x7f, 0xa4, 0x8d, 0x0d, 0xcf,
0x45, 0x83, 0x19, 0xb4, 0x12, 0xda, 0x4a, 0x7f, 0x5c, 0x88, 0x1e, 0xc1, 0x2a, 0x76, 0x9c, 0xfe,
0xe9, 0xb8, 0xf7, 0x0a, 0xf7, 0x7e, 0x3d, 0xce, 0xfb, 0x36, 0xb3, 0x19, 0x77, 0x8f, 0xf0, 0x84,
0xb4, 0x9e, 0x87, 0xec, 0x31, 0xee, 0x8f, 0x88, 0xfa, 0x3d, 0x58, 0x0a, 0xa5, 0x3a, 0xaa, 0x41,
0x7e, 0x40, 0x5c, 0x17, 0x77, 0x09, 0x47, 0x86, 0xa2, 0xe6, 0x4d, 0xd5, 0x32, 0x2c, 0x87, 0xd3,
0x5b, 0x1d, 0xf8, 0x86, 0x2c, 0x71, 0x99, 0xe1, 0x31, 0x19, 0xba, 0x2c, 0x5b, 0xa5, 0xa1, 0x9c,
0xa2, 0x2b, 0x50, 0xe2, 0xdb, 0x47, 0xf7, 0x9e, 0x33, 0xf4, 0xc8, 0x68, 0xcb, 0x5c, 0xf8, 0x50,
0x2a, 0xad, 0xc3, 0x92, 0xb3, 0xe5, 0xf8, 0x2a, 0x69, 0xae, 0x02, 0xce, 0x96, 0x23, 0x15, 0xd4,
0x1f, 0x41, 0x75, 0x3c, 0xdb, 0x51, 0x15, 0xd2, 0x8f, 0xc9, 0xa9, 0x7c, 0x1f, 0x1b, 0xa2, 0x55,
0xb9, 0x2c, 0xfe, 0x8e, 0xa2, 0x26, 0xd7, 0xf8, 0xd7, 0x94, 0x6f, 0xec, 0xa7, 0x39, 0xba, 0x0d,
0x19, 0x86, 0x9a, 0x12, 0x00, 0x95, 0x0d, 0x01, 0xa9, 0x1b, 0x1e, 0xa4, 0x6e, 0x1c, 0x7a, 0x90,
0x5a, 0x2f, 0x7c, 0xfd, 0x6c, 0x3d, 0xf1, 0xe5, 0xdf, 0xd7, 0x93, 0x1a, 0xb7, 0x40, 0xaf, 0xb0,
0xac, 0xc4, 0xa6, 0xa5, 0x9b, 0x86, 0x7c, 0x4f, 0x9e, 0xcf, 0x77, 0x0c, 0x74, 0x0f, 0xaa, 0x1d,
0xdb, 0x72, 0x89, 0xe5, 0x8e, 0x5c, 0x5d, 0x40, 0xb6, 0x84, 0xbd, 0xc9, 0xac, 0x69, 0x78, 0x8a,
0xfb, 0x5c, 0x4f, 0xab, 0x74, 0xa2, 0x02, 0x74, 0x17, 0xe0, 0x18, 0xf7, 0x4d, 0x03, 0x53, 0x7b,
0xe8, 0xd6, 0x32, 0x97, 0xd3, 0x53, 0xdd, 0x3c, 0xf4, 0x54, 0x1e, 0x38, 0x06, 0xa6, 0xa4, 0x9e,
0x61, 0xbf, 0x56, 0x0b, 0x59, 0xa2, 0xd7, 0xa0, 0x82, 0x1d, 0x47, 0x77, 0x29, 0xa6, 0x44, 0x6f,
0x9f, 0x52, 0xe2, 0x72, 0x30, 0x5c, 0xd6, 0x4a, 0xd8, 0x71, 0x0e, 0x98, 0xb4, 0xce, 0x84, 0xe8,
0x2a, 0x94, 0x19, 0xf0, 0x99, 0xb8, 0xaf, 0xf7, 0x88, 0xd9, 0xed, 0x51, 0x0e, 0x7a, 0x69, 0xad,
0x24, 0xa5, 0x2d, 0x2e, 0x54, 0x0d, 0x7f, 0x23, 0x70, 0xd0, 0x43, 0x08, 0x32, 0x06, 0xa6, 0x98,
0x07, 0x72, 0x59, 0xe3, 0x63, 0x26, 0x73, 0x30, 0xed, 0xc9, 0xf0, 0xf0, 0x31, 0x3a, 0x0f, 0x39,
0xe9, 0x36, 0xcd, 0xdd, 0xca, 0x19, 0xfb, 0x66, 0xce, 0xd0, 0x3e, 0x26, 0x1c, 0xe5, 0x0b, 0x9a,
0x98, 0xa8, 0xbf, 0x4d, 0xc1, 0xca, 0x04, 0x3c, 0x32, 0xbf, 0x3d, 0xec, 0xf6, 0xbc, 0x77, 0xb1,
0x31, 0xba, 0xc5, 0xfc, 0x62, 0x83, 0x0c, 0xe5, 0xb1, 0x54, 0x0b, 0x87, 0x48, 0x1c, 0xb9, 0x2d,
0xfe, 0x5c, 0x86, 0x46, 0x6a, 0xa3, 0x3d, 0xa8, 0xf6, 0xb1, 0x4b, 0x75, 0x01, 0x37, 0x7a, 0xe8,
0x88, 0x9a, 0x04, 0xd9, 0xfb, 0xd8, 0x03, 0x28, 0xb6, 0xd9, 0xa5, 0xa3, 0x72, 0x3f, 0x22, 0x45,
0x1a, 0xac, 0xb6, 0x4f, 0x3f, 0xc7, 0x16, 0x35, 0x2d, 0xa2, 0x4f, 0x7c, 0xb9, 0x57, 0x26, 0x9c,
0x36, 0x8f, 0x4d, 0x83, 0x58, 0x1d, 0xef, 0x93, 0x9d, 0xf3, 0x8d, 0xfd, 0x4f, 0xea, 0xaa, 0x1a,
0x94, 0xa3, 0x00, 0x8f, 0xca, 0x90, 0xa2, 0x27, 0x32, 0x00, 0x29, 0x7a, 0x82, 0xbe, 0x0f, 0x19,
0xb6, 0x48, 0xbe, 0xf8, 0xf2, 0x94, 0xd3, 0x55, 0xda, 0x1d, 0x9e, 0x3a, 0x44, 0xe3, 0x9a, 0xaa,
0xea, 0x67, 0x83, 0x0f, 0xfa, 0xe3, 0x5e, 0xd5, 0x6b, 0x50, 0x19, 0x43, 0xf5, 0xd0, 0xf7, 0x4b,
0x86, 0xbf, 0x9f, 0x5a, 0x81, 0x52, 0x04, 0xc2, 0xd5, 0xf3, 0xb0, 0x3a, 0x0d, 0x91, 0xd5, 0x9e,
0x2f, 0x8f, 0x20, 0x2b, 0xba, 0x09, 0x05, 0x1f, 0x92, 0x45, 0x36, 0x4e, 0xc6, 0xca, 0x53, 0xd6,
0x7c, 0x55, 0x96, 0x86, 0x6c, 0x5b, 0xf3, 0xfd, 0x90, 0xe2, 0x3f, 0x3c, 0x8f, 0x1d, 0xa7, 0x85,
0xdd, 0x9e, 0xfa, 0x09, 0xd4, 0xe2, 0xe0, 0x76, 0x6c, 0x19, 0x19, 0x7f, 0x1b, 0x9e, 0x87, 0xdc,
0x91, 0x3d, 0x1c, 0x60, 0xca, 0x9d, 0x95, 0x34, 0x39, 0x63, 0xdb, 0x53, 0x40, 0x6f, 0x9a, 0x8b,
0xc5, 0x44, 0xd5, 0xe1, 0x95, 0x58, 0xc8, 0x65, 0x26, 0xa6, 0x65, 0x10, 0x11, 0xcf, 0x92, 0x26,
0x26, 0x81, 0x23, 0xf1, 0x63, 0xc5, 0x84, 0xbd, 0xd6, 0xe5, 0x6b, 0xe5, 0xfe, 0x8b, 0x9a, 0x9c,
0xa9, 0xff, 0x2c, 0x40, 0x41, 0x23, 0xae, 0xc3, 0x30, 0x01, 0xd5, 0xa1, 0x48, 0x4e, 0x3a, 0x44,
0x90, 0xa1, 0x64, 0x2c, 0x99, 0x10, 0xda, 0x4d, 0x4f, 0x93, 0x9d, 0xe4, 0xbe, 0x19, 0xba, 0x21,
0x09, 0x5f, 0x3c, 0x77, 0x93, 0xe6, 0x61, 0xc6, 0x77, 0xcb, 0x63, 0x7c, 0xe9, 0xd8, 0xc3, 0x5b,
0x58, 0x8d, 0x51, 0xbe, 0x1b, 0x92, 0xf2, 0x65, 0xe6, 0xbc, 0x2c, 0xc2, 0xf9, 0x1a, 0x11, 0xce,
0x97, 0x9d, 0xb3, 0xcc, 0x18, 0xd2, 0xd7, 0x88, 0x90, 0xbe, 0xdc, 0x1c, 0x27, 0x31, 0xac, 0xef,
0x96, 0xc7, 0xfa, 0xf2, 0x73, 0x96, 0x3d, 0x46, 0xfb, 0xee, 0x46, 0x69, 0x9f, 0xa0, 0x6c, 0x57,
0x62, 0xad, 0x63, 0x79, 0xdf, 0x8f, 0x43, 0xbc, 0xaf, 0x18, 0x4b, 0xba, 0x84, 0x93, 0x29, 0xc4,
0xaf, 0x11, 0x21, 0x7e, 0x30, 0x27, 0x06, 0x31, 0xcc, 0xef, 0xbd, 0x30, 0xf3, 0x5b, 0x8a, 0x25,
0x8f, 0x72, 0xd3, 0x4c, 0xa3, 0x7e, 0x77, 0x7c, 0xea, 0xb7, 0x1c, 0xcb, 0x5d, 0xe5, 0x1a, 0xc6,
0xb9, 0xdf, 0xde, 0x04, 0xf7, 0x13, 0x5c, 0xed, 0xb5, 0x58, 0x17, 0x73, 0xc8, 0xdf, 0xde, 0x04,
0xf9, 0x2b, 0xcf, 0x71, 0x38, 0x87, 0xfd, 0xfd, 0x7a, 0x3a, 0xfb, 0x8b, 0xe7, 0x67, 0xf2, 0x67,
0x2e, 0x46, 0xff, 0xf4, 0x18, 0xfa, 0x57, 0xe5, 0xee, 0xdf, 0x88, 0x75, 0x7f, 0x76, 0xfe, 0x77,
0x8d, 0x1d, 0xb3, 0x63, 0xc0, 0xc1, 0xa0, 0x8a, 0x0c, 0x87, 0xf6, 0x50, 0x52, 0x2b, 0x31, 0x51,
0x5f, 0x67, 0x07, 0x7f, 0x00, 0x12, 0x33, 0xb8, 0x22, 0x3f, 0x12, 0x42, 0xc0, 0xa0, 0xfe, 0x29,
0x19, 0xd8, 0xf2, 0xb3, 0x32, 0x4c, 0x1a, 0x8a, 0x92, 0x34, 0x84, 0x28, 0x64, 0x2a, 0x4a, 0x21,
0xd7, 0x61, 0x89, 0x41, 0xfd, 0x18, 0x3b, 0xc4, 0x8e, 0xc7, 0x0e, 0xd1, 0x75, 0x58, 0xe1, 0x67,
0xb9, 0x20, 0x9a, 0x12, 0xdf, 0x33, 0xfc, 0x98, 0xaa, 0xb0, 0x07, 0x62, 0x73, 0x0a, 0xa0, 0x7f,
0x0b, 0xce, 0x85, 0x74, 0xfd, 0x23, 0x44, 0x50, 0xa2, 0xaa, 0xaf, 0xbd, 0x2d, 0xcf, 0x92, 0x0f,
0x83, 0x00, 0x05, 0xcc, 0x13, 0x41, 0xa6, 0x63, 0x1b, 0x44, 0x02, 0x3c, 0x1f, 0x33, 0x36, 0xda,
0xb7, 0xbb, 0x12, 0xc6, 0xd9, 0x90, 0x69, 0xf9, 0x28, 0x58, 0x14, 0x20, 0xa7, 0xfe, 0x25, 0x19,
0xf8, 0x0b, 0xc8, 0xe8, 0x34, 0xde, 0x98, 0xfc, 0xdf, 0xf0, 0xc6, 0xd4, 0xb7, 0xe6, 0x8d, 0xe1,
0x03, 0x36, 0x1d, 0x3d, 0x60, 0xff, 0x9d, 0x0c, 0xbe, 0xb0, 0xcf, 0x02, 0xbf, 0x5d, 0x44, 0x82,
0xd3, 0x32, 0xcb, 0xbf, 0x97, 0x3c, 0x2d, 0x25, 0xb7, 0xcf, 0xf1, 0xf7, 0x46, 0xb9, 0x7d, 0x5e,
0x9c, 0x9f, 0x7c, 0x82, 0x6e, 0x43, 0x91, 0x37, 0x5d, 0x74, 0xdb, 0x71, 0x25, 0xe0, 0x5e, 0x08,
0xaf, 0x55, 0xf4, 0x56, 0x36, 0xf6, 0x99, 0xce, 0x9e, 0xe3, 0x6a, 0x05, 0x47, 0x8e, 0x42, 0x44,
0xa0, 0x18, 0xe1, 0xa3, 0x17, 0xa1, 0xc8, 0x7e, 0xbd, 0xeb, 0xe0, 0x0e, 0xe1, 0xe0, 0x59, 0xd4,
0x02, 0x81, 0xfa, 0x08, 0xd0, 0x24, 0x7c, 0xa3, 0x16, 0xe4, 0xc8, 0x31, 0xb1, 0x28, 0xfb, 0x6a,
0x2c, 0xdc, 0xe7, 0xa7, 0x90, 0x3d, 0x62, 0xd1, 0x7a, 0x8d, 0x05, 0xf9, 0x5f, 0xcf, 0xd6, 0xab,
0x42, 0xfb, 0x4d, 0x7b, 0x60, 0x52, 0x32, 0x70, 0xe8, 0xa9, 0x26, 0xed, 0xd5, 0x2f, 0x52, 0x8c,
0x79, 0x45, 0xa0, 0x7d, 0x6a, 0x6c, 0xbd, 0x04, 0x4a, 0x85, 0x58, 0xf7, 0x62, 0xf1, 0x5e, 0x03,
0xe8, 0x62, 0x57, 0x7f, 0x82, 0x2d, 0x4a, 0x0c, 0x19, 0xf4, 0x90, 0x04, 0x29, 0x50, 0x60, 0xb3,
0x91, 0x4b, 0x0c, 0x59, 0x00, 0xf8, 0xf3, 0xd0, 0x3a, 0xf3, 0xdf, 0x6d, 0x9d, 0xd1, 0x28, 0x17,
0xc6, 0xa3, 0xfc, 0xbb, 0x54, 0x90, 0x25, 0x01, 0x49, 0xfd, 0xff, 0x8b, 0xc3, 0xef, 0x79, 0xe5,
0x1a, 0x3d, 0x63, 0xd1, 0x01, 0xac, 0xf8, 0x59, 0xaa, 0x8f, 0x78, 0xf6, 0x7a, 0xfb, 0x6e, 0xd1,
0x34, 0xaf, 0x1e, 0x47, 0xc5, 0x2e, 0xfa, 0x39, 0xbc, 0x3c, 0x86, 0x40, 0xbe, 0xeb, 0xd4, 0x82,
0x40, 0xf4, 0x52, 0x14, 0x88, 0x3c, 0xcf, 0x41, 0xac, 0xd2, 0xdf, 0x31, 0x37, 0x76, 0x58, 0x31,
0x14, 0x66, 0x0c, 0x53, 0xbf, 0xfe, 0x15, 0x28, 0x0d, 0x09, 0x65, 0xf5, 0x79, 0xa4, 0xdc, 0x5c,
0x16, 0x42, 0x59, 0xc4, 0xee, 0xc3, 0x4b, 0x53, 0x99, 0x03, 0xfa, 0x21, 0x14, 0x03, 0xd2, 0x91,
0x8c, 0xa9, 0xdc, 0xfc, 0x6a, 0x24, 0xd0, 0x55, 0xff, 0x9c, 0x0c, 0x5c, 0x46, 0xeb, 0x9b, 0x26,
0xe4, 0x86, 0xc4, 0x1d, 0xf5, 0x45, 0xc5, 0x51, 0xde, 0x7a, 0x6b, 0x31, 0xce, 0xc1, 0xa4, 0xa3,
0x3e, 0xd5, 0xa4, 0xb1, 0xfa, 0x08, 0x72, 0x42, 0x82, 0x96, 0x20, 0xff, 0x60, 0xf7, 0xde, 0xee,
0xde, 0x47, 0xbb, 0xd5, 0x04, 0x02, 0xc8, 0x6d, 0x37, 0x1a, 0xcd, 0xfd, 0xc3, 0x6a, 0x12, 0x15,
0x21, 0xbb, 0x5d, 0xdf, 0xd3, 0x0e, 0xab, 0x29, 0x26, 0xd6, 0x9a, 0x1f, 0x34, 0x1b, 0x87, 0xd5,
0x34, 0x5a, 0x81, 0x92, 0x18, 0xeb, 0x77, 0xf7, 0xb4, 0x0f, 0xb7, 0x0f, 0xab, 0x99, 0x90, 0xe8,
0xa0, 0xb9, 0xfb, 0x7e, 0x53, 0xab, 0x66, 0xd5, 0x1f, 0xb0, 0x92, 0x26, 0x86, 0xa5, 0x04, 0xc5,
0x4b, 0x32, 0x54, 0xbc, 0xa8, 0x7f, 0x4c, 0x81, 0x12, 0x4f, 0x3d, 0xd0, 0x07, 0x63, 0x0b, 0xdf,
0x3a, 0x03, 0x6f, 0x19, 0x5b, 0x3d, 0xba, 0x0a, 0xe5, 0x21, 0x39, 0x22, 0xb4, 0xd3, 0x13, 0x54,
0x48, 0x1c, 0x6c, 0x25, 0xad, 0x24, 0xa5, 0xdc, 0xc8, 0x15, 0x6a, 0x9f, 0x92, 0x0e, 0xd5, 0x45,
0x1d, 0x25, 0x36, 0x5d, 0x91, 0xa9, 0x31, 0xe9, 0x81, 0x10, 0xaa, 0x9f, 0x9c, 0x29, 0x96, 0x45,
0xc8, 0x6a, 0xcd, 0x43, 0xed, 0x17, 0xd5, 0x34, 0x42, 0x50, 0xe6, 0x43, 0xfd, 0x60, 0x77, 0x7b,
0xff, 0xa0, 0xb5, 0xc7, 0x62, 0x79, 0x0e, 0x2a, 0x5e, 0x2c, 0x3d, 0x61, 0x56, 0xfd, 0x4f, 0x12,
0x2a, 0x63, 0x09, 0x82, 0xb6, 0x20, 0x2b, 0xe8, 0x74, 0x5c, 0xd3, 0x9d, 0xe7, 0xb7, 0xcc, 0x26,
0xa1, 0x8a, 0xde, 0x81, 0x02, 0x91, 0x7d, 0x82, 0x69, 0x89, 0x28, 0xfa, 0x1b, 0x5e, 0x27, 0x41,
0x9a, 0xfa, 0x16, 0xe8, 0x5d, 0x28, 0xfa, 0x99, 0x2e, 0x6b, 0xb8, 0x57, 0x27, 0xcd, 0x7d, 0x8c,
0x90, 0xf6, 0x81, 0x0d, 0xba, 0x13, 0x70, 0xb2, 0xcc, 0x24, 0x89, 0x97, 0xe6, 0x42, 0x41, 0x1a,
0x7b, 0xfa, 0x6a, 0x03, 0x96, 0x42, 0xeb, 0x41, 0x17, 0xa0, 0x38, 0xc0, 0x27, 0xb2, 0xff, 0x24,
0x3a, 0x08, 0x85, 0x01, 0x3e, 0x11, 0xad, 0xa7, 0x97, 0x21, 0xcf, 0x1e, 0x76, 0xb1, 0x40, 0x9b,
0xb4, 0x96, 0x1b, 0xe0, 0x93, 0x9f, 0x62, 0x57, 0xfd, 0x18, 0xca, 0xd1, 0xde, 0x0b, 0xdb, 0x89,
0x43, 0x7b, 0x64, 0x19, 0xdc, 0x47, 0x56, 0x13, 0x13, 0x74, 0x13, 0xb2, 0xc7, 0xb6, 0x00, 0xab,
0xe9, 0x29, 0xfb, 0xd0, 0xa6, 0x24, 0xd4, 0xbb, 0x11, 0xda, 0xea, 0xe7, 0x90, 0xe5, 0xe0, 0xc3,
0x80, 0x84, 0x77, 0x51, 0x24, 0x1f, 0x65, 0x63, 0xf4, 0x31, 0x00, 0xa6, 0x74, 0x68, 0xb6, 0x47,
0x81, 0xe3, 0xf5, 0xe9, 0xe0, 0xb5, 0xed, 0xe9, 0xd5, 0x2f, 0x4a, 0x14, 0x5b, 0x0d, 0x4c, 0x43,
0x48, 0x16, 0x72, 0xa8, 0xee, 0x42, 0x39, 0x6a, 0x1b, 0xee, 0x67, 0x2e, 0x4f, 0xe9, 0x67, 0xfa,
0x9c, 0xc7, 0x67, 0x4c, 0x69, 0xd1, 0x31, 0xe3, 0x13, 0xf5, 0x69, 0x12, 0x0a, 0x87, 0x27, 0x72,
0x5b, 0xc7, 0x34, 0x6b, 0x02, 0xd3, 0x54, 0xb8, 0x35, 0x21, 0xba, 0x3f, 0x69, 0xbf, 0xa7, 0xf4,
0x9e, 0x9f, 0xb8, 0x99, 0x45, 0x8b, 0x47, 0xaf, 0xb9, 0x26, 0xc1, 0xea, 0x6d, 0x28, 0xfa, 0xbb,
0x8a, 0x11, 0x7b, 0x6c, 0x18, 0x43, 0xe2, 0xba, 0x72, 0x6d, 0xde, 0x94, 0xf7, 0xfe, 0xec, 0x27,
0xb2, 0xf9, 0x91, 0xd6, 0xc4, 0x44, 0x35, 0xa0, 0x32, 0x76, 0x6c, 0xa1, 0xb7, 0x21, 0xef, 0x8c,
0xda, 0xba, 0x17, 0x9e, 0xb1, 0xe4, 0xf1, 0x48, 0xde, 0xa8, 0xdd, 0x37, 0x3b, 0xf7, 0xc8, 0xa9,
0xf7, 0x63, 0x9c, 0x51, 0xfb, 0x9e, 0x88, 0xa2, 0x78, 0x4b, 0x2a, 0xfc, 0x96, 0x63, 0x28, 0x78,
0x9b, 0x02, 0xfd, 0x24, 0x9c, 0x27, 0x5e, 0x47, 0x38, 0xf6, 0x28, 0x95, 0xee, 0x43, 0x69, 0x72,
0x1d, 0x56, 0x5c, 0xb3, 0x6b, 0x11, 0x43, 0x0f, 0x4a, 0x0b, 0xfe, 0xb6, 0x82, 0x56, 0x11, 0x0f,
0xee, 0x7b, 0x75, 0x85, 0xfa, 0x2c, 0x09, 0x05, 0x2f, 0x61, 0xa7, 0xee, 0xbb, 0xc8, 0x8f, 0x49,
0x9d, 0xfd, 0xc7, 0xc4, 0x35, 0x5a, 0xbd, 0x8e, 0x77, 0xe6, 0xcc, 0x1d, 0xef, 0x37, 0x01, 0x51,
0x9b, 0xe2, 0xbe, 0x7e, 0x6c, 0x53, 0xd3, 0xea, 0xea, 0x22, 0x9a, 0x82, 0x32, 0x55, 0xf9, 0x93,
0x87, 0xfc, 0xc1, 0x3e, 0x0f, 0xec, 0x6f, 0x92, 0x50, 0xf0, 0x0f, 0xbf, 0xb3, 0xb6, 0xdb, 0xce,
0x43, 0x4e, 0xe2, 0xbb, 0xe8, 0xb7, 0xc9, 0x99, 0xdf, 0xf9, 0xcd, 0x84, 0x3a, 0xbf, 0x0a, 0x14,
0x06, 0x84, 0x62, 0xce, 0x00, 0x44, 0xf9, 0xe6, 0xcf, 0xaf, 0xdf, 0x81, 0xa5, 0x50, 0xe7, 0x93,
0xa5, 0xd6, 0x6e, 0xf3, 0xa3, 0x6a, 0x42, 0xc9, 0x3f, 0xfd, 0xea, 0x72, 0x7a, 0x97, 0x3c, 0x61,
0x9b, 0x52, 0x6b, 0x36, 0x5a, 0xcd, 0xc6, 0xbd, 0x6a, 0x52, 0x59, 0x7a, 0xfa, 0xd5, 0xe5, 0xbc,
0x46, 0x78, 0x03, 0x65, 0xeb, 0x0b, 0x80, 0xca, 0x76, 0xbd, 0xb1, 0xc3, 0x0e, 0x25, 0xb3, 0x83,
0x65, 0x5b, 0x29, 0xc3, 0x6b, 0xde, 0x99, 0x17, 0xa5, 0xca, 0xec, 0xae, 0x1a, 0xba, 0x0b, 0x59,
0x5e, 0x0e, 0xa3, 0xd9, 0x37, 0xa7, 0xca, 0x9c, 0x36, 0x1b, 0xfb, 0x31, 0x7c, 0xd7, 0xce, 0xbc,
0x4a, 0x55, 0x66, 0x77, 0xdd, 0x90, 0x06, 0xc5, 0xa0, 0x9e, 0x9d, 0x7f, 0xb5, 0xaa, 0x2c, 0xd0,
0x89, 0x63, 0x3e, 0x03, 0xb6, 0x3e, 0xff, 0xaa, 0x51, 0x59, 0x00, 0x57, 0xd0, 0x7d, 0xc8, 0x7b,
0x75, 0xd0, 0xbc, 0xcb, 0x4f, 0x65, 0x6e, 0x97, 0x8c, 0x7d, 0x02, 0x51, 0xaf, 0xce, 0xbe, 0xc9,
0x55, 0xe6, 0xb4, 0xfc, 0xd0, 0x0e, 0xe4, 0x24, 0x05, 0x9d, 0x73, 0xa1, 0xa9, 0xcc, 0xeb, 0x7a,
0xb1, 0xa0, 0x05, 0x8d, 0x80, 0xf9, 0xf7, 0xd3, 0xca, 0x02, 0xdd, 0x4c, 0xf4, 0x00, 0x20, 0x54,
0x9d, 0x2e, 0x70, 0xf1, 0xac, 0x2c, 0xd2, 0xa5, 0x44, 0x7b, 0x50, 0xf0, 0xab, 0x90, 0xb9, 0xd7,
0xc0, 0xca, 0xfc, 0x76, 0x21, 0x7a, 0x04, 0xa5, 0x28, 0xfd, 0x5e, 0xec, 0x72, 0x57, 0x59, 0xb0,
0x0f, 0xc8, 0xfc, 0x47, 0xb9, 0xf8, 0x62, 0x97, 0xbd, 0xca, 0x82, 0x6d, 0x41, 0xf4, 0x29, 0xac,
0x4c, 0x72, 0xe5, 0xc5, 0xef, 0x7e, 0x95, 0x33, 0x34, 0x0a, 0xd1, 0x00, 0xd0, 0x14, 0x8e, 0x7d,
0x86, 0xab, 0x60, 0xe5, 0x2c, 0x7d, 0xc3, 0x7a, 0xf3, 0xeb, 0xe7, 0x6b, 0xc9, 0x6f, 0x9e, 0xaf,
0x25, 0xff, 0xf1, 0x7c, 0x2d, 0xf9, 0xe5, 0x8b, 0xb5, 0xc4, 0x37, 0x2f, 0xd6, 0x12, 0x7f, 0x7b,
0xb1, 0x96, 0xf8, 0xe5, 0x1b, 0x5d, 0x93, 0xf6, 0x46, 0xed, 0x8d, 0x8e, 0x3d, 0xd8, 0x0c, 0xff,
0x4f, 0x65, 0xda, 0x7f, 0x67, 0xda, 0x39, 0x7e, 0xbc, 0xdc, 0xf8, 0x6f, 0x00, 0x00, 0x00, 0xff,
0xff, 0x21, 0x92, 0x34, 0xc9, 0x5b, 0x23, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -4413,6 +4422,11 @@ func (m *RequestInitChain) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i _ = i
var l int var l int
_ = l _ = l
if m.InitialHeight != 0 {
i = encodeVarintTypes(dAtA, i, uint64(m.InitialHeight))
i--
dAtA[i] = 0x30
}
if len(m.AppStateBytes) > 0 { if len(m.AppStateBytes) > 0 {
i -= len(m.AppStateBytes) i -= len(m.AppStateBytes)
copy(dAtA[i:], m.AppStateBytes) copy(dAtA[i:], m.AppStateBytes)
@ -6776,6 +6790,9 @@ func (m *RequestInitChain) Size() (n int) {
if l > 0 { if l > 0 {
n += 1 + l + sovTypes(uint64(l)) n += 1 + l + sovTypes(uint64(l))
} }
if m.InitialHeight != 0 {
n += 1 + sovTypes(uint64(m.InitialHeight))
}
return n return n
} }
@ -8862,6 +8879,25 @@ func (m *RequestInitChain) Unmarshal(dAtA []byte) error {
m.AppStateBytes = []byte{} m.AppStateBytes = []byte{}
} }
iNdEx = postIndex iNdEx = postIndex
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field InitialHeight", wireType)
}
m.InitialHeight = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.InitialHeight |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
}
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:]) skippy, err := skipTypes(dAtA[iNdEx:])


+ 4
- 0
cmd/tendermint/commands/testnet.go View File

@ -22,6 +22,7 @@ import (
var ( var (
nValidators int nValidators int
nNonValidators int nNonValidators int
initialHeight int64
configFile string configFile string
outputDir string outputDir string
nodeDirPrefix string nodeDirPrefix string
@ -50,6 +51,8 @@ func init() {
"Directory to store initialization data for the testnet") "Directory to store initialization data for the testnet")
TestnetFilesCmd.Flags().StringVar(&nodeDirPrefix, "node-dir-prefix", "node", TestnetFilesCmd.Flags().StringVar(&nodeDirPrefix, "node-dir-prefix", "node",
"Prefix the directory name for each node with (node results in node0, node1, ...)") "Prefix the directory name for each node with (node results in node0, node1, ...)")
TestnetFilesCmd.Flags().Int64Var(&initialHeight, "initial-height", 0,
"Initial height of the first block")
TestnetFilesCmd.Flags().BoolVar(&populatePersistentPeers, "populate-persistent-peers", true, TestnetFilesCmd.Flags().BoolVar(&populatePersistentPeers, "populate-persistent-peers", true,
"Update config of each node with the list of persistent peers build using either"+ "Update config of each node with the list of persistent peers build using either"+
@ -175,6 +178,7 @@ func testnetFiles(cmd *cobra.Command, args []string) error {
ChainID: "chain-" + tmrand.Str(6), ChainID: "chain-" + tmrand.Str(6),
ConsensusParams: types.DefaultConsensusParams(), ConsensusParams: types.DefaultConsensusParams(),
GenesisTime: tmtime.Now(), GenesisTime: tmtime.Now(),
InitialHeight: initialHeight,
Validators: genVals, Validators: genVals,
} }


+ 1
- 0
config/toml.go View File

@ -476,6 +476,7 @@ func ResetTestRootWithChainID(testName string, chainID string) *Config {
var testGenesisFmt = `{ var testGenesisFmt = `{
"genesis_time": "2018-10-10T08:20:13.695936996Z", "genesis_time": "2018-10-10T08:20:13.695936996Z",
"chain_id": "%s", "chain_id": "%s",
"initial_height": "1",
"validators": [ "validators": [
{ {
"pub_key": { "pub_key": {


+ 8
- 5
consensus/common_test.go View File

@ -430,7 +430,7 @@ func randState(nValidators int) (*State, []*validatorStub) {
return cs, vss return cs, vss
} }
func randStateWithEvpool(nValidators int) (*State, []*validatorStub, *evidence.Pool) {
func randStateWithEvpool(t *testing.T, nValidators int) (*State, []*validatorStub, *evidence.Pool) {
state, privVals := randGenesisState(nValidators, false, 10) state, privVals := randGenesisState(nValidators, false, 10)
vss := make([]*validatorStub, nValidators) vss := make([]*validatorStub, nValidators)
@ -451,7 +451,9 @@ func randStateWithEvpool(nValidators int) (*State, []*validatorStub, *evidence.P
mempool.EnableTxsAvailable() mempool.EnableTxsAvailable()
} }
stateDB := dbm.NewMemDB() stateDB := dbm.NewMemDB()
evpool, _ := evidence.NewPool(stateDB, evidenceDB, blockStore)
sm.SaveState(stateDB, state)
evpool, err := evidence.NewPool(stateDB, evidenceDB, blockStore)
require.NoError(t, err)
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyAppConnCon, mempool, evpool) blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
cs := NewState(config.Consensus, state, blockExec, blockStore, mempool, evpool) cs := NewState(config.Consensus, state, blockExec, blockStore, mempool, evpool)
cs.SetLogger(log.TestingLogger().With("module", "consensus")) cs.SetLogger(log.TestingLogger().With("module", "consensus"))
@ -821,9 +823,10 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
sort.Sort(types.PrivValidatorsByAddress(privValidators)) sort.Sort(types.PrivValidatorsByAddress(privValidators))
return &types.GenesisDoc{ return &types.GenesisDoc{
GenesisTime: tmtime.Now(),
ChainID: config.ChainID(),
Validators: validators,
GenesisTime: tmtime.Now(),
InitialHeight: 1,
ChainID: config.ChainID(),
Validators: validators,
}, privValidators }, privValidators
} }


+ 31
- 3
consensus/reactor.go View File

@ -249,6 +249,14 @@ func (conR *Reactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
case StateChannel: case StateChannel:
switch msg := msg.(type) { switch msg := msg.(type) {
case *NewRoundStepMessage: case *NewRoundStepMessage:
conR.conS.mtx.Lock()
initialHeight := conR.conS.state.InitialHeight
conR.conS.mtx.Unlock()
if err = msg.ValidateHeight(initialHeight); err != nil {
conR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
conR.Switch.StopPeerForError(src, err)
return
}
ps.ApplyNewRoundStepMessage(msg) ps.ApplyNewRoundStepMessage(msg)
case *NewValidBlockMessage: case *NewValidBlockMessage:
ps.ApplyNewValidBlockMessage(msg) ps.ApplyNewValidBlockMessage(msg)
@ -1435,9 +1443,29 @@ func (m *NewRoundStepMessage) ValidateBasic() error {
// NOTE: SecondsSinceStartTime may be negative // NOTE: SecondsSinceStartTime may be negative
if (m.Height == 1 && m.LastCommitRound != -1) ||
(m.Height > 1 && m.LastCommitRound < 0) {
return errors.New("invalid LastCommitRound (for 1st block: -1, for others: >= 0)")
// LastCommitRound will be -1 for the initial height, but we don't know what height this is
// since it can be specified in genesis. The reactor will have to validate this via
// ValidateHeight().
if m.LastCommitRound < -1 {
return errors.New("invalid LastCommitRound (cannot be < -1)")
}
return nil
}
// ValidateHeight validates the height given the chain's initial height.
func (m *NewRoundStepMessage) ValidateHeight(initialHeight int64) error {
if m.Height < initialHeight {
return fmt.Errorf("invalid Height %v (lower than initial height %v)",
m.Height, initialHeight)
}
if m.Height == initialHeight && m.LastCommitRound != -1 {
return fmt.Errorf("invalid LastCommitRound %v (must be -1 for initial height %v)",
m.LastCommitRound, initialHeight)
}
if m.Height > initialHeight && m.LastCommitRound < 0 {
return fmt.Errorf("LastCommitRound can only be negative for initial height %v", // nolint
initialHeight)
} }
return nil return nil
} }


+ 44
- 3
consensus/reactor_test.go View File

@ -710,8 +710,9 @@ func TestNewRoundStepMessageValidateBasic(t *testing.T) {
{true, -1, 0, 0, "Negative round", cstypes.RoundStepNewHeight}, {true, -1, 0, 0, "Negative round", cstypes.RoundStepNewHeight},
{true, 0, 0, -1, "Negative height", cstypes.RoundStepNewHeight}, {true, 0, 0, -1, "Negative height", cstypes.RoundStepNewHeight},
{true, 0, 0, 0, "Invalid Step", cstypes.RoundStepCommit + 1}, {true, 0, 0, 0, "Invalid Step", cstypes.RoundStepCommit + 1},
{true, 0, 0, 1, "H == 1 but LCR != -1 ", cstypes.RoundStepNewHeight},
{true, 0, -1, 2, "H > 1 but LCR < 0", cstypes.RoundStepNewHeight},
// The following cases will be handled by ValidateHeight
{false, 0, 0, 1, "H == 1 but LCR != -1 ", cstypes.RoundStepNewHeight},
{false, 0, -1, 2, "H > 1 but LCR < 0", cstypes.RoundStepNewHeight},
} }
for _, tc := range testCases { for _, tc := range testCases {
@ -724,7 +725,47 @@ func TestNewRoundStepMessageValidateBasic(t *testing.T) {
LastCommitRound: tc.messageLastCommitRound, LastCommitRound: tc.messageLastCommitRound,
} }
assert.Equal(t, tc.expectErr, message.ValidateBasic() != nil, "Validate Basic had an unexpected result")
err := message.ValidateBasic()
if tc.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
func TestNewRoundStepMessageValidateHeight(t *testing.T) {
initialHeight := int64(10)
testCases := []struct { // nolint: maligned
expectErr bool
messageLastCommitRound int32
messageHeight int64
testName string
}{
{false, 0, 11, "Valid Message"},
{true, 0, -1, "Negative height"},
{true, 0, 0, "Zero height"},
{true, 0, 10, "Initial height but LCR != -1 "},
{true, -1, 11, "Normal height but LCR < 0"},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.testName, func(t *testing.T) {
message := NewRoundStepMessage{
Height: tc.messageHeight,
Round: 0,
Step: cstypes.RoundStepNewHeight,
LastCommitRound: tc.messageLastCommitRound,
}
err := message.ValidateHeight(initialHeight)
if tc.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
}) })
} }
} }


+ 23
- 7
consensus/replay.go View File

@ -120,14 +120,21 @@ func (cs *State) catchupReplay(csHeight int64) error {
// Search for last height marker. // Search for last height marker.
// //
// Ignore data corruption errors in previous heights because we only care about last height // Ignore data corruption errors in previous heights because we only care about last height
gr, found, err = cs.wal.SearchForEndHeight(csHeight-1, &WALSearchOptions{IgnoreDataCorruptionErrors: true})
if csHeight < cs.state.InitialHeight {
return fmt.Errorf("cannot replay height %v, below initial height %v", csHeight, cs.state.InitialHeight)
}
endHeight := csHeight - 1
if csHeight == cs.state.InitialHeight {
endHeight = 0
}
gr, found, err = cs.wal.SearchForEndHeight(endHeight, &WALSearchOptions{IgnoreDataCorruptionErrors: true})
if err == io.EOF { if err == io.EOF {
cs.Logger.Error("Replay: wal.group.Search returned EOF", "#ENDHEIGHT", csHeight-1)
cs.Logger.Error("Replay: wal.group.Search returned EOF", "#ENDHEIGHT", endHeight)
} else if err != nil { } else if err != nil {
return err return err
} }
if !found { if !found {
return fmt.Errorf("cannot replay height %d. WAL does not contain #ENDHEIGHT for %d", csHeight, csHeight-1)
return fmt.Errorf("cannot replay height %d. WAL does not contain #ENDHEIGHT for %d", csHeight, endHeight)
} }
defer gr.Close() defer gr.Close()
@ -254,7 +261,7 @@ func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
"protocol-version", res.AppVersion, "protocol-version", res.AppVersion,
) )
// Only set the version if we're starting from zero.
// Only set the version if there is no existing state.
if h.initialState.LastBlockHeight == 0 { if h.initialState.LastBlockHeight == 0 {
h.initialState.Version.Consensus.App = res.AppVersion h.initialState.Version.Consensus.App = res.AppVersion
} }
@ -306,6 +313,7 @@ func (h *Handshaker) ReplayBlocks(
req := abci.RequestInitChain{ req := abci.RequestInitChain{
Time: h.genDoc.GenesisTime, Time: h.genDoc.GenesisTime,
ChainId: h.genDoc.ChainID, ChainId: h.genDoc.ChainID,
InitialHeight: h.genDoc.InitialHeight,
ConsensusParams: csParams, ConsensusParams: csParams,
Validators: nextVals, Validators: nextVals,
AppStateBytes: h.genDoc.AppState, AppStateBytes: h.genDoc.AppState,
@ -353,7 +361,11 @@ func (h *Handshaker) ReplayBlocks(
assertAppHashEqualsOneFromState(appHash, state) assertAppHashEqualsOneFromState(appHash, state)
return appHash, nil return appHash, nil
case appBlockHeight < storeBlockBase-1:
case appBlockHeight == 0 && state.InitialHeight < storeBlockBase:
// the app has no state, and the block store is truncated above the initial height
return appHash, sm.ErrAppBlockHeightTooLow{AppHeight: appBlockHeight, StoreBase: storeBlockBase}
case appBlockHeight > 0 && appBlockHeight < storeBlockBase-1:
// the app is too far behind truncated store (can be 1 behind since we replay the next) // the app is too far behind truncated store (can be 1 behind since we replay the next)
return appHash, sm.ErrAppBlockHeightTooLow{AppHeight: appBlockHeight, StoreBase: storeBlockBase} return appHash, sm.ErrAppBlockHeightTooLow{AppHeight: appBlockHeight, StoreBase: storeBlockBase}
@ -444,7 +456,11 @@ func (h *Handshaker) replayBlocks(
if mutateState { if mutateState {
finalBlock-- finalBlock--
} }
for i := appBlockHeight + 1; i <= finalBlock; i++ {
firstBlock := appBlockHeight + 1
if firstBlock == 1 {
firstBlock = state.InitialHeight
}
for i := firstBlock; i <= finalBlock; i++ {
h.logger.Info("Applying block", "height", i) h.logger.Info("Applying block", "height", i)
block := h.store.LoadBlock(i) block := h.store.LoadBlock(i)
// Extra check to ensure the app was not changed in a way it shouldn't have. // Extra check to ensure the app was not changed in a way it shouldn't have.
@ -452,7 +468,7 @@ func (h *Handshaker) replayBlocks(
assertAppHashEqualsOneFromBlock(appHash, block) assertAppHashEqualsOneFromBlock(appHash, block)
} }
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, h.stateDB)
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, h.stateDB, h.genDoc.InitialHeight)
if err != nil { if err != nil {
return nil, err return nil, err
} }


+ 2
- 1
consensus/replay_test.go View File

@ -153,7 +153,8 @@ LOOP:
logger := log.NewNopLogger() logger := log.NewNopLogger()
blockDB := dbm.NewMemDB() blockDB := dbm.NewMemDB()
stateDB := blockDB stateDB := blockDB
state, _ := sm.MakeGenesisStateFromFile(consensusReplayConfig.GenesisFile())
state, err := sm.MakeGenesisStateFromFile(consensusReplayConfig.GenesisFile())
require.NoError(t, err)
privValidator := loadPrivValidator(consensusReplayConfig) privValidator := loadPrivValidator(consensusReplayConfig)
cs := newStateWithConfigAndBlockStore( cs := newStateWithConfigAndBlockStore(
consensusReplayConfig, consensusReplayConfig,


+ 35
- 26
consensus/state.go View File

@ -555,27 +555,33 @@ func (cs *State) updateToState(state sm.State) {
panic(fmt.Sprintf("updateToState() expected state height of %v but found %v", panic(fmt.Sprintf("updateToState() expected state height of %v but found %v",
cs.Height, state.LastBlockHeight)) cs.Height, state.LastBlockHeight))
} }
if !cs.state.IsEmpty() && cs.state.LastBlockHeight+1 != cs.Height {
// This might happen when someone else is mutating cs.state.
// Someone forgot to pass in state.Copy() somewhere?!
panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v",
cs.state.LastBlockHeight+1, cs.Height))
}
// If state isn't further out than cs.state, just ignore.
// This happens when SwitchToConsensus() is called in the reactor.
// We don't want to reset e.g. the Votes, but we still want to
// signal the new round step, because other services (eg. txNotifier)
// depend on having an up-to-date peer state!
if !cs.state.IsEmpty() && (state.LastBlockHeight <= cs.state.LastBlockHeight) {
cs.Logger.Info(
"Ignoring updateToState()",
"newHeight",
state.LastBlockHeight+1,
"oldHeight",
cs.state.LastBlockHeight+1)
cs.newStep()
return
if !cs.state.IsEmpty() {
if cs.state.LastBlockHeight > 0 && cs.state.LastBlockHeight+1 != cs.Height {
// This might happen when someone else is mutating cs.state.
// Someone forgot to pass in state.Copy() somewhere?!
panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v",
cs.state.LastBlockHeight+1, cs.Height))
}
if cs.state.LastBlockHeight > 0 && cs.Height == cs.state.InitialHeight {
panic(fmt.Sprintf("Inconsistent cs.state.LastBlockHeight %v, expected 0 for initial height %v",
cs.state.LastBlockHeight, cs.state.InitialHeight))
}
// If state isn't further out than cs.state, just ignore.
// This happens when SwitchToConsensus() is called in the reactor.
// We don't want to reset e.g. the Votes, but we still want to
// signal the new round step, because other services (eg. txNotifier)
// depend on having an up-to-date peer state!
if state.LastBlockHeight <= cs.state.LastBlockHeight {
cs.Logger.Info(
"Ignoring updateToState()",
"newHeight",
state.LastBlockHeight+1,
"oldHeight",
cs.state.LastBlockHeight+1)
cs.newStep()
return
}
} }
// Reset fields based on state. // Reset fields based on state.
@ -595,13 +601,16 @@ func (cs *State) updateToState(state sm.State) {
case cs.LastCommit == nil: case cs.LastCommit == nil:
// NOTE: when Tendermint starts, it has no votes. reconstructLastCommit // NOTE: when Tendermint starts, it has no votes. reconstructLastCommit
// must be called to reconstruct LastCommit from SeenCommit. // must be called to reconstruct LastCommit from SeenCommit.
panic(fmt.Sprintf("LastCommit cannot be empty in heights > 1 (H:%d)",
panic(fmt.Sprintf("LastCommit cannot be empty after initial block (H:%d)",
state.LastBlockHeight+1, state.LastBlockHeight+1,
)) ))
} }
// Next desired block height // Next desired block height
height := state.LastBlockHeight + 1 height := state.LastBlockHeight + 1
if height == 1 {
height = state.InitialHeight
}
// RoundState fields // RoundState fields
cs.updateHeight(height) cs.updateHeight(height)
@ -933,7 +942,7 @@ func (cs *State) enterNewRound(height int64, round int32) {
// needProofBlock returns true on the first height (so the genesis app hash is signed right away) // needProofBlock returns true on the first height (so the genesis app hash is signed right away)
// and where the last block (height-1) caused the app hash to change // and where the last block (height-1) caused the app hash to change
func (cs *State) needProofBlock(height int64) bool { func (cs *State) needProofBlock(height int64) bool {
if height == 1 {
if height == cs.state.InitialHeight {
return true return true
} }
@ -1090,7 +1099,7 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa
var commit *types.Commit var commit *types.Commit
switch { switch {
case cs.Height == 1:
case cs.Height == cs.state.InitialHeight:
// We're creating a proposal for the first block. // We're creating a proposal for the first block.
// The commit is empty, but not nil. // The commit is empty, but not nil.
commit = types.NewCommit(0, 0, types.BlockID{}, nil) commit = types.NewCommit(0, 0, types.BlockID{}, nil)
@ -1607,7 +1616,7 @@ func (cs *State) recordMetrics(height int64, block *types.Block) {
// height=0 -> MissingValidators and MissingValidatorsPower are both 0. // height=0 -> MissingValidators and MissingValidatorsPower are both 0.
// Remember that the first LastCommit is intentionally empty, so it's not // Remember that the first LastCommit is intentionally empty, so it's not
// fair to increment missing validators number. // fair to increment missing validators number.
if height > 1 {
if height > cs.state.InitialHeight {
// Sanity check that commit size matches validator set size - only applies // Sanity check that commit size matches validator set size - only applies
// after first block. // after first block.
var ( var (
@ -1818,7 +1827,7 @@ func (cs *State) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, error) {
return added, err return added, err
} }
var timestamp time.Time var timestamp time.Time
if voteErr.VoteA.Height == 1 {
if voteErr.VoteA.Height == cs.state.InitialHeight {
timestamp = cs.state.LastBlockTime // genesis time timestamp = cs.state.LastBlockTime // genesis time
} else { } else {
timestamp = sm.MedianTime(cs.LastCommit.MakeCommit(), cs.LastValidators) timestamp = sm.MedianTime(cs.LastCommit.MakeCommit(), cs.LastValidators)


+ 2
- 2
consensus/state_test.go View File

@ -620,7 +620,7 @@ func TestStateLockPOLRelockThenChangeLock(t *testing.T) {
// 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka // 4 vals, one precommits, other 3 polka at next round, so we unlock and precomit the polka
func TestStateLockPOLUnlock(t *testing.T) { func TestStateLockPOLUnlock(t *testing.T) {
cs1, vss, evpool := randStateWithEvpool(4)
cs1, vss, evpool := randStateWithEvpool(t, 4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3] vs2, vs3, vs4 := vss[1], vss[2], vss[3]
height, round := cs1.Height, cs1.Round height, round := cs1.Height, cs1.Round
@ -723,7 +723,7 @@ func TestStateLockPOLUnlock(t *testing.T) {
// v1 should unlock and precommit nil. In the third round another block is proposed, all vals // v1 should unlock and precommit nil. In the third round another block is proposed, all vals
// prevote and now v1 can lock onto the third block and precommit that // prevote and now v1 can lock onto the third block and precommit that
func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) { func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) {
cs1, vss, evpool := randStateWithEvpool(4)
cs1, vss, evpool := randStateWithEvpool(t, 4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3] vs2, vs3, vs4 := vss[1], vss[2], vss[3]
height, round := cs1.Height, cs1.Round height, round := cs1.Height, cs1.Round


+ 1
- 0
evidence/pool_test.go View File

@ -491,6 +491,7 @@ func initializeStateFromValidatorSet(valSet *types.ValidatorSet, height int64) d
stateDB := dbm.NewMemDB() stateDB := dbm.NewMemDB()
state := sm.State{ state := sm.State{
ChainID: evidenceChainID, ChainID: evidenceChainID,
InitialHeight: 1,
LastBlockHeight: height, LastBlockHeight: height,
LastBlockTime: tmtime.Now(), LastBlockTime: tmtime.Now(),
Validators: valSet, Validators: valSet,


+ 2
- 1
node/node.go View File

@ -564,7 +564,8 @@ func startStateSync(ssR *statesync.Reactor, bcR fastSyncReactor, conR *cs.Reacto
state := sm.LoadState(stateDB) state := sm.LoadState(stateDB)
if stateProvider == nil { if stateProvider == nil {
var err error var err error
stateProvider, err = statesync.NewLightClientStateProvider(state.ChainID, state.Version,
stateProvider, err = statesync.NewLightClientStateProvider(
state.ChainID, state.Version, state.InitialHeight,
config.RPCServers, light.TrustOptions{ config.RPCServers, light.TrustOptions{
Period: config.TrustPeriod, Period: config.TrustPeriod,
Height: config.TrustHeight, Height: config.TrustHeight,


+ 1
- 0
proto/tendermint/abci/types.proto View File

@ -64,6 +64,7 @@ message RequestInitChain {
ConsensusParams consensus_params = 3; ConsensusParams consensus_params = 3;
repeated ValidatorUpdate validators = 4 [(gogoproto.nullable) = false]; repeated ValidatorUpdate validators = 4 [(gogoproto.nullable) = false];
bytes app_state_bytes = 5; bytes app_state_bytes = 5;
int64 initial_height = 6;
} }
message RequestQuery { message RequestQuery {


+ 85
- 49
proto/tendermint/state/types.pb.go View File

@ -254,7 +254,8 @@ func (m *Version) GetSoftware() string {
type State struct { type State struct {
Version Version `protobuf:"bytes,1,opt,name=version,proto3" json:"version"` Version Version `protobuf:"bytes,1,opt,name=version,proto3" json:"version"`
// immutable // immutable
ChainID string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
ChainID string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
InitialHeight int64 `protobuf:"varint,14,opt,name=initial_height,json=initialHeight,proto3" json:"initial_height,omitempty"`
// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist) // LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
LastBlockHeight int64 `protobuf:"varint,3,opt,name=last_block_height,json=lastBlockHeight,proto3" json:"last_block_height,omitempty"` LastBlockHeight int64 `protobuf:"varint,3,opt,name=last_block_height,json=lastBlockHeight,proto3" json:"last_block_height,omitempty"`
LastBlockID types1.BlockID `protobuf:"bytes,4,opt,name=last_block_id,json=lastBlockId,proto3" json:"last_block_id"` LastBlockID types1.BlockID `protobuf:"bytes,4,opt,name=last_block_id,json=lastBlockId,proto3" json:"last_block_id"`
@ -326,6 +327,13 @@ func (m *State) GetChainID() string {
return "" return ""
} }
func (m *State) GetInitialHeight() int64 {
if m != nil {
return m.InitialHeight
}
return 0
}
func (m *State) GetLastBlockHeight() int64 { func (m *State) GetLastBlockHeight() int64 {
if m != nil { if m != nil {
return m.LastBlockHeight return m.LastBlockHeight
@ -414,54 +422,55 @@ func init() {
func init() { proto.RegisterFile("tendermint/state/types.proto", fileDescriptor_ccfacf933f22bf93) } func init() { proto.RegisterFile("tendermint/state/types.proto", fileDescriptor_ccfacf933f22bf93) }
var fileDescriptor_ccfacf933f22bf93 = []byte{ var fileDescriptor_ccfacf933f22bf93 = []byte{
// 750 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x95, 0x4f, 0x6f, 0xd3, 0x3e,
0x18, 0xc7, 0x9b, 0x5f, 0xb7, 0xb5, 0x75, 0xd6, 0x75, 0x3f, 0x8f, 0x43, 0xd7, 0xb1, 0xb4, 0x2b,
0x08, 0x4d, 0x1c, 0x52, 0x69, 0x1c, 0x10, 0x97, 0x49, 0x4b, 0x8b, 0x58, 0xa5, 0x09, 0x81, 0x37,
0xed, 0xc0, 0x25, 0x72, 0x1b, 0x2f, 0x89, 0x68, 0x93, 0x28, 0x76, 0xcb, 0x78, 0x01, 0xdc, 0x77,
0xe5, 0xad, 0xf0, 0x0a, 0x76, 0xdc, 0x11, 0x71, 0x18, 0xa8, 0x7b, 0x23, 0xc8, 0x76, 0xfe, 0xb8,
0x2d, 0x93, 0x86, 0xb8, 0x39, 0x7e, 0x9e, 0xe7, 0xe3, 0xaf, 0x1f, 0x7f, 0x1f, 0x05, 0x3c, 0x66,
0x24, 0x70, 0x48, 0x3c, 0xf6, 0x03, 0xd6, 0xa1, 0x0c, 0x33, 0xd2, 0x61, 0x9f, 0x23, 0x42, 0xcd,
0x28, 0x0e, 0x59, 0x08, 0x37, 0xf3, 0xa8, 0x29, 0xa2, 0x8d, 0x47, 0x6e, 0xe8, 0x86, 0x22, 0xd8,
0xe1, 0x2b, 0x99, 0xd7, 0xd8, 0x51, 0x28, 0x78, 0x30, 0xf4, 0x55, 0x48, 0x43, 0x3d, 0x42, 0xec,
0xcf, 0x45, 0x5b, 0x4b, 0xd1, 0x29, 0x1e, 0xf9, 0x0e, 0x66, 0x61, 0x9c, 0x64, 0xec, 0x2e, 0x65,
0x44, 0x38, 0xc6, 0xe3, 0x14, 0x60, 0x28, 0xe1, 0x29, 0x89, 0xa9, 0x1f, 0x06, 0x73, 0x07, 0x34,
0xdd, 0x30, 0x74, 0x47, 0xa4, 0x23, 0xbe, 0x06, 0x93, 0x8b, 0x0e, 0xf3, 0xc7, 0x84, 0x32, 0x3c,
0x8e, 0x64, 0x42, 0xfb, 0x87, 0x06, 0xaa, 0x47, 0x56, 0xb7, 0x8f, 0x08, 0x8d, 0xc2, 0x80, 0x12,
0x0a, 0xbb, 0x40, 0x77, 0xc8, 0xc8, 0x9f, 0x92, 0xd8, 0x66, 0x97, 0xb4, 0xae, 0xb5, 0x8a, 0xfb,
0xfa, 0x41, 0xdb, 0x54, 0x9a, 0xc1, 0x2f, 0x69, 0xa6, 0x05, 0x3d, 0x99, 0x7b, 0x76, 0x89, 0x80,
0x93, 0x2e, 0x29, 0x3c, 0x04, 0x15, 0x12, 0x38, 0xf6, 0x60, 0x14, 0x0e, 0x3f, 0xd6, 0xff, 0x6b,
0x69, 0xfb, 0xfa, 0xc1, 0xde, 0xbd, 0x88, 0xd7, 0x81, 0x63, 0xf1, 0x44, 0x54, 0x26, 0xc9, 0x0a,
0xf6, 0x80, 0x3e, 0x20, 0xae, 0x1f, 0x24, 0x84, 0xa2, 0x20, 0x3c, 0xb9, 0x97, 0x60, 0xf1, 0x5c,
0xc9, 0x00, 0x83, 0x6c, 0xdd, 0xfe, 0xa2, 0x81, 0x8d, 0xf3, 0xb4, 0xa1, 0xb4, 0x1f, 0x5c, 0x84,
0xb0, 0x0b, 0xaa, 0x59, 0x8b, 0x6d, 0x4a, 0x58, 0x5d, 0x13, 0x68, 0x43, 0x45, 0xcb, 0x06, 0x66,
0x85, 0xa7, 0x84, 0xa1, 0xf5, 0xa9, 0xf2, 0x05, 0x4d, 0xb0, 0x35, 0xc2, 0x94, 0xd9, 0x1e, 0xf1,
0x5d, 0x8f, 0xd9, 0x43, 0x0f, 0x07, 0x2e, 0x71, 0xc4, 0x3d, 0x8b, 0xe8, 0x7f, 0x1e, 0x3a, 0x16,
0x91, 0xae, 0x0c, 0xb4, 0xbf, 0x6a, 0x60, 0xab, 0xcb, 0x75, 0x06, 0x74, 0x42, 0xdf, 0x89, 0xf7,
0x13, 0x62, 0x10, 0xd8, 0x1c, 0xa6, 0xdb, 0xb6, 0x7c, 0xd7, 0x44, 0xcf, 0xde, 0xb2, 0x9e, 0x05,
0x80, 0xb5, 0x72, 0x7d, 0xdb, 0x2c, 0xa0, 0xda, 0x70, 0x7e, 0xfb, 0xaf, 0xb5, 0x79, 0xa0, 0x74,
0x2e, 0x8d, 0x03, 0x8f, 0x40, 0x25, 0xa3, 0x25, 0x3a, 0x76, 0x55, 0x1d, 0x89, 0xc1, 0x72, 0x25,
0x89, 0x86, 0xbc, 0x0a, 0x36, 0x40, 0x99, 0x86, 0x17, 0xec, 0x13, 0x8e, 0x89, 0x38, 0xb2, 0x82,
0xb2, 0xef, 0xf6, 0xb7, 0x35, 0xb0, 0x7a, 0xca, 0xe7, 0x08, 0xbe, 0x02, 0xa5, 0x84, 0x95, 0x1c,
0xb3, 0x6d, 0x2e, 0xce, 0x9a, 0x99, 0x88, 0x4a, 0x8e, 0x48, 0xf3, 0xe1, 0x33, 0x50, 0x1e, 0x7a,
0xd8, 0x0f, 0x6c, 0x5f, 0xde, 0xa9, 0x62, 0xe9, 0xb3, 0xdb, 0x66, 0xa9, 0xcb, 0xf7, 0xfa, 0x3d,
0x54, 0x12, 0xc1, 0xbe, 0x03, 0x9f, 0x03, 0x71, 0x57, 0xe9, 0x9f, 0xa4, 0x19, 0xc2, 0x46, 0x45,
0x54, 0xe3, 0x01, 0x61, 0x10, 0xd9, 0x09, 0x88, 0x40, 0x55, 0xc9, 0xf5, 0x9d, 0xfa, 0xca, 0xb2,
0x28, 0xf9, 0x06, 0xa2, 0xaa, 0xdf, 0xb3, 0xb6, 0xb8, 0xa8, 0xd9, 0x6d, 0x53, 0x3f, 0x49, 0x51,
0xfd, 0x1e, 0xd2, 0x33, 0x6e, 0xdf, 0x81, 0x27, 0xa0, 0xa6, 0x30, 0xf9, 0xd4, 0xd5, 0x57, 0x05,
0xb5, 0x61, 0xca, 0x91, 0x34, 0xd3, 0x91, 0x34, 0xcf, 0xd2, 0x91, 0xb4, 0xca, 0x1c, 0x7b, 0xf5,
0xb3, 0xa9, 0xa1, 0x6a, 0xc6, 0xe2, 0x51, 0xf8, 0x06, 0xd4, 0x02, 0x72, 0xc9, 0xec, 0xcc, 0x85,
0xb4, 0xbe, 0xf6, 0x20, 0xdf, 0x6e, 0xf0, 0xb2, 0x7c, 0x04, 0xe0, 0x21, 0x00, 0x0a, 0xa3, 0xf4,
0x20, 0x86, 0x52, 0xc1, 0x85, 0x88, 0x6b, 0x29, 0x90, 0xf2, 0xc3, 0x84, 0xf0, 0x32, 0x45, 0x48,
0x17, 0x18, 0xaa, 0x4d, 0x73, 0x5e, 0xe6, 0xd8, 0x8a, 0x78, 0xac, 0x9d, 0xdc, 0xb1, 0x79, 0x75,
0xe2, 0xdd, 0x3f, 0xce, 0x0f, 0xf8, 0xc7, 0xf9, 0x79, 0x0b, 0x9e, 0xce, 0xcd, 0xcf, 0x02, 0x3f,
0x93, 0xa7, 0x0b, 0x79, 0x2d, 0x65, 0xa0, 0xe6, 0x41, 0xa9, 0xc6, 0xd4, 0x88, 0x31, 0xa1, 0x93,
0x11, 0xa3, 0xb6, 0x87, 0xa9, 0x57, 0x5f, 0x6f, 0x69, 0xfb, 0xeb, 0xd2, 0x88, 0x48, 0xee, 0x1f,
0x63, 0xea, 0xc1, 0x6d, 0x50, 0xc6, 0x51, 0x24, 0x53, 0xaa, 0x22, 0xa5, 0x84, 0xa3, 0x88, 0x87,
0xac, 0xf7, 0xd7, 0x33, 0x43, 0xbb, 0x99, 0x19, 0xda, 0xaf, 0x99, 0xa1, 0x5d, 0xdd, 0x19, 0x85,
0x9b, 0x3b, 0xa3, 0xf0, 0xfd, 0xce, 0x28, 0x7c, 0x78, 0xe9, 0xfa, 0xcc, 0x9b, 0x0c, 0xcc, 0x61,
0x38, 0xee, 0xa8, 0x3f, 0x8b, 0x7c, 0x29, 0xff, 0x58, 0x8b, 0xff, 0xba, 0xc1, 0x9a, 0xd8, 0x7f,
0xf1, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xcb, 0xd2, 0xe7, 0x00, 0x06, 0x07, 0x00, 0x00,
// 763 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xcf, 0x6f, 0xd3, 0x30,
0x14, 0x6e, 0xe8, 0xb6, 0xb6, 0xce, 0xda, 0x0e, 0x8f, 0x43, 0xd6, 0xb1, 0xb4, 0x2b, 0x3f, 0x34,
0x71, 0x48, 0xa5, 0x71, 0x40, 0x5c, 0x26, 0x2d, 0x2d, 0x62, 0x95, 0x26, 0x04, 0xd9, 0xb4, 0x03,
0x97, 0xc8, 0x6d, 0xbc, 0x24, 0xa2, 0x4d, 0xa2, 0xd8, 0x2d, 0xe3, 0x0f, 0xe0, 0xbe, 0x2b, 0xff,
0xd1, 0x8e, 0x3b, 0x22, 0x0e, 0x03, 0xba, 0x7f, 0x04, 0xd9, 0xce, 0x0f, 0xb7, 0x65, 0xd2, 0x10,
0x37, 0xfb, 0x7d, 0xdf, 0xfb, 0xfc, 0xf9, 0xf9, 0x3d, 0x19, 0x3c, 0xa6, 0x38, 0x70, 0x70, 0x3c,
0xf6, 0x03, 0xda, 0x21, 0x14, 0x51, 0xdc, 0xa1, 0x5f, 0x22, 0x4c, 0x8c, 0x28, 0x0e, 0x69, 0x08,
0x37, 0x72, 0xd4, 0xe0, 0x68, 0xe3, 0x91, 0x1b, 0xba, 0x21, 0x07, 0x3b, 0x6c, 0x25, 0x78, 0x8d,
0x6d, 0x49, 0x05, 0x0d, 0x86, 0xbe, 0x2c, 0xd2, 0x90, 0x8f, 0xe0, 0xf1, 0x39, 0xb4, 0xb5, 0x84,
0x4e, 0xd1, 0xc8, 0x77, 0x10, 0x0d, 0xe3, 0x84, 0xb1, 0xb3, 0xc4, 0x88, 0x50, 0x8c, 0xc6, 0xa9,
0x80, 0x2e, 0xc1, 0x53, 0x1c, 0x13, 0x3f, 0x0c, 0xe6, 0x0e, 0x68, 0xba, 0x61, 0xe8, 0x8e, 0x70,
0x87, 0xef, 0x06, 0x93, 0xf3, 0x0e, 0xf5, 0xc7, 0x98, 0x50, 0x34, 0x8e, 0x04, 0xa1, 0xfd, 0x43,
0x01, 0xd5, 0x43, 0xb3, 0xdb, 0xb7, 0x30, 0x89, 0xc2, 0x80, 0x60, 0x02, 0xbb, 0x40, 0x75, 0xf0,
0xc8, 0x9f, 0xe2, 0xd8, 0xa6, 0x17, 0x44, 0x53, 0x5a, 0xc5, 0x3d, 0x75, 0xbf, 0x6d, 0x48, 0xc5,
0x60, 0x97, 0x34, 0xd2, 0x84, 0x9e, 0xe0, 0x9e, 0x5e, 0x58, 0xc0, 0x49, 0x97, 0x04, 0x1e, 0x80,
0x0a, 0x0e, 0x1c, 0x7b, 0x30, 0x0a, 0x87, 0x9f, 0xb4, 0x07, 0x2d, 0x65, 0x4f, 0xdd, 0xdf, 0xbd,
0x53, 0xe2, 0x4d, 0xe0, 0x98, 0x8c, 0x68, 0x95, 0x71, 0xb2, 0x82, 0x3d, 0xa0, 0x0e, 0xb0, 0xeb,
0x07, 0x89, 0x42, 0x91, 0x2b, 0x3c, 0xb9, 0x53, 0xc1, 0x64, 0x5c, 0xa1, 0x01, 0x06, 0xd9, 0xba,
0xfd, 0x55, 0x01, 0xb5, 0xb3, 0xb4, 0xa0, 0xa4, 0x1f, 0x9c, 0x87, 0xb0, 0x0b, 0xaa, 0x59, 0x89,
0x6d, 0x82, 0xa9, 0xa6, 0x70, 0x69, 0x5d, 0x96, 0x16, 0x05, 0xcc, 0x12, 0x4f, 0x30, 0xb5, 0xd6,
0xa7, 0xd2, 0x0e, 0x1a, 0x60, 0x73, 0x84, 0x08, 0xb5, 0x3d, 0xec, 0xbb, 0x1e, 0xb5, 0x87, 0x1e,
0x0a, 0x5c, 0xec, 0xf0, 0x7b, 0x16, 0xad, 0x87, 0x0c, 0x3a, 0xe2, 0x48, 0x57, 0x00, 0xed, 0x6f,
0x0a, 0xd8, 0xec, 0x32, 0x9f, 0x01, 0x99, 0x90, 0xf7, 0xfc, 0xfd, 0xb8, 0x19, 0x0b, 0x6c, 0x0c,
0xd3, 0xb0, 0x2d, 0xde, 0x35, 0xf1, 0xb3, 0xbb, 0xec, 0x67, 0x41, 0xc0, 0x5c, 0xb9, 0xba, 0x69,
0x16, 0xac, 0xfa, 0x70, 0x3e, 0xfc, 0xcf, 0xde, 0x3c, 0x50, 0x3a, 0x13, 0x8d, 0x03, 0x0f, 0x41,
0x25, 0x53, 0x4b, 0x7c, 0xec, 0xc8, 0x3e, 0x92, 0x06, 0xcb, 0x9d, 0x24, 0x1e, 0xf2, 0x2c, 0xd8,
0x00, 0x65, 0x12, 0x9e, 0xd3, 0xcf, 0x28, 0xc6, 0xfc, 0xc8, 0x8a, 0x95, 0xed, 0xdb, 0xbf, 0xd7,
0xc0, 0xea, 0x09, 0x9b, 0x23, 0xf8, 0x1a, 0x94, 0x12, 0xad, 0xe4, 0x98, 0x2d, 0x63, 0x71, 0xd6,
0x8c, 0xc4, 0x54, 0x72, 0x44, 0xca, 0x87, 0xcf, 0x41, 0x79, 0xe8, 0x21, 0x3f, 0xb0, 0x7d, 0x71,
0xa7, 0x8a, 0xa9, 0xce, 0x6e, 0x9a, 0xa5, 0x2e, 0x8b, 0xf5, 0x7b, 0x56, 0x89, 0x83, 0x7d, 0x07,
0x3e, 0x03, 0x35, 0x3f, 0xf0, 0xa9, 0x8f, 0x46, 0x49, 0x25, 0xb4, 0x1a, 0xaf, 0x40, 0x35, 0x89,
0x8a, 0x22, 0xc0, 0x17, 0x80, 0x97, 0x44, 0xb4, 0x59, 0xca, 0x2c, 0x72, 0x66, 0x9d, 0x01, 0xbc,
0x8f, 0x12, 0xae, 0x05, 0xaa, 0x12, 0xd7, 0x77, 0xb4, 0x95, 0x65, 0xef, 0xe2, 0xa9, 0x78, 0x56,
0xbf, 0x67, 0x6e, 0x32, 0xef, 0xb3, 0x9b, 0xa6, 0x7a, 0x9c, 0x4a, 0xf5, 0x7b, 0x96, 0x9a, 0xe9,
0xf6, 0x1d, 0x78, 0x0c, 0xea, 0x92, 0x26, 0x1b, 0x4e, 0x6d, 0x95, 0xab, 0x36, 0x0c, 0x31, 0xb9,
0x46, 0x3a, 0xb9, 0xc6, 0x69, 0x3a, 0xb9, 0x66, 0x99, 0xc9, 0x5e, 0xfe, 0x6c, 0x2a, 0x56, 0x35,
0xd3, 0x62, 0x28, 0x7c, 0x0b, 0xea, 0x01, 0xbe, 0xa0, 0x76, 0xd6, 0xac, 0x44, 0x5b, 0xbb, 0x57,
0x7b, 0xd7, 0x58, 0x5a, 0x3e, 0x29, 0xf0, 0x00, 0x00, 0x49, 0xa3, 0x74, 0x2f, 0x0d, 0x29, 0x83,
0x19, 0xe1, 0xd7, 0x92, 0x44, 0xca, 0xf7, 0x33, 0xc2, 0xd2, 0x24, 0x23, 0x5d, 0xa0, 0xcb, 0xdd,
0x9c, 0xeb, 0x65, 0x8d, 0x5d, 0xe1, 0x8f, 0xb5, 0x9d, 0x37, 0x76, 0x9e, 0x9d, 0xb4, 0xf8, 0x5f,
0xc7, 0x0c, 0xfc, 0xe7, 0x98, 0xbd, 0x03, 0x4f, 0xe7, 0xc6, 0x6c, 0x41, 0x3f, 0xb3, 0xa7, 0x72,
0x7b, 0x2d, 0x69, 0xee, 0xe6, 0x85, 0x52, 0x8f, 0x69, 0x23, 0xc6, 0x98, 0x4c, 0x46, 0x94, 0xd8,
0x1e, 0x22, 0x9e, 0xb6, 0xde, 0x52, 0xf6, 0xd6, 0x45, 0x23, 0x5a, 0x22, 0x7e, 0x84, 0x88, 0x07,
0xb7, 0x40, 0x19, 0x45, 0x91, 0xa0, 0x54, 0x39, 0xa5, 0x84, 0xa2, 0x88, 0x41, 0xe6, 0x87, 0xab,
0x99, 0xae, 0x5c, 0xcf, 0x74, 0xe5, 0xd7, 0x4c, 0x57, 0x2e, 0x6f, 0xf5, 0xc2, 0xf5, 0xad, 0x5e,
0xf8, 0x7e, 0xab, 0x17, 0x3e, 0xbe, 0x72, 0x7d, 0xea, 0x4d, 0x06, 0xc6, 0x30, 0x1c, 0x77, 0xe4,
0x3f, 0x25, 0x5f, 0x8a, 0x8f, 0x6d, 0xf1, 0x4b, 0x1c, 0xac, 0xf1, 0xf8, 0xcb, 0x3f, 0x01, 0x00,
0x00, 0xff, 0xff, 0xa5, 0x17, 0xac, 0x23, 0x2d, 0x07, 0x00, 0x00,
} }
func (m *ABCIResponses) Marshal() (dAtA []byte, err error) { func (m *ABCIResponses) Marshal() (dAtA []byte, err error) {
@ -663,6 +672,11 @@ func (m *State) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i _ = i
var l int var l int
_ = l _ = l
if m.InitialHeight != 0 {
i = encodeVarintTypes(dAtA, i, uint64(m.InitialHeight))
i--
dAtA[i] = 0x70
}
if len(m.AppHash) > 0 { if len(m.AppHash) > 0 {
i -= len(m.AppHash) i -= len(m.AppHash)
copy(dAtA[i:], m.AppHash) copy(dAtA[i:], m.AppHash)
@ -902,6 +916,9 @@ func (m *State) Size() (n int) {
if l > 0 { if l > 0 {
n += 1 + l + sovTypes(uint64(l)) n += 1 + l + sovTypes(uint64(l))
} }
if m.InitialHeight != 0 {
n += 1 + sovTypes(uint64(m.InitialHeight))
}
return n return n
} }
@ -1827,6 +1844,25 @@ func (m *State) Unmarshal(dAtA []byte) error {
m.AppHash = []byte{} m.AppHash = []byte{}
} }
iNdEx = postIndex iNdEx = postIndex
case 14:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field InitialHeight", wireType)
}
m.InitialHeight = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.InitialHeight |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
}
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:]) skippy, err := skipTypes(dAtA[iNdEx:])


+ 2
- 1
proto/tendermint/state/types.proto View File

@ -41,7 +41,8 @@ message State {
Version version = 1 [(gogoproto.nullable) = false]; Version version = 1 [(gogoproto.nullable) = false];
// immutable // immutable
string chain_id = 2 [(gogoproto.customname) = "ChainID"];
string chain_id = 2 [(gogoproto.customname) = "ChainID"];
int64 initial_height = 14;
// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist) // LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
int64 last_block_height = 3; int64 last_block_height = 3;


+ 1
- 1
rpc/core/env.go View File

@ -150,7 +150,7 @@ func getHeight(latestHeight int64, heightPtr *int64) (int64, error) {
} }
base := env.BlockStore.Base() base := env.BlockStore.Base()
if height < base { if height < base {
return 0, fmt.Errorf("height %v is not available, blocks pruned at height %v",
return 0, fmt.Errorf("height %v is not available, lowest height is %v",
height, base) height, base)
} }
return height, nil return height, nil


+ 11
- 6
state/execution.go View File

@ -134,7 +134,8 @@ func (blockExec *BlockExecutor) ApplyBlock(
} }
startTime := time.Now().UnixNano() startTime := time.Now().UnixNano()
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, blockExec.db)
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block,
blockExec.db, state.InitialHeight)
endTime := time.Now().UnixNano() endTime := time.Now().UnixNano()
blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000) blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000)
if err != nil { if err != nil {
@ -254,6 +255,7 @@ func execBlockOnProxyApp(
proxyAppConn proxy.AppConnConsensus, proxyAppConn proxy.AppConnConsensus,
block *types.Block, block *types.Block,
stateDB dbm.DB, stateDB dbm.DB,
initialHeight int64,
) (*tmstate.ABCIResponses, error) { ) (*tmstate.ABCIResponses, error) {
var validTxs, invalidTxs = 0, 0 var validTxs, invalidTxs = 0, 0
@ -281,7 +283,7 @@ func execBlockOnProxyApp(
} }
proxyAppConn.SetResponseCallback(proxyCb) proxyAppConn.SetResponseCallback(proxyCb)
commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB)
commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB, initialHeight)
// Begin block // Begin block
var err error var err error
@ -320,12 +322,13 @@ func execBlockOnProxyApp(
return abciResponses, nil return abciResponses, nil
} }
func getBeginBlockValidatorInfo(block *types.Block, stateDB dbm.DB) (abci.LastCommitInfo, []abci.Evidence) {
func getBeginBlockValidatorInfo(block *types.Block, stateDB dbm.DB,
initialHeight int64) (abci.LastCommitInfo, []abci.Evidence) {
voteInfos := make([]abci.VoteInfo, block.LastCommit.Size()) voteInfos := make([]abci.VoteInfo, block.LastCommit.Size())
// block.Height=1 -> LastCommitInfo.Votes are empty.
// Initial block -> LastCommitInfo.Votes are empty.
// Remember that the first LastCommit is intentionally empty, so it makes // Remember that the first LastCommit is intentionally empty, so it makes
// sense for LastCommitInfo.Votes to also be empty. // sense for LastCommitInfo.Votes to also be empty.
if block.Height > 1 {
if block.Height > initialHeight {
lastValSet, err := LoadValidators(stateDB, block.Height-1) lastValSet, err := LoadValidators(stateDB, block.Height-1)
if err != nil { if err != nil {
panic(err) panic(err)
@ -445,6 +448,7 @@ func updateState(
return State{ return State{
Version: nextVersion, Version: nextVersion,
ChainID: state.ChainID, ChainID: state.ChainID,
InitialHeight: state.InitialHeight,
LastBlockHeight: header.Height, LastBlockHeight: header.Height,
LastBlockID: blockID, LastBlockID: blockID,
LastBlockTime: header.Time, LastBlockTime: header.Time,
@ -515,8 +519,9 @@ func ExecCommitBlock(
block *types.Block, block *types.Block,
logger log.Logger, logger log.Logger,
stateDB dbm.DB, stateDB dbm.DB,
initialHeight int64,
) ([]byte, error) { ) ([]byte, error) {
_, err := execBlockOnProxyApp(logger, appConnConsensus, block, stateDB)
_, err := execBlockOnProxyApp(logger, appConnConsensus, block, stateDB, initialHeight)
if err != nil { if err != nil {
logger.Error("Error executing block on proxy app", "height", block.Height, "err", err) logger.Error("Error executing block on proxy app", "height", block.Height, "err", err)
return nil, err return nil, err


+ 2
- 2
state/execution_test.go View File

@ -94,7 +94,7 @@ func TestBeginBlockValidators(t *testing.T) {
// block for height 2 // block for height 2
block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address) block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address)
_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateDB)
_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateDB, 1)
require.Nil(t, err, tc.desc) require.Nil(t, err, tc.desc)
// -> app receives a list of validators with a bool indicating if they signed // -> app receives a list of validators with a bool indicating if they signed
@ -163,7 +163,7 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
block, _ := state.MakeBlock(10, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address) block, _ := state.MakeBlock(10, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address)
block.Time = now block.Time = now
block.Evidence.Evidence = tc.evidence block.Evidence.Evidence = tc.evidence
_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateDB)
_, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateDB, 1)
require.Nil(t, err, tc.desc) require.Nil(t, err, tc.desc)
// -> app must receive an index of the byzantine validator // -> app must receive an index of the byzantine validator


+ 13
- 8
state/state.go View File

@ -49,7 +49,8 @@ type State struct {
Version tmstate.Version Version tmstate.Version
// immutable // immutable
ChainID string
ChainID string
InitialHeight int64 // should be 1, not 0, when starting from height 1
// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist) // LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
LastBlockHeight int64 LastBlockHeight int64
@ -83,8 +84,9 @@ type State struct {
func (state State) Copy() State { func (state State) Copy() State {
return State{ return State{
Version: state.Version,
ChainID: state.ChainID,
Version: state.Version,
ChainID: state.ChainID,
InitialHeight: state.InitialHeight,
LastBlockHeight: state.LastBlockHeight, LastBlockHeight: state.LastBlockHeight,
LastBlockID: state.LastBlockID, LastBlockID: state.LastBlockID,
@ -139,6 +141,7 @@ func (state *State) ToProto() (*tmstate.State, error) {
sm.Version = state.Version sm.Version = state.Version
sm.ChainID = state.ChainID sm.ChainID = state.ChainID
sm.InitialHeight = state.InitialHeight
sm.LastBlockHeight = state.LastBlockHeight sm.LastBlockHeight = state.LastBlockHeight
sm.LastBlockID = state.LastBlockID.ToProto() sm.LastBlockID = state.LastBlockID.ToProto()
@ -182,6 +185,7 @@ func StateFromProto(pb *tmstate.State) (*State, error) { //nolint:golint
state.Version = pb.Version state.Version = pb.Version
state.ChainID = pb.ChainID state.ChainID = pb.ChainID
state.InitialHeight = pb.InitialHeight
bi, err := types.BlockIDFromProto(&pb.LastBlockID) bi, err := types.BlockIDFromProto(&pb.LastBlockID)
if err != nil { if err != nil {
@ -241,7 +245,7 @@ func (state State) MakeBlock(
// Set time. // Set time.
var timestamp time.Time var timestamp time.Time
if height == 1 {
if height == state.InitialHeight {
timestamp = state.LastBlockTime // genesis time timestamp = state.LastBlockTime // genesis time
} else { } else {
timestamp = MedianTime(commit, state.LastValidators) timestamp = MedianTime(commit, state.LastValidators)
@ -331,8 +335,9 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
} }
return State{ return State{
Version: InitStateVersion,
ChainID: genDoc.ChainID,
Version: InitStateVersion,
ChainID: genDoc.ChainID,
InitialHeight: genDoc.InitialHeight,
LastBlockHeight: 0, LastBlockHeight: 0,
LastBlockID: types.BlockID{}, LastBlockID: types.BlockID{},
@ -341,10 +346,10 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
NextValidators: nextValidatorSet, NextValidators: nextValidatorSet,
Validators: validatorSet, Validators: validatorSet,
LastValidators: types.NewValidatorSet(nil), LastValidators: types.NewValidatorSet(nil),
LastHeightValidatorsChanged: 1,
LastHeightValidatorsChanged: genDoc.InitialHeight,
ConsensusParams: *genDoc.ConsensusParams, ConsensusParams: *genDoc.ConsensusParams,
LastHeightConsensusParamsChanged: 1,
LastHeightConsensusParamsChanged: genDoc.InitialHeight,
AppHash: genDoc.AppHash, AppHash: genDoc.AppHash,
}, nil }, nil


+ 13
- 8
state/store.go View File

@ -110,12 +110,12 @@ func SaveState(db dbm.DB, state State) {
func saveState(db dbm.DB, state State, key []byte) { func saveState(db dbm.DB, state State, key []byte) {
nextHeight := state.LastBlockHeight + 1 nextHeight := state.LastBlockHeight + 1
// If first block, save validators for block 1.
// If first block, save validators for the block.
if nextHeight == 1 { if nextHeight == 1 {
nextHeight = state.InitialHeight
// This extra logic due to Tendermint validator set changes being delayed 1 block. // This extra logic due to Tendermint validator set changes being delayed 1 block.
// It may get overwritten due to InitChain validator updates. // It may get overwritten due to InitChain validator updates.
lastHeightVoteChanged := int64(1)
saveValidatorsInfo(db, nextHeight, lastHeightVoteChanged, state.Validators)
saveValidatorsInfo(db, nextHeight, nextHeight, state.Validators)
} }
// Save next validators. // Save next validators.
saveValidatorsInfo(db, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators) saveValidatorsInfo(db, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
@ -130,11 +130,16 @@ func saveState(db dbm.DB, state State, key []byte) {
// BootstrapState saves a new state, used e.g. by state sync when starting from non-zero height. // BootstrapState saves a new state, used e.g. by state sync when starting from non-zero height.
func BootstrapState(db dbm.DB, state State) error { func BootstrapState(db dbm.DB, state State) error {
height := state.LastBlockHeight
saveValidatorsInfo(db, height, height, state.LastValidators)
saveValidatorsInfo(db, height+1, height+1, state.Validators)
saveValidatorsInfo(db, height+2, height+2, state.NextValidators)
saveConsensusParamsInfo(db, height+1, height+1, state.ConsensusParams)
height := state.LastBlockHeight + 1
if height == 1 {
height = state.InitialHeight
}
if height > 1 && !state.LastValidators.IsNilOrEmpty() {
saveValidatorsInfo(db, height-1, height-1, state.LastValidators)
}
saveValidatorsInfo(db, height, height, state.Validators)
saveValidatorsInfo(db, height+1, height+1, state.NextValidators)
saveConsensusParamsInfo(db, height, height, state.ConsensusParams)
return db.SetSync(stateKey, state.Bytes()) return db.SetSync(stateKey, state.Bytes())
} }


+ 1
- 0
state/store_test.go View File

@ -119,6 +119,7 @@ func TestPruneStates(t *testing.T) {
} }
state := sm.State{ state := sm.State{
InitialHeight: 1,
LastBlockHeight: h - 1, LastBlockHeight: h - 1,
Validators: validatorSet, Validators: validatorSet,
NextValidators: validatorSet, NextValidators: validatorSet,


+ 15
- 5
state/validation.go View File

@ -34,7 +34,11 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
block.ChainID, block.ChainID,
) )
} }
if block.Height != state.LastBlockHeight+1 {
if state.LastBlockHeight == 0 && block.Height != state.InitialHeight {
return fmt.Errorf("wrong Block.Header.Height. Expected %v for initial block, got %v",
block.Height, state.InitialHeight)
}
if state.LastBlockHeight > 0 && block.Height != state.LastBlockHeight+1 {
return fmt.Errorf("wrong Block.Header.Height. Expected %v, got %v", return fmt.Errorf("wrong Block.Header.Height. Expected %v, got %v",
state.LastBlockHeight+1, state.LastBlockHeight+1,
block.Height, block.Height,
@ -82,9 +86,9 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
} }
// Validate block LastCommit. // Validate block LastCommit.
if block.Height == 1 {
if block.Height == state.InitialHeight {
if len(block.LastCommit.Signatures) != 0 { if len(block.LastCommit.Signatures) != 0 {
return errors.New("block at height 1 can't have LastCommit signatures")
return errors.New("initial block can't have LastCommit signatures")
} }
} else { } else {
// LastCommit.Signatures length is checked in VerifyCommit. // LastCommit.Signatures length is checked in VerifyCommit.
@ -110,7 +114,8 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
} }
// Validate block Time // Validate block Time
if block.Height > 1 {
switch {
case block.Height > state.InitialHeight:
if !block.Time.After(state.LastBlockTime) { if !block.Time.After(state.LastBlockTime) {
return fmt.Errorf("block time %v not greater than last block time %v", return fmt.Errorf("block time %v not greater than last block time %v",
block.Time, block.Time,
@ -124,7 +129,8 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
block.Time, block.Time,
) )
} }
} else if block.Height == 1 {
case block.Height == state.InitialHeight:
genesisTime := state.LastBlockTime genesisTime := state.LastBlockTime
if !block.Time.Equal(genesisTime) { if !block.Time.Equal(genesisTime) {
return fmt.Errorf("block time %v is not equal to genesis time %v", return fmt.Errorf("block time %v is not equal to genesis time %v",
@ -132,6 +138,10 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
genesisTime, genesisTime,
) )
} }
default:
return fmt.Errorf("block height %v lower than initial height %v",
block.Height, state.InitialHeight)
} }
// Limit the amount of evidence // Limit the amount of evidence


+ 16
- 9
statesync/stateprovider.go View File

@ -35,16 +35,18 @@ type StateProvider interface {
// lightClientStateProvider is a state provider using the light client. // lightClientStateProvider is a state provider using the light client.
type lightClientStateProvider struct { type lightClientStateProvider struct {
tmsync.Mutex // light.Client is not concurrency-safe
lc *light.Client
version tmstate.Version
providers map[lightprovider.Provider]string
tmsync.Mutex // light.Client is not concurrency-safe
lc *light.Client
version tmstate.Version
initialHeight int64
providers map[lightprovider.Provider]string
} }
// NewLightClientStateProvider creates a new StateProvider using a light client and RPC clients. // NewLightClientStateProvider creates a new StateProvider using a light client and RPC clients.
func NewLightClientStateProvider( func NewLightClientStateProvider(
chainID string, chainID string,
version tmstate.Version, version tmstate.Version,
initialHeight int64,
servers []string, servers []string,
trustOptions light.TrustOptions, trustOptions light.TrustOptions,
logger log.Logger, logger log.Logger,
@ -73,9 +75,10 @@ func NewLightClientStateProvider(
return nil, err return nil, err
} }
return &lightClientStateProvider{ return &lightClientStateProvider{
lc: lc,
version: version,
providers: providerRemotes,
lc: lc,
version: version,
initialHeight: initialHeight,
providers: providerRemotes,
}, nil }, nil
} }
@ -109,8 +112,12 @@ func (s *lightClientStateProvider) State(height uint64) (sm.State, error) {
defer s.Unlock() defer s.Unlock()
state := sm.State{ state := sm.State{
ChainID: s.lc.ChainID(),
Version: s.version,
ChainID: s.lc.ChainID(),
Version: s.version,
InitialHeight: s.initialHeight,
}
if state.InitialHeight == 0 {
state.InitialHeight = 1
} }
// We need to verify up until h+2, to get the validator set. This also prefetches the headers // We need to verify up until h+2, to get the validator set. This also prefetches the headers


+ 2
- 4
types/block.go View File

@ -65,10 +65,8 @@ func (b *Block) ValidateBasic() error {
if b.LastCommit == nil { if b.LastCommit == nil {
return errors.New("nil LastCommit") return errors.New("nil LastCommit")
} }
if b.Header.Height > 1 {
if err := b.LastCommit.ValidateBasic(); err != nil {
return fmt.Errorf("wrong LastCommit: %v", err)
}
if err := b.LastCommit.ValidateBasic(); err != nil {
return fmt.Errorf("wrong LastCommit: %v", err)
} }
if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) { if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) {


+ 7
- 0
types/genesis.go View File

@ -39,6 +39,7 @@ type GenesisValidator struct {
type GenesisDoc struct { type GenesisDoc struct {
GenesisTime time.Time `json:"genesis_time"` GenesisTime time.Time `json:"genesis_time"`
ChainID string `json:"chain_id"` ChainID string `json:"chain_id"`
InitialHeight int64 `json:"initial_height"`
ConsensusParams *tmproto.ConsensusParams `json:"consensus_params,omitempty"` ConsensusParams *tmproto.ConsensusParams `json:"consensus_params,omitempty"`
Validators []GenesisValidator `json:"validators,omitempty"` Validators []GenesisValidator `json:"validators,omitempty"`
AppHash tmbytes.HexBytes `json:"app_hash"` AppHash tmbytes.HexBytes `json:"app_hash"`
@ -73,6 +74,12 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error {
if len(genDoc.ChainID) > MaxChainIDLen { if len(genDoc.ChainID) > MaxChainIDLen {
return fmt.Errorf("chain_id in genesis doc is too long (max: %d)", MaxChainIDLen) return fmt.Errorf("chain_id in genesis doc is too long (max: %d)", MaxChainIDLen)
} }
if genDoc.InitialHeight < 0 {
return fmt.Errorf("initial_height cannot be negative (got %v)", genDoc.InitialHeight)
}
if genDoc.InitialHeight == 0 {
genDoc.InitialHeight = 1
}
if genDoc.ConsensusParams == nil { if genDoc.ConsensusParams == nil {
genDoc.ConsensusParams = DefaultConsensusParams() genDoc.ConsensusParams = DefaultConsensusParams()


+ 18
- 9
types/genesis_test.go View File

@ -19,7 +19,8 @@ func TestGenesisBad(t *testing.T) {
{}, // empty {}, // empty
{1, 1, 1, 1, 1}, // junk {1, 1, 1, 1, 1}, // junk
[]byte(`{}`), // empty []byte(`{}`), // empty
[]byte(`{"chain_id":"mychain","validators":[{}]}`), // invalid validator
[]byte(`{"chain_id":"mychain","validators":[{}]}`), // invalid validator
[]byte(`{"chain_id":"chain","initial_height":"-1"}`), // negative initial height
// missing pub_key type // missing pub_key type
[]byte( []byte(
`{"validators":[{"pub_key":{"value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":"10","name":""}]}`, `{"validators":[{"pub_key":{"value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":"10","name":""}]}`,
@ -59,11 +60,19 @@ func TestGenesisBad(t *testing.T) {
func TestGenesisGood(t *testing.T) { func TestGenesisGood(t *testing.T) {
// test a good one by raw json // test a good one by raw json
genDocBytes := []byte( genDocBytes := []byte(
`{"genesis_time":"0001-01-01T00:00:00Z","chain_id":"test-chain-QDKdJr","consensus_params":null,"validators":[` +
`{"pub_key":{` +
`"type":"tendermint/PubKeyEd25519","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="` +
`},"power":"10","name":""}` +
`],"app_hash":"","app_state":{"account_owner": "Bob"}}`,
`{
"genesis_time": "0001-01-01T00:00:00Z",
"chain_id": "test-chain-QDKdJr",
"initial_height": "1000",
"consensus_params": null,
"validators": [{
"pub_key":{"type":"tendermint/PubKeyEd25519","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},
"power":"10",
"name":""
}],
"app_hash":"",
"app_state":{"account_owner": "Bob"}
}`,
) )
_, err := GenesisDocFromJSON(genDocBytes) _, err := GenesisDocFromJSON(genDocBytes)
assert.NoError(t, err, "expected no error for good genDoc json") assert.NoError(t, err, "expected no error for good genDoc json")
@ -133,9 +142,7 @@ func TestGenesisSaveAs(t *testing.T) {
// load // load
genDoc2, err := GenesisDocFromFile(tmpfile.Name()) genDoc2, err := GenesisDocFromFile(tmpfile.Name())
require.NoError(t, err) require.NoError(t, err)
// fails to unknown reason
// assert.EqualValues(t, genDoc2, genDoc)
assert.EqualValues(t, genDoc2, genDoc)
assert.Equal(t, genDoc2.Validators, genDoc.Validators) assert.Equal(t, genDoc2.Validators, genDoc.Validators)
} }
@ -149,7 +156,9 @@ func randomGenesisDoc() *GenesisDoc {
return &GenesisDoc{ return &GenesisDoc{
GenesisTime: tmtime.Now(), GenesisTime: tmtime.Now(),
ChainID: "abc", ChainID: "abc",
InitialHeight: 1000,
Validators: []GenesisValidator{{pubkey.Address(), pubkey, 10, "myval"}}, Validators: []GenesisValidator{{pubkey.Address(), pubkey, 10, "myval"}},
ConsensusParams: DefaultConsensusParams(), ConsensusParams: DefaultConsensusParams(),
AppHash: []byte{1, 2, 3},
} }
} }

Loading…
Cancel
Save