Browse Source

genesis json tests and mv ConsensusParams to types

pull/650/head
Ethan Buchman 7 years ago
parent
commit
2b6db268cf
9 changed files with 149 additions and 61 deletions
  1. +2
    -2
      blockchain/reactor.go
  2. +0
    -27
      config/consensus.go
  3. +4
    -4
      consensus/replay_test.go
  4. +2
    -2
      consensus/state.go
  5. +7
    -7
      consensus/state_test.go
  6. +17
    -11
      state/state.go
  7. +6
    -8
      types/genesis.go
  8. +79
    -0
      types/genesis_test.go
  9. +32
    -0
      types/params.go

+ 2
- 2
blockchain/reactor.go View File

@ -165,7 +165,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
// maxMsgSize returns the maximum allowable size of a // maxMsgSize returns the maximum allowable size of a
// message on the blockchain reactor. // message on the blockchain reactor.
func (bcR *BlockchainReactor) maxMsgSize() int { 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. // 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. // We need both to sync the first block.
break SYNC_LOOP break SYNC_LOOP
} }
firstParts := first.MakePartSet(bcR.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes)
firstParts := first.MakePartSet(bcR.state.Params().BlockPartSizeBytes)
firstPartsHeader := firstParts.Header() firstPartsHeader := firstParts.Header()
// Finally, verify the first block using the second's commit // Finally, verify the first block using the second's commit
// NOTE: we can probably make this more efficient, but note that calling // NOTE: we can probably make this more efficient, but note that calling


+ 0
- 27
config/consensus.go View File

@ -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
}

+ 4
- 4
consensus/replay_test.go View File

@ -381,7 +381,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
} }
func applyBlock(st *sm.State, blk *types.Block, proxyApp proxy.AppConns) { 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) err := st.ApplyBlock(nil, proxyApp.Consensus(), blk, blk.MakePartSet(testPartSize).Header(), mempool)
if err != nil { if err != nil {
panic(err) panic(err)
@ -561,7 +561,7 @@ func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBl
state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile()) state := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
state.SetLogger(log.TestingLogger().With("module", "state")) state.SetLogger(log.TestingLogger().With("module", "state"))
store := NewMockBlockStore(config, state.GenesisDoc.ConsensusParams)
store := NewMockBlockStore(config, state.Params())
return state, store return state, store
} }
@ -570,13 +570,13 @@ func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBl
type mockBlockStore struct { type mockBlockStore struct {
config *cfg.Config config *cfg.Config
params *cfg.ConsensusParams
params *types.ConsensusParams
chain []*types.Block chain []*types.Block
commits []*types.Commit commits []*types.Commit
} }
// TODO: NewBlockStore(db.NewMemDB) ... // 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} return &mockBlockStore{config, params, nil, nil}
} }


+ 2
- 2
consensus/state.go View File

@ -984,7 +984,7 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts
return types.MakeBlock(cs.Height, cs.state.ChainID, txs, commit, return types.MakeBlock(cs.Height, cs.state.ChainID, txs, commit,
cs.state.LastBlockID, cs.state.Validators.Hash(), 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. // Enter: `timeoutPropose` after entering Propose.
@ -1419,7 +1419,7 @@ func (cs *ConsensusState) addProposalBlockPart(height int, part *types.Part, ver
var n int var n int
var err error var err error
cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), 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 // 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()) cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash())
if cs.Step == RoundStepPropose && cs.isProposalComplete() { if cs.Step == RoundStepPropose && cs.isProposalComplete() {


+ 7
- 7
consensus/state_test.go View File

@ -180,7 +180,7 @@ func TestBadProposal(t *testing.T) {
height, round := cs1.Height, cs1.Round height, round := cs1.Height, cs1.Round
vs2 := vss[1] vs2 := vss[1]
partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes
partSize := cs1.state.Params().BlockPartSizeBytes
proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1) proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1) voteCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringVote(), 1)
@ -327,7 +327,7 @@ func TestLockNoPOL(t *testing.T) {
vs2 := vss[1] vs2 := vss[1]
height := cs1.Height height := cs1.Height
partSize := cs1.state.GenesisDoc.ConsensusParams.BlockPartSizeBytes
partSize := cs1.state.Params().BlockPartSizeBytes
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
@ -493,7 +493,7 @@ func TestLockPOLRelock(t *testing.T) {
cs1, vss := randConsensusState(4) cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3] 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) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)
@ -608,7 +608,7 @@ func TestLockPOLUnlock(t *testing.T) {
cs1, vss := randConsensusState(4) cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3] 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) proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
@ -703,7 +703,7 @@ func TestLockPOLSafety1(t *testing.T) {
cs1, vss := randConsensusState(4) cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3] 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) proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
@ -824,7 +824,7 @@ func TestLockPOLSafety2(t *testing.T) {
cs1, vss := randConsensusState(4) cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3] 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) proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1) timeoutProposeCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutPropose(), 1)
@ -999,7 +999,7 @@ func TestHalt1(t *testing.T) {
cs1, vss := randConsensusState(4) cs1, vss := randConsensusState(4)
vs2, vs3, vs4 := vss[1], vss[2], vss[3] 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) proposalCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringCompleteProposal(), 1)
timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1) timeoutWaitCh := subscribeToEvent(cs1.evsw, "tester", types.EventStringTimeoutWait(), 1)


+ 17
- 11
state/state.go View File

@ -65,6 +65,19 @@ type State struct {
logger log.Logger 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. // LoadState loads the State from the database.
func LoadState(db dbm.DB) *State { func LoadState(db dbm.DB) *State {
return loadState(db, stateKey) return loadState(db, stateKey)
@ -248,17 +261,10 @@ func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) {
return s.LastValidators, s.Validators 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
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------


+ 6
- 8
types/genesis.go View File

@ -10,8 +10,6 @@ import (
"github.com/tendermint/go-crypto" "github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire/data" "github.com/tendermint/go-wire/data"
cmn "github.com/tendermint/tmlibs/common" 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. // GenesisDoc defines the initial conditions for a tendermint blockchain, in particular its validator set.
type GenesisDoc struct { 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. // 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 { if genDoc.ConsensusParams == nil {
genDoc.ConsensusParams = cfg.DefaultConsensusParams()
genDoc.ConsensusParams = DefaultConsensusParams()
} else { } else {
if err := genDoc.ConsensusParams.Validate(); err != nil { if err := genDoc.ConsensusParams.Validate(); err != nil {
return err return err


+ 79
- 0
types/genesis_test.go View File

@ -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")
}
}
}

+ 32
- 0
types/params.go View File

@ -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
}

Loading…
Cancel
Save