From 29bfcb0a31da9647c5ff057cf25850a23a0d45d6 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 11 Sep 2017 15:45:12 -0400 Subject: [PATCH 01/10] minor comments/changes --- blockchain/pool.go | 2 +- blockchain/reactor.go | 2 +- types/genesis.go | 5 ----- types/priv_validator.go | 1 + 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/blockchain/pool.go b/blockchain/pool.go index e1288c9f..924880c0 100644 --- a/blockchain/pool.go +++ b/blockchain/pool.go @@ -352,7 +352,7 @@ func (peer *bpPeer) setLogger(l log.Logger) { func (peer *bpPeer) resetMonitor() { peer.recvMonitor = flow.New(time.Second, time.Second*40) - var initialValue = float64(minRecvRate) * math.E + initialValue := float64(minRecvRate) * math.E peer.recvMonitor.SetREMA(initialValue) } diff --git a/blockchain/reactor.go b/blockchain/reactor.go index efa6e2f0..e4b63ca2 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -28,7 +28,7 @@ const ( statusUpdateIntervalSeconds = 10 // check if we should switch to consensus reactor switchToConsensusIntervalSeconds = 1 - maxBlockchainResponseSize = types.MaxBlockSize + 2 + maxBlockchainResponseSize = types.MaxBlockSize + 2 // TODO ) type consensusReactor interface { diff --git a/types/genesis.go b/types/genesis.go index 23b14c9e..17078b6f 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -12,11 +12,6 @@ import ( cmn "github.com/tendermint/tmlibs/common" ) -//------------------------------------------------------------ -// we store the gendoc in the db - -var GenDocKey = []byte("GenDocKey") - //------------------------------------------------------------ // core types for a genesis definition diff --git a/types/priv_validator.go b/types/priv_validator.go index b96e988d..3e84e7f3 100644 --- a/types/priv_validator.go +++ b/types/priv_validator.go @@ -15,6 +15,7 @@ import ( "github.com/tendermint/tmlibs/log" ) +// TODO: type ? const ( stepNone = 0 // Used to distinguish the initial state stepPropose = 1 From 1f3e4d2d9ac42c5da8ec18bebb0284e88fceaf62 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 11 Sep 2017 16:28:00 -0400 Subject: [PATCH 02/10] move PartSetSize out of the config, into ConsensusParams --- blockchain/reactor.go | 15 ++++++++++----- config/config.go | 7 ------- config/consensus.go | 27 +++++++++++++++++++++++++++ consensus/replay_test.go | 17 ++++++++--------- consensus/state.go | 6 ++++-- consensus/state_test.go | 14 +++++++------- types/block.go | 5 ----- types/genesis.go | 29 +++++++++++++++++++++-------- 8 files changed, 77 insertions(+), 43 deletions(-) create mode 100644 config/consensus.go diff --git a/blockchain/reactor.go b/blockchain/reactor.go index e4b63ca2..fa3c7079 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -28,7 +28,6 @@ const ( statusUpdateIntervalSeconds = 10 // check if we should switch to consensus reactor switchToConsensusIntervalSeconds = 1 - maxBlockchainResponseSize = types.MaxBlockSize + 2 // TODO ) type consensusReactor interface { @@ -124,7 +123,7 @@ func (bcR *BlockchainReactor) RemovePeer(peer p2p.Peer, reason interface{}) { // Receive implements Reactor by handling 4 types of messages (look below). func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) { - _, msg, err := DecodeMessage(msgBytes) + _, msg, err := DecodeMessage(msgBytes, bcR.maxMsgSize()) if err != nil { bcR.Logger.Error("Error decoding message", "err", err) return @@ -163,6 +162,12 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) } } +// maxMsgSize returns the maximum allowable size of a +// message on the blockchain reactor. +func (bcR *BlockchainReactor) maxMsgSize() int { + return bcR.state.GenesisDoc.ConsensusParams.MaxBlockSizeBytes + 2 +} + // Handle messages from the poolReactor telling the reactor what to do. // NOTE: Don't sleep in the FOR_LOOP or otherwise slow it down! // (Except for the SYNC_LOOP, which is the primary purpose and must be synchronous.) @@ -221,7 +226,7 @@ FOR_LOOP: // We need both to sync the first block. break SYNC_LOOP } - firstParts := first.MakePartSet(types.DefaultBlockPartSize) + firstParts := first.MakePartSet(bcR.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes) firstPartsHeader := firstParts.Header() // Finally, verify the first block using the second's commit // NOTE: we can probably make this more efficient, but note that calling @@ -290,11 +295,11 @@ var _ = wire.RegisterInterface( // DecodeMessage decodes BlockchainMessage. // TODO: ensure that bz is completely read. -func DecodeMessage(bz []byte) (msgType byte, msg BlockchainMessage, err error) { +func DecodeMessage(bz []byte, maxSize int) (msgType byte, msg BlockchainMessage, err error) { msgType = bz[0] n := int(0) r := bytes.NewReader(bz) - msg = wire.ReadBinary(struct{ BlockchainMessage }{}, r, maxBlockchainResponseSize, &n, &err).(struct{ BlockchainMessage }).BlockchainMessage + msg = wire.ReadBinary(struct{ BlockchainMessage }{}, r, maxSize, &n, &err).(struct{ BlockchainMessage }).BlockchainMessage if err != nil && n != len(bz) { err = errors.New("DecodeMessage() had bytes left over") } diff --git a/config/config.go b/config/config.go index ec1f85ed..23da4f40 100644 --- a/config/config.go +++ b/config/config.go @@ -4,8 +4,6 @@ import ( "fmt" "path/filepath" "time" - - "github.com/tendermint/tendermint/types" // TODO: remove ) // Config defines the top level configuration for a Tendermint node @@ -320,10 +318,6 @@ type ConsensusConfig struct { CreateEmptyBlocks bool `mapstructure:"create_empty_blocks"` CreateEmptyBlocksInterval int `mapstructure:"create_empty_blocks_interval"` - // TODO: This probably shouldn't be exposed but it makes it - // easy to write tests for the wal/replay - BlockPartSize int `mapstructure:"block_part_size"` - // Reactor sleep duration parameters are in ms PeerGossipSleepDuration int `mapstructure:"peer_gossip_sleep_duration"` PeerQueryMaj23SleepDuration int `mapstructure:"peer_query_maj23_sleep_duration"` @@ -386,7 +380,6 @@ func DefaultConsensusConfig() *ConsensusConfig { MaxBlockSizeBytes: 1, // TODO CreateEmptyBlocks: true, CreateEmptyBlocksInterval: 0, - BlockPartSize: types.DefaultBlockPartSize, // TODO: we shouldnt be importing types PeerGossipSleepDuration: 100, PeerQueryMaj23SleepDuration: 2000, } diff --git a/config/consensus.go b/config/consensus.go new file mode 100644 index 00000000..5b10911d --- /dev/null +++ b/config/consensus.go @@ -0,0 +1,27 @@ +package config + +import ( + "fmt" +) + +type ConsensusParams struct { + MaxBlockSizeBytes int `json:"max_block_size_bytes"` + BlockPartSizeBytes int `json:"block_part_size_bytes"` +} + +func DefaultConsensusParams() *ConsensusParams { + return &ConsensusParams{ + MaxBlockSizeBytes: 22020096, // 21MB + BlockPartSizeBytes: 65536, // 64kB, + } +} + +func (params *ConsensusParams) Validate() error { + if params.MaxBlockSizeBytes <= 0 { + return fmt.Errorf("MaxBlockSizeBytes must be greater than 0. Got %d", params.MaxBlockSizeBytes) + } + if params.BlockPartSizeBytes <= 0 { + return fmt.Errorf("BlockPartSizeBytes must be greater than 0. Got %d", params.BlockPartSizeBytes) + } + return nil +} diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 78cdaf7b..179e8696 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -267,8 +267,6 @@ func testReplayCrashBeforeWriteVote(t *testing.T, thisCase *testCase, lineNum in var ( NUM_BLOCKS = 6 // number of blocks in the test_data/many_blocks.cswal mempool = types.MockMempool{} - - testPartSize int ) //--------------------------------------- @@ -320,7 +318,6 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) { config.Consensus.SetWalFile(walFile) privVal := types.LoadPrivValidator(config.PrivValidatorFile()) - testPartSize = config.Consensus.BlockPartSize wal, err := NewWAL(walFile, false) if err != nil { @@ -384,6 +381,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) { } func applyBlock(st *sm.State, blk *types.Block, proxyApp proxy.AppConns) { + testPartSize := st.GenesisDoc.ConsensusParams.BlockPartSizeBytes err := st.ApplyBlock(nil, proxyApp.Consensus(), blk, blk.MakePartSet(testPartSize).Header(), mempool) if err != nil { panic(err) @@ -503,7 +501,7 @@ func makeBlockchainFromWAL(wal *WAL) ([]*types.Block, []*types.Commit, error) { // if its not the first one, we have a full block if blockParts != nil { var n int - block := wire.ReadBinary(&types.Block{}, blockParts.GetReader(), types.MaxBlockSize, &n, &err).(*types.Block) + block := wire.ReadBinary(&types.Block{}, blockParts.GetReader(), 0, &n, &err).(*types.Block) blocks = append(blocks, block) } blockParts = types.NewPartSetFromHeader(*p) @@ -524,7 +522,7 @@ func makeBlockchainFromWAL(wal *WAL) ([]*types.Block, []*types.Commit, error) { } // grab the last block too var n int - block := wire.ReadBinary(&types.Block{}, blockParts.GetReader(), types.MaxBlockSize, &n, &err).(*types.Block) + block := wire.ReadBinary(&types.Block{}, blockParts.GetReader(), 0, &n, &err).(*types.Block) blocks = append(blocks, block) return blocks, commits, nil } @@ -563,7 +561,7 @@ func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBl state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile()) state.SetLogger(log.TestingLogger().With("module", "state")) - store := NewMockBlockStore(config) + store := NewMockBlockStore(config, state.GenesisDoc.ConsensusParams) return state, store } @@ -572,13 +570,14 @@ func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBl type mockBlockStore struct { config *cfg.Config + params *cfg.ConsensusParams chain []*types.Block commits []*types.Commit } // TODO: NewBlockStore(db.NewMemDB) ... -func NewMockBlockStore(config *cfg.Config) *mockBlockStore { - return &mockBlockStore{config, nil, nil} +func NewMockBlockStore(config *cfg.Config, params *cfg.ConsensusParams) *mockBlockStore { + return &mockBlockStore{config, params, nil, nil} } func (bs *mockBlockStore) Height() int { return len(bs.chain) } @@ -586,7 +585,7 @@ func (bs *mockBlockStore) LoadBlock(height int) *types.Block { return bs.chain[h func (bs *mockBlockStore) LoadBlockMeta(height int) *types.BlockMeta { block := bs.chain[height-1] return &types.BlockMeta{ - BlockID: types.BlockID{block.Hash(), block.MakePartSet(bs.config.Consensus.BlockPartSize).Header()}, + BlockID: types.BlockID{block.Hash(), block.MakePartSet(bs.params.BlockPartSizeBytes).Header()}, Header: block.Header, } } diff --git a/consensus/state.go b/consensus/state.go index 2523aac6..8a19a052 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -983,7 +983,8 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts txs := cs.mempool.Reap(cs.config.MaxBlockSizeTxs) return types.MakeBlock(cs.Height, cs.state.ChainID, txs, commit, - cs.state.LastBlockID, cs.state.Validators.Hash(), cs.state.AppHash, cs.config.BlockPartSize) + cs.state.LastBlockID, cs.state.Validators.Hash(), + cs.state.AppHash, cs.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes) } // Enter: `timeoutPropose` after entering Propose. @@ -1417,7 +1418,8 @@ func (cs *ConsensusState) addProposalBlockPart(height int, part *types.Part, ver // Added and completed! var n int var err error - cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), types.MaxBlockSize, &n, &err).(*types.Block) + cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), + cs.state.GenesisDoc.ConsensusParams.MaxBlockSizeBytes, &n, &err).(*types.Block) // NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash()) if cs.Step == RoundStepPropose && cs.isProposalComplete() { diff --git a/consensus/state_test.go b/consensus/state_test.go index 81ef016b..6f804fcb 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -180,7 +180,7 @@ func TestBadProposal(t *testing.T) { height, round := cs1.Height, cs1.Round vs2 := vss[1] - partSize := config.Consensus.BlockPartSize + partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1) @@ -327,7 +327,7 @@ func TestLockNoPOL(t *testing.T) { vs2 := vss[1] height := cs1.Height - partSize := config.Consensus.BlockPartSize + partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) @@ -493,7 +493,7 @@ func TestLockPOLRelock(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := config.Consensus.BlockPartSize + partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) @@ -608,7 +608,7 @@ func TestLockPOLUnlock(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := config.Consensus.BlockPartSize + partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) @@ -703,7 +703,7 @@ func TestLockPOLSafety1(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := config.Consensus.BlockPartSize + partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) @@ -824,7 +824,7 @@ func TestLockPOLSafety2(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := config.Consensus.BlockPartSize + partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) @@ -999,7 +999,7 @@ func TestHalt1(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := config.Consensus.BlockPartSize + partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) diff --git a/types/block.go b/types/block.go index fee62e98..c8cdf81a 100644 --- a/types/block.go +++ b/types/block.go @@ -14,11 +14,6 @@ import ( "github.com/tendermint/tmlibs/merkle" ) -const ( - MaxBlockSize = 22020096 // 21MB TODO make it configurable - DefaultBlockPartSize = 65536 // 64kB TODO: put part size in parts header? -) - // Block defines the atomic unit of a Tendermint blockchain type Block struct { *Header `json:"header"` diff --git a/types/genesis.go b/types/genesis.go index 17078b6f..b7762c57 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -10,6 +10,8 @@ import ( "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire/data" cmn "github.com/tendermint/tmlibs/common" + + cfg "github.com/tendermint/tendermint/config" ) //------------------------------------------------------------ @@ -24,10 +26,11 @@ type GenesisValidator struct { // GenesisDoc defines the initial conditions for a tendermint blockchain, in particular its validator set. type GenesisDoc struct { - GenesisTime time.Time `json:"genesis_time"` - ChainID string `json:"chain_id"` - Validators []GenesisValidator `json:"validators"` - AppHash data.Bytes `json:"app_hash"` + GenesisTime time.Time `json:"genesis_time"` + ChainID string `json:"chain_id"` + ConsensusParams *cfg.ConsensusParams `json:"consensus_params"` + Validators []GenesisValidator `json:"validators"` + AppHash data.Bytes `json:"app_hash"` } // SaveAs is a utility method for saving GenensisDoc as a JSON file. @@ -56,6 +59,19 @@ func (genDoc *GenesisDoc) ValidatorHash() []byte { func GenesisDocFromJSON(jsonBlob []byte) (*GenesisDoc, error) { genDoc := GenesisDoc{} err := json.Unmarshal(jsonBlob, &genDoc) + + // validate genesis + if genDoc.ChainID == "" { + return nil, errors.Errorf("Genesis doc must include non-empty chain_id") + } + if genDoc.ConsensusParams == nil { + genDoc.ConsensusParams = cfg.DefaultConsensusParams() + } else { + if err := genDoc.ConsensusParams.Validate(); err != nil { + return nil, err + } + } + return &genDoc, err } @@ -67,10 +83,7 @@ func GenesisDocFromFile(genDocFile string) (*GenesisDoc, error) { } genDoc, err := GenesisDocFromJSON(jsonBlob) if err != nil { - return nil, errors.Wrap(err, "Error reading GenesisDoc") - } - if genDoc.ChainID == "" { - return nil, errors.Errorf("Genesis doc %v must include non-empty chain_id", genDocFile) + return nil, errors.Wrap(err, cmn.Fmt("Error reading GenesisDoc at %v", genDocFile)) } return genDoc, nil } From 14abdd57f3f8091d9e5855dc0c6e27f6973284d0 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 11 Sep 2017 16:48:41 -0400 Subject: [PATCH 03/10] genDoc.ValidateAndComplete --- state/state.go | 9 +++------ types/genesis.go | 42 ++++++++++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/state/state.go b/state/state.go index 7e22e04d..4e0fa75b 100644 --- a/state/state.go +++ b/state/state.go @@ -324,12 +324,9 @@ func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) *State { // // Used in tests. func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State { - if len(genDoc.Validators) == 0 { - cmn.Exit(cmn.Fmt("The genesis file has no validators")) - } - - if genDoc.GenesisTime.IsZero() { - genDoc.GenesisTime = time.Now() + err := genDoc.ValidateAndComplete() + if err != nil { + cmn.Exit(cmn.Fmt("Error in genesis file: %v", err)) } // Make validators slice diff --git a/types/genesis.go b/types/genesis.go index b7762c57..79bf63c8 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -52,6 +52,33 @@ func (genDoc *GenesisDoc) ValidatorHash() []byte { return vset.Hash() } +// ValidateAndComplete checks that all necessary fields are present +// and fills in defaults for optional fields left empty +func (genDoc *GenesisDoc) ValidateAndComplete() error { + + if genDoc.ChainID == "" { + return errors.Errorf("Genesis doc must include non-empty chain_id") + } + + if genDoc.ConsensusParams == nil { + genDoc.ConsensusParams = cfg.DefaultConsensusParams() + } else { + if err := genDoc.ConsensusParams.Validate(); err != nil { + return err + } + } + + if len(genDoc.Validators) == 0 { + return errors.Errorf("The genesis file must have at least one validator") + } + + if genDoc.GenesisTime.IsZero() { + genDoc.GenesisTime = time.Now() + } + + return nil +} + //------------------------------------------------------------ // Make genesis state from file @@ -59,17 +86,12 @@ func (genDoc *GenesisDoc) ValidatorHash() []byte { func GenesisDocFromJSON(jsonBlob []byte) (*GenesisDoc, error) { genDoc := GenesisDoc{} err := json.Unmarshal(jsonBlob, &genDoc) - - // validate genesis - if genDoc.ChainID == "" { - return nil, errors.Errorf("Genesis doc must include non-empty chain_id") + if err != nil { + return nil, err } - if genDoc.ConsensusParams == nil { - genDoc.ConsensusParams = cfg.DefaultConsensusParams() - } else { - if err := genDoc.ConsensusParams.Validate(); err != nil { - return nil, err - } + + if err := genDoc.ValidateAndComplete(); err != nil { + return nil, err } return &genDoc, err From 2b6db268cfb1cacfe8fb70347f68a8622c87fb50 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 12 Sep 2017 15:20:19 -0400 Subject: [PATCH 04/10] genesis json tests and mv ConsensusParams to types --- blockchain/reactor.go | 4 +- config/consensus.go | 27 -------------- consensus/replay_test.go | 8 ++-- consensus/state.go | 4 +- consensus/state_test.go | 14 +++---- state/state.go | 28 ++++++++------ types/genesis.go | 14 +++---- types/genesis_test.go | 79 ++++++++++++++++++++++++++++++++++++++++ types/params.go | 32 ++++++++++++++++ 9 files changed, 149 insertions(+), 61 deletions(-) delete mode 100644 config/consensus.go create mode 100644 types/genesis_test.go create mode 100644 types/params.go diff --git a/blockchain/reactor.go b/blockchain/reactor.go index fa3c7079..fccfcdf8 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -165,7 +165,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) // maxMsgSize returns the maximum allowable size of a // message on the blockchain reactor. func (bcR *BlockchainReactor) maxMsgSize() int { - return bcR.state.GenesisDoc.ConsensusParams.MaxBlockSizeBytes + 2 + return bcR.state.Params().MaxBlockSizeBytes + 2 } // Handle messages from the poolReactor telling the reactor what to do. @@ -226,7 +226,7 @@ FOR_LOOP: // We need both to sync the first block. break SYNC_LOOP } - firstParts := first.MakePartSet(bcR.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes) + firstParts := first.MakePartSet(bcR.state.Params().BlockPartSizeBytes) firstPartsHeader := firstParts.Header() // Finally, verify the first block using the second's commit // NOTE: we can probably make this more efficient, but note that calling diff --git a/config/consensus.go b/config/consensus.go deleted file mode 100644 index 5b10911d..00000000 --- a/config/consensus.go +++ /dev/null @@ -1,27 +0,0 @@ -package config - -import ( - "fmt" -) - -type ConsensusParams struct { - MaxBlockSizeBytes int `json:"max_block_size_bytes"` - BlockPartSizeBytes int `json:"block_part_size_bytes"` -} - -func DefaultConsensusParams() *ConsensusParams { - return &ConsensusParams{ - MaxBlockSizeBytes: 22020096, // 21MB - BlockPartSizeBytes: 65536, // 64kB, - } -} - -func (params *ConsensusParams) Validate() error { - if params.MaxBlockSizeBytes <= 0 { - return fmt.Errorf("MaxBlockSizeBytes must be greater than 0. Got %d", params.MaxBlockSizeBytes) - } - if params.BlockPartSizeBytes <= 0 { - return fmt.Errorf("BlockPartSizeBytes must be greater than 0. Got %d", params.BlockPartSizeBytes) - } - return nil -} diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 179e8696..3fa88517 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -381,7 +381,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) { } func applyBlock(st *sm.State, blk *types.Block, proxyApp proxy.AppConns) { - testPartSize := st.GenesisDoc.ConsensusParams.BlockPartSizeBytes + testPartSize := st.Params().BlockPartSizeBytes err := st.ApplyBlock(nil, proxyApp.Consensus(), blk, blk.MakePartSet(testPartSize).Header(), mempool) if err != nil { panic(err) @@ -561,7 +561,7 @@ func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBl state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile()) state.SetLogger(log.TestingLogger().With("module", "state")) - store := NewMockBlockStore(config, state.GenesisDoc.ConsensusParams) + store := NewMockBlockStore(config, state.Params()) return state, store } @@ -570,13 +570,13 @@ func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBl type mockBlockStore struct { config *cfg.Config - params *cfg.ConsensusParams + params *types.ConsensusParams chain []*types.Block commits []*types.Commit } // TODO: NewBlockStore(db.NewMemDB) ... -func NewMockBlockStore(config *cfg.Config, params *cfg.ConsensusParams) *mockBlockStore { +func NewMockBlockStore(config *cfg.Config, params *types.ConsensusParams) *mockBlockStore { return &mockBlockStore{config, params, nil, nil} } diff --git a/consensus/state.go b/consensus/state.go index 8a19a052..1a5b26e6 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -984,7 +984,7 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts return types.MakeBlock(cs.Height, cs.state.ChainID, txs, commit, cs.state.LastBlockID, cs.state.Validators.Hash(), - cs.state.AppHash, cs.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes) + cs.state.AppHash, cs.state.Params().BlockPartSizeBytes) } // Enter: `timeoutPropose` after entering Propose. @@ -1419,7 +1419,7 @@ func (cs *ConsensusState) addProposalBlockPart(height int, part *types.Part, ver var n int var err error cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), - cs.state.GenesisDoc.ConsensusParams.MaxBlockSizeBytes, &n, &err).(*types.Block) + cs.state.Params().MaxBlockSizeBytes, &n, &err).(*types.Block) // NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash()) if cs.Step == RoundStepPropose && cs.isProposalComplete() { diff --git a/consensus/state_test.go b/consensus/state_test.go index 6f804fcb..9ae05203 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -180,7 +180,7 @@ func TestBadProposal(t *testing.T) { height, round := cs1.Height, cs1.Round vs2 := vss[1] - partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes + partSize := cs1.state.Params().BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1) @@ -327,7 +327,7 @@ func TestLockNoPOL(t *testing.T) { vs2 := vss[1] height := cs1.Height - partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes + partSize := cs1.state.Params().BlockPartSizeBytes timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) @@ -493,7 +493,7 @@ func TestLockPOLRelock(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes + partSize := cs1.state.Params().BlockPartSizeBytes timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) @@ -608,7 +608,7 @@ func TestLockPOLUnlock(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes + partSize := cs1.state.Params().BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) @@ -703,7 +703,7 @@ func TestLockPOLSafety1(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes + partSize := cs1.state.Params().BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) @@ -824,7 +824,7 @@ func TestLockPOLSafety2(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes + partSize := cs1.state.Params().BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) @@ -999,7 +999,7 @@ func TestHalt1(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes + partSize := cs1.state.Params().BlockPartSizeBytes proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) diff --git a/state/state.go b/state/state.go index 4e0fa75b..0ea15aca 100644 --- a/state/state.go +++ b/state/state.go @@ -65,6 +65,19 @@ type State struct { logger log.Logger } +// GetState loads the most recent state from the database, +// or creates a new one from the given genesisFile and persists the result +// to the database. +func GetState(stateDB dbm.DB, genesisFile string) *State { + state := LoadState(stateDB) + if state == nil { + state = MakeGenesisStateFromFile(stateDB, genesisFile) + state.Save() + } + + return state +} + // LoadState loads the State from the database. func LoadState(db dbm.DB) *State { return loadState(db, stateKey) @@ -248,17 +261,10 @@ func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) { return s.LastValidators, s.Validators } -// GetState loads the most recent state from the database, -// or creates a new one from the given genesisFile and persists the result -// to the database. -func GetState(stateDB dbm.DB, genesisFile string) *State { - state := LoadState(stateDB) - if state == nil { - state = MakeGenesisStateFromFile(stateDB, genesisFile) - state.Save() - } - - return state +// Params returns the consensus parameters used for +// validating blocks +func (s *State) Params() *types.ConsensusParams { + return s.GenesisDoc.ConsensusParams } //------------------------------------------------------------------------ diff --git a/types/genesis.go b/types/genesis.go index 79bf63c8..822a4e16 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -10,8 +10,6 @@ import ( "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire/data" cmn "github.com/tendermint/tmlibs/common" - - cfg "github.com/tendermint/tendermint/config" ) //------------------------------------------------------------ @@ -26,11 +24,11 @@ type GenesisValidator struct { // GenesisDoc defines the initial conditions for a tendermint blockchain, in particular its validator set. type GenesisDoc struct { - GenesisTime time.Time `json:"genesis_time"` - ChainID string `json:"chain_id"` - ConsensusParams *cfg.ConsensusParams `json:"consensus_params"` - Validators []GenesisValidator `json:"validators"` - AppHash data.Bytes `json:"app_hash"` + GenesisTime time.Time `json:"genesis_time"` + ChainID string `json:"chain_id"` + ConsensusParams *ConsensusParams `json:"consensus_params"` + Validators []GenesisValidator `json:"validators"` + AppHash data.Bytes `json:"app_hash"` } // SaveAs is a utility method for saving GenensisDoc as a JSON file. @@ -61,7 +59,7 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error { } if genDoc.ConsensusParams == nil { - genDoc.ConsensusParams = cfg.DefaultConsensusParams() + genDoc.ConsensusParams = DefaultConsensusParams() } else { if err := genDoc.ConsensusParams.Validate(); err != nil { return err diff --git a/types/genesis_test.go b/types/genesis_test.go new file mode 100644 index 00000000..9743a961 --- /dev/null +++ b/types/genesis_test.go @@ -0,0 +1,79 @@ +package types + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + crypto "github.com/tendermint/go-crypto" +) + +func TestGenesis(t *testing.T) { + + // test some bad ones from raw json + testCases := [][]byte{ + []byte{}, // empty + []byte{1, 1, 1, 1, 1}, // junk + []byte(`{}`), // empty + []byte(`{"chain_id": "mychain"}`), // missing validators + []byte(`{"validators": [{"data":abcd}`), // missing validators + []byte(`{"validators":[{"pub_key": + {"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"}, + "amount":10,"name":""}]}`), // missing chain_id + } + + for _, testCase := range testCases { + _, err := GenesisDocFromJSON(testCase) + assert.NotNil(t, err, "expected error for empty genDoc json") + } + + // test a good one by raw json + genDocBytes := []byte(`{"genesis_time":"0001-01-01T00:00:00Z","chain_id":"test-chain-QDKdJr","consensus_params":null,"validators":[{"pub_key":{"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"},"amount":10,"name":""}],"app_hash":""}`) + _, err := GenesisDocFromJSON(genDocBytes) + assert.Nil(t, err, "expected no error for good genDoc json") + + // create a base gendoc from struct + baseGenDoc := &GenesisDoc{ + ChainID: "abc", + Validators: []GenesisValidator{{crypto.GenPrivKeyEd25519().PubKey(), 10, "myval"}}, + } + genDocBytes, err = json.Marshal(baseGenDoc) + assert.Nil(t, err, "error marshalling genDoc") + + // test base gendoc and check consensus params were filled + genDoc, err := GenesisDocFromJSON(genDocBytes) + assert.Nil(t, err, "expected no error for valid genDoc json") + assert.NotNil(t, genDoc.ConsensusParams, "expected consensus params to be filled in") + + // create json with consensus params filled + genDocBytes, err = json.Marshal(genDoc) + assert.Nil(t, err, "error marshalling genDoc") + genDoc, err = GenesisDocFromJSON(genDocBytes) + assert.Nil(t, err, "expected no error for valid genDoc json") + + // test with invalid consensus params + genDoc.ConsensusParams.MaxBlockSizeBytes = 0 + genDocBytes, err = json.Marshal(genDoc) + assert.Nil(t, err, "error marshalling genDoc") + genDoc, err = GenesisDocFromJSON(genDocBytes) + assert.NotNil(t, err, "expected error for genDoc json with block size of 0") +} + +func TestConsensusParams(t *testing.T) { + testCases := []struct { + params *ConsensusParams + valid bool + }{ + {&ConsensusParams{1, 1}, true}, + {&ConsensusParams{1, 0}, false}, + {&ConsensusParams{0, 1}, false}, + {&ConsensusParams{0, 0}, false}, + } + for _, testCase := range testCases { + if testCase.valid { + assert.Nil(t, testCase.params.Validate(), "expected no error for valid params") + } else { + assert.NotNil(t, testCase.params.Validate(), "expected error for non valid params") + } + } +} diff --git a/types/params.go b/types/params.go new file mode 100644 index 00000000..cff9ae3d --- /dev/null +++ b/types/params.go @@ -0,0 +1,32 @@ +package types + +import ( + "github.com/pkg/errors" +) + +// ConsensusParams contains consensus critical parameters +// that determine the validity of blocks. +type ConsensusParams struct { + MaxBlockSizeBytes int `json:"max_block_size_bytes"` + BlockPartSizeBytes int `json:"block_part_size_bytes"` +} + +// DefaultConsensusParams returns a default ConsensusParams. +func DefaultConsensusParams() *ConsensusParams { + return &ConsensusParams{ + MaxBlockSizeBytes: 22020096, // 21MB + BlockPartSizeBytes: 65536, // 64kB, + } +} + +// Validate validates the ConsensusParams to ensure all values +// are within their allowed limits, and returns an error if they are not. +func (params *ConsensusParams) Validate() error { + if params.MaxBlockSizeBytes <= 0 { + return errors.Errorf("MaxBlockSizeBytes must be greater than 0. Got %d", params.MaxBlockSizeBytes) + } + if params.BlockPartSizeBytes <= 0 { + return errors.Errorf("BlockPartSizeBytes must be greater than 0. Got %d", params.BlockPartSizeBytes) + } + return nil +} From d343560108e247a91fb05a3bbb082c1946de62df Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 15 Sep 2017 23:52:09 -0400 Subject: [PATCH 05/10] adr: add 005 consensus params --- docs/architecture/adr-005-consensus-params.md | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 docs/architecture/adr-005-consensus-params.md diff --git a/docs/architecture/adr-005-consensus-params.md b/docs/architecture/adr-005-consensus-params.md new file mode 100644 index 00000000..6f43fe7d --- /dev/null +++ b/docs/architecture/adr-005-consensus-params.md @@ -0,0 +1,77 @@ +# ADR 005: Consensus Params + +## Context + +Consensus critical parameters controlling blockchain capacity have until now been hard coded, loaded from a local config, or neglected. +Since they may be need to be different in different networks, and potentially to evolve over time within +networks, we seek to initialize them in a genesis file, and expose them through the ABCI. + +While we have some specific parameters now, like maximum block and transaction size, we expect to have more in the future, +such as a period over which evidence is valid, or the frequency of checkpoints. + +## Decision + +### ConsensusParams + +A new `ConsensusParams` is optionally included in the `genesis.json` file, +and loaded into the `State`. Any items not included are set to their default value. +A value of 0 is undefined (see ABCI, below). A value of -1 is used to indicate the parameter does not apply. +No consensus critical parameters should ever be found in the `config.toml`. + +``` +type ConsensusParams struct { + BlockSizeParams + TxSizeParams + BlockGossipParams +} + +type BlockSizeParams struct { + BlockSizeBytes int + BlockSizeTxs int + BlockSizeGas int +} + +type TxSizeParams struct { + TxSizeBytes int + TxSizeGas int +} + +type BlockGossipParams struct { + BlockPartSizeBytes int +} +``` + +The `ConsensusParams` can evolve over time by adding new structs that cover different aspects of the consensus rules. + +### ABCI + +#### InitChain + +InitChain currently takes the initial validator set. It should be extended to also take the ConsensusParams. +In fact, it might as well just consume the whole Genesis. + +#### EndBlock + +The EndBlock response includes a `ConsensusParams`, which includes BlockSizeParams and TxSizeParams, but not BlockGossipParams. +Other param struct can be added to `ConsensusParams` in the future. +The `0` value is used to denote no change. +Any other value will update that parameter in the `State.ConsensusParams`, to be applied for the next block. +Tendermint should have hard-coded upper limits as sanity checks. + +## Status + +Proposed. + +## Consequences + +### Positive + +- Alternative capacity limits and consensus parameters can be specified without re-compiling the software. +- They can also change over time under the control of the application + +### Negative + +- More exposed parameters is more complexity +- Different rules at different heights in the blockchain complicates fast sync + +### Neutral From 3a03fe5a15e012d1fd2cf61cd8c8e44cdf109a62 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 16 Sep 2017 00:16:49 -0400 Subject: [PATCH 06/10] updated to match adr 005 --- blockchain/reactor.go | 2 +- consensus/state.go | 2 +- docs/architecture/adr-005-consensus-params.md | 24 +++++--- types/genesis_test.go | 19 ++++-- types/params.go | 60 ++++++++++++++++--- 5 files changed, 84 insertions(+), 23 deletions(-) diff --git a/blockchain/reactor.go b/blockchain/reactor.go index fccfcdf8..fb68aadd 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -165,7 +165,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) // maxMsgSize returns the maximum allowable size of a // message on the blockchain reactor. func (bcR *BlockchainReactor) maxMsgSize() int { - return bcR.state.Params().MaxBlockSizeBytes + 2 + return bcR.state.Params().BlockSizeParams.MaxBytes + 2 } // Handle messages from the poolReactor telling the reactor what to do. diff --git a/consensus/state.go b/consensus/state.go index 1a5b26e6..ac165620 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -1419,7 +1419,7 @@ func (cs *ConsensusState) addProposalBlockPart(height int, part *types.Part, ver var n int var err error cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), - cs.state.Params().MaxBlockSizeBytes, &n, &err).(*types.Block) + cs.state.Params().BlockSizeParams.MaxBytes, &n, &err).(*types.Block) // NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash()) if cs.Step == RoundStepPropose && cs.isProposalComplete() { diff --git a/docs/architecture/adr-005-consensus-params.md b/docs/architecture/adr-005-consensus-params.md index 6f43fe7d..678de42e 100644 --- a/docs/architecture/adr-005-consensus-params.md +++ b/docs/architecture/adr-005-consensus-params.md @@ -13,10 +13,12 @@ such as a period over which evidence is valid, or the frequency of checkpoints. ### ConsensusParams +No consensus critical parameters should ever be found in the `config.toml`. + A new `ConsensusParams` is optionally included in the `genesis.json` file, and loaded into the `State`. Any items not included are set to their default value. A value of 0 is undefined (see ABCI, below). A value of -1 is used to indicate the parameter does not apply. -No consensus critical parameters should ever be found in the `config.toml`. +The parameters are used to determine the validity of a block (and tx) via the union of all relevant parameters. ``` type ConsensusParams struct { @@ -26,14 +28,14 @@ type ConsensusParams struct { } type BlockSizeParams struct { - BlockSizeBytes int - BlockSizeTxs int - BlockSizeGas int + MaxBytes int + MaxTxs int + MaxGas int } type TxSizeParams struct { - TxSizeBytes int - TxSizeGas int + MaxBytes int + MaxGas int } type BlockGossipParams struct { @@ -43,12 +45,16 @@ type BlockGossipParams struct { The `ConsensusParams` can evolve over time by adding new structs that cover different aspects of the consensus rules. +The `BlockPartSizeBytes` and the `BlockSizeParams.MaxBytes` are enforced to be greater than 0. +The former because we need a part size, the latter so that we always have at least some sanity check over the size of blocks. + ### ABCI #### InitChain -InitChain currently takes the initial validator set. It should be extended to also take the ConsensusParams. -In fact, it might as well just consume the whole Genesis. +InitChain currently takes the initial validator set. It should be extended to also take parts of the ConsensusParams. +There is some case to be made for it to take the entire Genesis, except there may be things in the genesis, +like the BlockPartSize, that the app shouldn't really know about. #### EndBlock @@ -75,3 +81,5 @@ Proposed. - Different rules at different heights in the blockchain complicates fast sync ### Neutral + +- The TxSizeParams, which checks validity, may be in conflict with the config's `max_block_size_tx`, which determines proposal sizes diff --git a/types/genesis_test.go b/types/genesis_test.go index 9743a961..7d7731f1 100644 --- a/types/genesis_test.go +++ b/types/genesis_test.go @@ -52,22 +52,31 @@ func TestGenesis(t *testing.T) { assert.Nil(t, err, "expected no error for valid genDoc json") // test with invalid consensus params - genDoc.ConsensusParams.MaxBlockSizeBytes = 0 + genDoc.ConsensusParams.BlockSizeParams.MaxBytes = 0 genDocBytes, err = json.Marshal(genDoc) assert.Nil(t, err, "error marshalling genDoc") genDoc, err = GenesisDocFromJSON(genDocBytes) assert.NotNil(t, err, "expected error for genDoc json with block size of 0") } +func newConsensusParams(blockSize, partSize int) *ConsensusParams { + return &ConsensusParams{ + BlockSizeParams: &BlockSizeParams{MaxBytes: blockSize}, + BlockGossipParams: &BlockGossipParams{BlockPartSizeBytes: partSize}, + } + +} + func TestConsensusParams(t *testing.T) { + testCases := []struct { params *ConsensusParams valid bool }{ - {&ConsensusParams{1, 1}, true}, - {&ConsensusParams{1, 0}, false}, - {&ConsensusParams{0, 1}, false}, - {&ConsensusParams{0, 0}, false}, + {newConsensusParams(1, 1), true}, + {newConsensusParams(1, 0), false}, + {newConsensusParams(0, 1), false}, + {newConsensusParams(0, 0), false}, } for _, testCase := range testCases { if testCase.valid { diff --git a/types/params.go b/types/params.go index cff9ae3d..71ffe60c 100644 --- a/types/params.go +++ b/types/params.go @@ -7,26 +7,70 @@ import ( // ConsensusParams contains consensus critical parameters // that determine the validity of blocks. type ConsensusParams struct { - MaxBlockSizeBytes int `json:"max_block_size_bytes"` - BlockPartSizeBytes int `json:"block_part_size_bytes"` + *BlockSizeParams `json:"block_size_params"` + *TxSizeParams `json:"tx_size_params"` + *BlockGossipParams `json:"block_gossip_params"` +} + +// BlockSizeParams contain limits on the block size. +type BlockSizeParams struct { + MaxBytes int `json:"max_bytes"` // NOTE: must not be 0 + MaxTxs int `json:"max_txs"` + MaxGas int `json:"max_gas"` +} + +// TxSizeParams contain limits on the tx size. +type TxSizeParams struct { + MaxBytes int `json:"max_bytes"` + MaxGas int `json:"max_gas"` +} + +// BlockGossipParams determine consensus critical elements of how blocks are gossiped +type BlockGossipParams struct { + BlockPartSizeBytes int `json:"block_part_size_bytes"` // NOTE: must not be 0 } // DefaultConsensusParams returns a default ConsensusParams. func DefaultConsensusParams() *ConsensusParams { return &ConsensusParams{ - MaxBlockSizeBytes: 22020096, // 21MB - BlockPartSizeBytes: 65536, // 64kB, + DefaultBlockSizeParams(), + DefaultTxSizeParams(), + DefaultBlockGossipParams(), + } +} + +// DefaultBlockSizeParams returns a default BlockSizeParams. +func DefaultBlockSizeParams() *BlockSizeParams { + return &BlockSizeParams{ + MaxBytes: 22020096, // 21MB + MaxTxs: 100000, + MaxGas: -1, + } +} + +// DefaultTxSizeParams returns a default TxSizeParams. +func DefaultTxSizeParams() *TxSizeParams { + return &TxSizeParams{ + MaxBytes: 10240, // 10kB + MaxGas: -1, + } +} + +// DefaultBlockGossipParams returns a default BlockGossipParams. +func DefaultBlockGossipParams() *BlockGossipParams { + return &BlockGossipParams{ + BlockPartSizeBytes: 65536, // 64kB, } } // Validate validates the ConsensusParams to ensure all values // are within their allowed limits, and returns an error if they are not. func (params *ConsensusParams) Validate() error { - if params.MaxBlockSizeBytes <= 0 { - return errors.Errorf("MaxBlockSizeBytes must be greater than 0. Got %d", params.MaxBlockSizeBytes) + if params.BlockSizeParams.MaxBytes <= 0 { + return errors.Errorf("BlockSizeParams.MaxBytes must be greater than 0. Got %d", params.BlockSizeParams.MaxBytes) } - if params.BlockPartSizeBytes <= 0 { - return errors.Errorf("BlockPartSizeBytes must be greater than 0. Got %d", params.BlockPartSizeBytes) + if params.BlockGossipParams.BlockPartSizeBytes <= 0 { + return errors.Errorf("BlockGossipParams.BlockPartSizeBytes must be greater than 0. Got %d", params.BlockGossipParams.BlockPartSizeBytes) } return nil } From 715e74186ca89d147cdd75c26295d1f2ff0b4827 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 18 Sep 2017 17:00:09 -0400 Subject: [PATCH 07/10] fixes from review --- types/genesis_test.go | 31 ++++++++++++++++--------------- types/params.go | 11 +++++++++++ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/types/genesis_test.go b/types/genesis_test.go index 7d7731f1..75184e5a 100644 --- a/types/genesis_test.go +++ b/types/genesis_test.go @@ -12,11 +12,12 @@ func TestGenesis(t *testing.T) { // test some bad ones from raw json testCases := [][]byte{ - []byte{}, // empty - []byte{1, 1, 1, 1, 1}, // junk - []byte(`{}`), // empty - []byte(`{"chain_id": "mychain"}`), // missing validators - []byte(`{"validators": [{"data":abcd}`), // missing validators + []byte{}, // empty + []byte{1, 1, 1, 1, 1}, // junk + []byte(`{}`), // empty + []byte(`{"chain_id": "mychain"}`), // missing validators + []byte(`{"chain_id": "mychain", "validators": []`), // missing validators + []byte(`{"chain_id": "mychain", "validators": [{}]`), // missing validators []byte(`{"validators":[{"pub_key": {"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"}, "amount":10,"name":""}]}`), // missing chain_id @@ -24,13 +25,13 @@ func TestGenesis(t *testing.T) { for _, testCase := range testCases { _, err := GenesisDocFromJSON(testCase) - assert.NotNil(t, err, "expected error for empty genDoc json") + assert.Error(t, err, "expected error for empty genDoc json") } // test a good one by raw json genDocBytes := []byte(`{"genesis_time":"0001-01-01T00:00:00Z","chain_id":"test-chain-QDKdJr","consensus_params":null,"validators":[{"pub_key":{"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"},"amount":10,"name":""}],"app_hash":""}`) _, err := GenesisDocFromJSON(genDocBytes) - assert.Nil(t, err, "expected no error for good genDoc json") + assert.NoError(t, err, "expected no error for good genDoc json") // create a base gendoc from struct baseGenDoc := &GenesisDoc{ @@ -38,25 +39,25 @@ func TestGenesis(t *testing.T) { Validators: []GenesisValidator{{crypto.GenPrivKeyEd25519().PubKey(), 10, "myval"}}, } genDocBytes, err = json.Marshal(baseGenDoc) - assert.Nil(t, err, "error marshalling genDoc") + assert.NoError(t, err, "error marshalling genDoc") // test base gendoc and check consensus params were filled genDoc, err := GenesisDocFromJSON(genDocBytes) - assert.Nil(t, err, "expected no error for valid genDoc json") + assert.NoError(t, err, "expected no error for valid genDoc json") assert.NotNil(t, genDoc.ConsensusParams, "expected consensus params to be filled in") // create json with consensus params filled genDocBytes, err = json.Marshal(genDoc) - assert.Nil(t, err, "error marshalling genDoc") + assert.NoError(t, err, "error marshalling genDoc") genDoc, err = GenesisDocFromJSON(genDocBytes) - assert.Nil(t, err, "expected no error for valid genDoc json") + assert.NoError(t, err, "expected no error for valid genDoc json") // test with invalid consensus params genDoc.ConsensusParams.BlockSizeParams.MaxBytes = 0 genDocBytes, err = json.Marshal(genDoc) - assert.Nil(t, err, "error marshalling genDoc") + assert.NoError(t, err, "error marshalling genDoc") genDoc, err = GenesisDocFromJSON(genDocBytes) - assert.NotNil(t, err, "expected error for genDoc json with block size of 0") + assert.Error(t, err, "expected error for genDoc json with block size of 0") } func newConsensusParams(blockSize, partSize int) *ConsensusParams { @@ -80,9 +81,9 @@ func TestConsensusParams(t *testing.T) { } for _, testCase := range testCases { if testCase.valid { - assert.Nil(t, testCase.params.Validate(), "expected no error for valid params") + assert.NoError(t, testCase.params.Validate(), "expected no error for valid params") } else { - assert.NotNil(t, testCase.params.Validate(), "expected error for non valid params") + assert.Error(t, testCase.params.Validate(), "expected error for non valid params") } } } diff --git a/types/params.go b/types/params.go index 71ffe60c..b55ceb8c 100644 --- a/types/params.go +++ b/types/params.go @@ -4,6 +4,10 @@ import ( "github.com/pkg/errors" ) +const ( + maxBlockSizeBytes = 104857600 // 100MB +) + // ConsensusParams contains consensus critical parameters // that determine the validity of blocks. type ConsensusParams struct { @@ -66,11 +70,18 @@ func DefaultBlockGossipParams() *BlockGossipParams { // Validate validates the ConsensusParams to ensure all values // are within their allowed limits, and returns an error if they are not. func (params *ConsensusParams) Validate() error { + // ensure some values are greater than 0 if params.BlockSizeParams.MaxBytes <= 0 { return errors.Errorf("BlockSizeParams.MaxBytes must be greater than 0. Got %d", params.BlockSizeParams.MaxBytes) } if params.BlockGossipParams.BlockPartSizeBytes <= 0 { return errors.Errorf("BlockGossipParams.BlockPartSizeBytes must be greater than 0. Got %d", params.BlockGossipParams.BlockPartSizeBytes) } + + // ensure blocks aren't too big + if cp.BlockSizeParams.MaxBytes > maxBlockSizeBytes { + return errors.Errorf("BlockSizeParams.MaxBytes is too big. %d > %d", + cp.BlockSizeParams.MaxBytes, maxBlockSizeBytes) + } return nil } From 5feeb65cf0df559a3467a6a9d2f7271a94328178 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Sep 2017 14:34:36 -0400 Subject: [PATCH 08/10] dont use pointers for ConsensusParams --- consensus/replay_test.go | 4 ++-- state/state.go | 4 +++- types/genesis.go | 5 +++-- types/genesis_test.go | 10 +++++----- types/params.go | 26 +++++++++++++------------- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 3fa88517..03ca6c8d 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -570,13 +570,13 @@ func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBl type mockBlockStore struct { config *cfg.Config - params *types.ConsensusParams + params types.ConsensusParams chain []*types.Block commits []*types.Commit } // TODO: NewBlockStore(db.NewMemDB) ... -func NewMockBlockStore(config *cfg.Config, params *types.ConsensusParams) *mockBlockStore { +func NewMockBlockStore(config *cfg.Config, params types.ConsensusParams) *mockBlockStore { return &mockBlockStore{config, params, nil, nil} } diff --git a/state/state.go b/state/state.go index 0ea15aca..1374fcf4 100644 --- a/state/state.go +++ b/state/state.go @@ -263,7 +263,9 @@ func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) { // Params returns the consensus parameters used for // validating blocks -func (s *State) Params() *types.ConsensusParams { +func (s *State) Params() types.ConsensusParams { + // TODO: this should move into the State proper + // when we allow the app to change it return s.GenesisDoc.ConsensusParams } diff --git a/types/genesis.go b/types/genesis.go index 822a4e16..06b3d124 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -26,7 +26,7 @@ type GenesisValidator struct { type GenesisDoc struct { GenesisTime time.Time `json:"genesis_time"` ChainID string `json:"chain_id"` - ConsensusParams *ConsensusParams `json:"consensus_params"` + ConsensusParams ConsensusParams `json:"consensus_params"` Validators []GenesisValidator `json:"validators"` AppHash data.Bytes `json:"app_hash"` } @@ -58,7 +58,8 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error { return errors.Errorf("Genesis doc must include non-empty chain_id") } - if genDoc.ConsensusParams == nil { + var emptyParams ConsensusParams + if genDoc.ConsensusParams == emptyParams { genDoc.ConsensusParams = DefaultConsensusParams() } else { if err := genDoc.ConsensusParams.Validate(); err != nil { diff --git a/types/genesis_test.go b/types/genesis_test.go index 75184e5a..d06a70da 100644 --- a/types/genesis_test.go +++ b/types/genesis_test.go @@ -60,10 +60,10 @@ func TestGenesis(t *testing.T) { assert.Error(t, err, "expected error for genDoc json with block size of 0") } -func newConsensusParams(blockSize, partSize int) *ConsensusParams { - return &ConsensusParams{ - BlockSizeParams: &BlockSizeParams{MaxBytes: blockSize}, - BlockGossipParams: &BlockGossipParams{BlockPartSizeBytes: partSize}, +func newConsensusParams(blockSize, partSize int) ConsensusParams { + return ConsensusParams{ + BlockSizeParams: BlockSizeParams{MaxBytes: blockSize}, + BlockGossipParams: BlockGossipParams{BlockPartSizeBytes: partSize}, } } @@ -71,7 +71,7 @@ func newConsensusParams(blockSize, partSize int) *ConsensusParams { func TestConsensusParams(t *testing.T) { testCases := []struct { - params *ConsensusParams + params ConsensusParams valid bool }{ {newConsensusParams(1, 1), true}, diff --git a/types/params.go b/types/params.go index b55ceb8c..cd324219 100644 --- a/types/params.go +++ b/types/params.go @@ -11,9 +11,9 @@ const ( // ConsensusParams contains consensus critical parameters // that determine the validity of blocks. type ConsensusParams struct { - *BlockSizeParams `json:"block_size_params"` - *TxSizeParams `json:"tx_size_params"` - *BlockGossipParams `json:"block_gossip_params"` + BlockSizeParams `json:"block_size_params"` + TxSizeParams `json:"tx_size_params"` + BlockGossipParams `json:"block_gossip_params"` } // BlockSizeParams contain limits on the block size. @@ -35,8 +35,8 @@ type BlockGossipParams struct { } // DefaultConsensusParams returns a default ConsensusParams. -func DefaultConsensusParams() *ConsensusParams { - return &ConsensusParams{ +func DefaultConsensusParams() ConsensusParams { + return ConsensusParams{ DefaultBlockSizeParams(), DefaultTxSizeParams(), DefaultBlockGossipParams(), @@ -44,8 +44,8 @@ func DefaultConsensusParams() *ConsensusParams { } // DefaultBlockSizeParams returns a default BlockSizeParams. -func DefaultBlockSizeParams() *BlockSizeParams { - return &BlockSizeParams{ +func DefaultBlockSizeParams() BlockSizeParams { + return BlockSizeParams{ MaxBytes: 22020096, // 21MB MaxTxs: 100000, MaxGas: -1, @@ -53,16 +53,16 @@ func DefaultBlockSizeParams() *BlockSizeParams { } // DefaultTxSizeParams returns a default TxSizeParams. -func DefaultTxSizeParams() *TxSizeParams { - return &TxSizeParams{ +func DefaultTxSizeParams() TxSizeParams { + return TxSizeParams{ MaxBytes: 10240, // 10kB MaxGas: -1, } } // DefaultBlockGossipParams returns a default BlockGossipParams. -func DefaultBlockGossipParams() *BlockGossipParams { - return &BlockGossipParams{ +func DefaultBlockGossipParams() BlockGossipParams { + return BlockGossipParams{ BlockPartSizeBytes: 65536, // 64kB, } } @@ -79,9 +79,9 @@ func (params *ConsensusParams) Validate() error { } // ensure blocks aren't too big - if cp.BlockSizeParams.MaxBytes > maxBlockSizeBytes { + if params.BlockSizeParams.MaxBytes > maxBlockSizeBytes { return errors.Errorf("BlockSizeParams.MaxBytes is too big. %d > %d", - cp.BlockSizeParams.MaxBytes, maxBlockSizeBytes) + params.BlockSizeParams.MaxBytes, maxBlockSizeBytes) } return nil } From 3089bbf2b8c011d04e2c5a53d3444d3fbc46e6f2 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Sep 2017 14:37:34 -0400 Subject: [PATCH 09/10] Amount -> Power. Closes #166 --- cmd/tendermint/commands/init.go | 2 +- cmd/tendermint/commands/testnet.go | 4 ++-- config/toml.go | 2 +- consensus/common_test.go | 2 +- docs/specification/genesis.rst | 10 +++++----- docs/using-tendermint.rst | 6 +++--- rpc/client/rpc_test.go | 2 +- rpc/core/net.go | 2 +- state/state.go | 2 +- test/p2p/data/mach1/core/genesis.json | 8 ++++---- test/p2p/data/mach2/core/genesis.json | 8 ++++---- test/p2p/data/mach3/core/genesis.json | 8 ++++---- test/p2p/data/mach4/core/genesis.json | 8 ++++---- types/genesis.go | 10 ++++++++-- types/genesis_test.go | 4 ++-- 15 files changed, 42 insertions(+), 36 deletions(-) diff --git a/cmd/tendermint/commands/init.go b/cmd/tendermint/commands/init.go index cd16707c..ce900def 100644 --- a/cmd/tendermint/commands/init.go +++ b/cmd/tendermint/commands/init.go @@ -34,7 +34,7 @@ func initFiles(cmd *cobra.Command, args []string) { } genDoc.Validators = []types.GenesisValidator{types.GenesisValidator{ PubKey: privValidator.PubKey, - Amount: 10, + Power: 10, }} genDoc.SaveAs(genFile) diff --git a/cmd/tendermint/commands/testnet.go b/cmd/tendermint/commands/testnet.go index 58767eb0..315f3b49 100644 --- a/cmd/tendermint/commands/testnet.go +++ b/cmd/tendermint/commands/testnet.go @@ -7,8 +7,8 @@ import ( "github.com/spf13/cobra" - cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tendermint/types" + cmn "github.com/tendermint/tmlibs/common" ) var testnetFilesCmd = &cobra.Command{ @@ -48,7 +48,7 @@ func testnetFiles(cmd *cobra.Command, args []string) { privVal := types.LoadPrivValidator(privValFile) genVals[i] = types.GenesisValidator{ PubKey: privVal.PubKey, - Amount: 1, + Power: 1, Name: mach, } } diff --git a/config/toml.go b/config/toml.go index 999a0594..5dcbe533 100644 --- a/config/toml.go +++ b/config/toml.go @@ -119,7 +119,7 @@ var testGenesis = `{ "type": "ed25519", "data":"3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8" }, - "amount": 10, + "power": 10, "name": "" } ], diff --git a/consensus/common_test.go b/consensus/common_test.go index 84f47d02..6a05b74e 100644 --- a/consensus/common_test.go +++ b/consensus/common_test.go @@ -400,7 +400,7 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G val, privVal := types.RandValidator(randPower, minPower) validators[i] = types.GenesisValidator{ PubKey: val.PubKey, - Amount: val.VotingPower, + Power: val.VotingPower, } privValidators[i] = privVal } diff --git a/docs/specification/genesis.rst b/docs/specification/genesis.rst index 32dd1963..2187eb57 100644 --- a/docs/specification/genesis.rst +++ b/docs/specification/genesis.rst @@ -21,7 +21,7 @@ Fields - ``validators``: - ``pub_key``: The first element specifies the pub\_key type. 1 == Ed25519. The second element are the pubkey bytes. -- ``amount``: The validator's voting power. +- ``power``: The validator's voting power. - ``name``: Name of the validator (optional). - ``app_hash``: The expected application hash (as returned by the ``Commit`` ABCI message) upon genesis. If the app's hash does not @@ -41,7 +41,7 @@ Sample genesis.json 1, "9BC5112CB9614D91CE423FA8744885126CD9D08D9FC9D1F42E552D662BAA411E" ], - "amount": 1, + "power": 1, "name": "mach1" }, { @@ -49,7 +49,7 @@ Sample genesis.json 1, "F46A5543D51F31660D9F59653B4F96061A740FF7433E0DC1ECBC30BE8494DE06" ], - "amount": 1, + "power": 1, "name": "mach2" }, { @@ -57,7 +57,7 @@ Sample genesis.json 1, "0E7B423C1635FD07C0FC3603B736D5D27953C1C6CA865BB9392CD79DE1A682BB" ], - "amount": 1, + "power": 1, "name": "mach3" }, { @@ -65,7 +65,7 @@ Sample genesis.json 1, "4F49237B9A32EB50682EDD83C48CE9CDB1D02A7CFDADCFF6EC8C1FAADB358879" ], - "amount": 1, + "power": 1, "name": "mach4" } ], diff --git a/docs/using-tendermint.rst b/docs/using-tendermint.rst index fb9882f6..1cb3ad86 100644 --- a/docs/using-tendermint.rst +++ b/docs/using-tendermint.rst @@ -177,7 +177,7 @@ When ``tendermint init`` is run, both a ``genesis.json`` and "genesis_time": "0001-01-01T00:00:00.000Z", "validators": [ { - "amount": 10, + "power": 10, "name": "", "pub_key": [ 1, @@ -310,7 +310,7 @@ then the new ``genesis.json`` will be: "genesis_time": "0001-01-01T00:00:00.000Z", "validators": [ { - "amount": 10, + "power": 10, "name": "", "pub_key": [ 1, @@ -318,7 +318,7 @@ then the new ``genesis.json`` will be: ] }, { - "amount": 10, + "power": 10, "name": "", "pub_key": [ 1, diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index fee92b4a..33cd4b43 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -93,7 +93,7 @@ func TestGenesisAndValidators(t *testing.T) { val := vals.Validators[0] // make sure the current set is also the genesis set - assert.Equal(t, gval.Amount, val.VotingPower) + assert.Equal(t, gval.Power, val.VotingPower) assert.Equal(t, gval.PubKey, val.PubKey) } } diff --git a/rpc/core/net.go b/rpc/core/net.go index c6749941..b3f1c7ce 100644 --- a/rpc/core/net.go +++ b/rpc/core/net.go @@ -90,7 +90,7 @@ func UnsafeDialSeeds(seeds []string) (*ctypes.ResultDialSeeds, error) { // "validators": [ // { // "name": "", -// "amount": 10, +// "power": 10, // "pub_key": { // "data": "68DFDA7E50F82946E7E8546BED37944A422CD1B831E70DF66BA3B8430593944D", // "type": "ed25519" diff --git a/state/state.go b/state/state.go index 1374fcf4..3a8b98d0 100644 --- a/state/state.go +++ b/state/state.go @@ -347,7 +347,7 @@ func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State { validators[i] = &types.Validator{ Address: address, PubKey: pubKey, - VotingPower: val.Amount, + VotingPower: val.Power, } } diff --git a/test/p2p/data/mach1/core/genesis.json b/test/p2p/data/mach1/core/genesis.json index 522f9831..8d5c6c7b 100644 --- a/test/p2p/data/mach1/core/genesis.json +++ b/test/p2p/data/mach1/core/genesis.json @@ -4,7 +4,7 @@ "genesis_time": "2016-06-24T20:01:19.322Z", "validators": [ { - "amount": 1, + "power": 1, "name": "mach1", "pub_key": { "type": "ed25519", @@ -12,7 +12,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach2", "pub_key": { "type": "ed25519", @@ -20,7 +20,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach3", "pub_key": { "type": "ed25519", @@ -28,7 +28,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach4", "pub_key": { "type": "ed25519", diff --git a/test/p2p/data/mach2/core/genesis.json b/test/p2p/data/mach2/core/genesis.json index 522f9831..8d5c6c7b 100644 --- a/test/p2p/data/mach2/core/genesis.json +++ b/test/p2p/data/mach2/core/genesis.json @@ -4,7 +4,7 @@ "genesis_time": "2016-06-24T20:01:19.322Z", "validators": [ { - "amount": 1, + "power": 1, "name": "mach1", "pub_key": { "type": "ed25519", @@ -12,7 +12,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach2", "pub_key": { "type": "ed25519", @@ -20,7 +20,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach3", "pub_key": { "type": "ed25519", @@ -28,7 +28,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach4", "pub_key": { "type": "ed25519", diff --git a/test/p2p/data/mach3/core/genesis.json b/test/p2p/data/mach3/core/genesis.json index 522f9831..8d5c6c7b 100644 --- a/test/p2p/data/mach3/core/genesis.json +++ b/test/p2p/data/mach3/core/genesis.json @@ -4,7 +4,7 @@ "genesis_time": "2016-06-24T20:01:19.322Z", "validators": [ { - "amount": 1, + "power": 1, "name": "mach1", "pub_key": { "type": "ed25519", @@ -12,7 +12,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach2", "pub_key": { "type": "ed25519", @@ -20,7 +20,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach3", "pub_key": { "type": "ed25519", @@ -28,7 +28,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach4", "pub_key": { "type": "ed25519", diff --git a/test/p2p/data/mach4/core/genesis.json b/test/p2p/data/mach4/core/genesis.json index 522f9831..8d5c6c7b 100644 --- a/test/p2p/data/mach4/core/genesis.json +++ b/test/p2p/data/mach4/core/genesis.json @@ -4,7 +4,7 @@ "genesis_time": "2016-06-24T20:01:19.322Z", "validators": [ { - "amount": 1, + "power": 1, "name": "mach1", "pub_key": { "type": "ed25519", @@ -12,7 +12,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach2", "pub_key": { "type": "ed25519", @@ -20,7 +20,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach3", "pub_key": { "type": "ed25519", @@ -28,7 +28,7 @@ } }, { - "amount": 1, + "power": 1, "name": "mach4", "pub_key": { "type": "ed25519", diff --git a/types/genesis.go b/types/genesis.go index 06b3d124..e57787c4 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -18,7 +18,7 @@ import ( // GenesisValidator is an initial validator. type GenesisValidator struct { PubKey crypto.PubKey `json:"pub_key"` - Amount int64 `json:"amount"` + Power int64 `json:"power"` Name string `json:"name"` } @@ -44,7 +44,7 @@ func (genDoc *GenesisDoc) SaveAs(file string) error { func (genDoc *GenesisDoc) ValidatorHash() []byte { vals := make([]*Validator, len(genDoc.Validators)) for i, v := range genDoc.Validators { - vals[i] = NewValidator(v.PubKey, v.Amount) + vals[i] = NewValidator(v.PubKey, v.Power) } vset := NewValidatorSet(vals) return vset.Hash() @@ -71,6 +71,12 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error { return errors.Errorf("The genesis file must have at least one validator") } + for _, v := range genDoc.Validators { + if v.Power == 0 { + return errors.Errorf("The genesis file cannot contain validators with no voting power: %v", v) + } + } + if genDoc.GenesisTime.IsZero() { genDoc.GenesisTime = time.Now() } diff --git a/types/genesis_test.go b/types/genesis_test.go index d06a70da..fe997b69 100644 --- a/types/genesis_test.go +++ b/types/genesis_test.go @@ -20,7 +20,7 @@ func TestGenesis(t *testing.T) { []byte(`{"chain_id": "mychain", "validators": [{}]`), // missing validators []byte(`{"validators":[{"pub_key": {"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"}, - "amount":10,"name":""}]}`), // missing chain_id + "power":10,"name":""}]}`), // missing chain_id } for _, testCase := range testCases { @@ -29,7 +29,7 @@ func TestGenesis(t *testing.T) { } // test a good one by raw json - genDocBytes := []byte(`{"genesis_time":"0001-01-01T00:00:00Z","chain_id":"test-chain-QDKdJr","consensus_params":null,"validators":[{"pub_key":{"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"},"amount":10,"name":""}],"app_hash":""}`) + genDocBytes := []byte(`{"genesis_time":"0001-01-01T00:00:00Z","chain_id":"test-chain-QDKdJr","consensus_params":null,"validators":[{"pub_key":{"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"},"power":10,"name":""}],"app_hash":""}`) _, err := GenesisDocFromJSON(genDocBytes) assert.NoError(t, err, "expected no error for good genDoc json") From 1f0985689dbc4a0f29f1ee297d37f08df6042a28 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Sep 2017 15:22:58 -0400 Subject: [PATCH 10/10] ConsensusParams ptr in GenesisDoc for json --- state/state.go | 2 +- types/genesis.go | 5 ++--- types/params.go | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/state/state.go b/state/state.go index 3a8b98d0..2ebbec10 100644 --- a/state/state.go +++ b/state/state.go @@ -266,7 +266,7 @@ func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) { func (s *State) Params() types.ConsensusParams { // TODO: this should move into the State proper // when we allow the app to change it - return s.GenesisDoc.ConsensusParams + return *s.GenesisDoc.ConsensusParams } //------------------------------------------------------------------------ diff --git a/types/genesis.go b/types/genesis.go index e57787c4..f1b2736f 100644 --- a/types/genesis.go +++ b/types/genesis.go @@ -26,7 +26,7 @@ type GenesisValidator struct { type GenesisDoc struct { GenesisTime time.Time `json:"genesis_time"` ChainID string `json:"chain_id"` - ConsensusParams ConsensusParams `json:"consensus_params"` + ConsensusParams *ConsensusParams `json:"consensus_params,omitempty"` Validators []GenesisValidator `json:"validators"` AppHash data.Bytes `json:"app_hash"` } @@ -58,8 +58,7 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error { return errors.Errorf("Genesis doc must include non-empty chain_id") } - var emptyParams ConsensusParams - if genDoc.ConsensusParams == emptyParams { + if genDoc.ConsensusParams == nil { genDoc.ConsensusParams = DefaultConsensusParams() } else { if err := genDoc.ConsensusParams.Validate(); err != nil { diff --git a/types/params.go b/types/params.go index cd324219..495d1fd4 100644 --- a/types/params.go +++ b/types/params.go @@ -35,8 +35,8 @@ type BlockGossipParams struct { } // DefaultConsensusParams returns a default ConsensusParams. -func DefaultConsensusParams() ConsensusParams { - return ConsensusParams{ +func DefaultConsensusParams() *ConsensusParams { + return &ConsensusParams{ DefaultBlockSizeParams(), DefaultTxSizeParams(), DefaultBlockGossipParams(),