You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

288 lines
8.3 KiB

package state_test
import (
"bytes"
"fmt"
"time"
dbm "github.com/tendermint/tm-db"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
tmrand "github.com/tendermint/tendermint/libs/rand"
"github.com/tendermint/tendermint/proxy"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
type paramsChangeTestCase struct {
height int64
params types.ConsensusParams
}
// always returns true if asked if any evidence was already committed.
type mockEvPoolAlwaysCommitted struct{}
func (m mockEvPoolAlwaysCommitted) PendingEvidence(int64) []types.Evidence { return nil }
func (m mockEvPoolAlwaysCommitted) AddEvidence(types.Evidence) error { return nil }
func (m mockEvPoolAlwaysCommitted) Update(*types.Block, sm.State) {}
func (m mockEvPoolAlwaysCommitted) IsCommitted(types.Evidence) bool { return true }
func (m mockEvPoolAlwaysCommitted) IsPending(types.Evidence) bool { return false }
func newTestApp() proxy.AppConns {
app := &testApp{}
cc := proxy.NewLocalClientCreator(app)
return proxy.NewAppConns(cc)
}
func makeAndCommitGoodBlock(
state sm.State,
height int64,
lastCommit *types.Commit,
proposerAddr []byte,
blockExec *sm.BlockExecutor,
privVals map[string]types.PrivValidator,
evidence []types.Evidence) (sm.State, types.BlockID, *types.Commit, error) {
// A good block passes
state, blockID, err := makeAndApplyGoodBlock(state, height, lastCommit, proposerAddr, blockExec, evidence)
if err != nil {
return state, types.BlockID{}, nil, err
}
// Simulate a lastCommit for this block from all validators for the next height
commit, err := makeValidCommit(height, blockID, state.Validators, privVals)
if err != nil {
return state, types.BlockID{}, nil, err
}
return state, blockID, commit, nil
}
func makeAndApplyGoodBlock(state sm.State, height int64, lastCommit *types.Commit, proposerAddr []byte,
blockExec *sm.BlockExecutor, evidence []types.Evidence) (sm.State, types.BlockID, error) {
block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr)
if err := blockExec.ValidateBlock(state, block); err != nil {
return state, types.BlockID{}, err
}
blockID := types.BlockID{Hash: block.Hash(),
PartsHeader: types.PartSetHeader{Total: 3, Hash: tmrand.Bytes(32)}}
state, _, err := blockExec.ApplyBlock(state, blockID, block)
if err != nil {
return state, types.BlockID{}, err
}
return state, blockID, nil
}
func makeValidCommit(
height int64,
blockID types.BlockID,
vals *types.ValidatorSet,
privVals map[string]types.PrivValidator,
) (*types.Commit, error) {
sigs := make([]types.CommitSig, 0)
for i := 0; i < vals.Size(); i++ {
_, val := vals.GetByIndex(i)
vote, err := types.MakeVote(height, blockID, vals, privVals[val.Address.String()], chainID, time.Now())
if err != nil {
return nil, err
}
sigs = append(sigs, vote.CommitSig())
}
return types.NewCommit(height, 0, blockID, sigs), nil
}
// make some bogus txs
func makeTxs(height int64) (txs []types.Tx) {
for i := 0; i < nTxsPerBlock; i++ {
txs = append(txs, types.Tx([]byte{byte(height), byte(i)}))
}
return txs
}
func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) {
vals := make([]types.GenesisValidator, nVals)
privVals := make(map[string]types.PrivValidator, nVals)
for i := 0; i < nVals; i++ {
secret := []byte(fmt.Sprintf("test%d", i))
pk := ed25519.GenPrivKeyFromSecret(secret)
valAddr := pk.PubKey().Address()
vals[i] = types.GenesisValidator{
Address: valAddr,
PubKey: pk.PubKey(),
Power: 1000,
Name: fmt.Sprintf("test%d", i),
}
privVals[valAddr.String()] = types.NewMockPVWithParams(pk, false, false)
}
s, _ := sm.MakeGenesisState(&types.GenesisDoc{
ChainID: chainID,
Validators: vals,
AppHash: nil,
})
stateDB := dbm.NewMemDB()
sm.SaveState(stateDB, s)
for i := 1; i < height; i++ {
s.LastBlockHeight++
s.LastValidators = s.Validators.Copy()
sm.SaveState(stateDB, s)
}
return s, stateDB, privVals
}
func makeBlock(state sm.State, height int64) *types.Block {
block, _ := state.MakeBlock(
height,
makeTxs(state.LastBlockHeight),
new(types.Commit),
nil,
state.Validators.GetProposer().Address,
)
return block
}
func genValSet(size int) *types.ValidatorSet {
vals := make([]*types.Validator, size)
for i := 0; i < size; i++ {
vals[i] = types.NewValidator(ed25519.GenPrivKey().PubKey(), 10)
}
return types.NewValidatorSet(vals)
}
func makeConsensusParams(
blockBytes, blockGas int64,
blockTimeIotaMs int64,
evidenceAge int64,
) types.ConsensusParams {
return types.ConsensusParams{
Block: types.BlockParams{
MaxBytes: blockBytes,
MaxGas: blockGas,
TimeIotaMs: blockTimeIotaMs,
},
Evidence: types.EvidenceParams{
MaxAgeNumBlocks: evidenceAge,
MaxAgeDuration: time.Duration(evidenceAge),
},
}
}
func makeHeaderPartsResponsesValPubKeyChange(
state sm.State,
pubkey crypto.PubKey,
) (types.Header, types.BlockID, *sm.ABCIResponses) {
block := makeBlock(state, state.LastBlockHeight+1)
abciResponses := &sm.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
// If the pubkey is new, remove the old and add the new.
_, val := state.NextValidators.GetByIndex(0)
if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) {
abciResponses.EndBlock = &abci.ResponseEndBlock{
ValidatorUpdates: []abci.ValidatorUpdate{
types.TM2PB.NewValidatorUpdate(val.PubKey, 0),
types.TM2PB.NewValidatorUpdate(pubkey, 10),
},
}
}
return block.Header, types.BlockID{Hash: block.Hash(), PartsHeader: types.PartSetHeader{}}, abciResponses
}
func makeHeaderPartsResponsesValPowerChange(
state sm.State,
power int64,
) (types.Header, types.BlockID, *sm.ABCIResponses) {
block := makeBlock(state, state.LastBlockHeight+1)
abciResponses := &sm.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
}
// If the pubkey is new, remove the old and add the new.
_, val := state.NextValidators.GetByIndex(0)
if val.VotingPower != power {
abciResponses.EndBlock = &abci.ResponseEndBlock{
ValidatorUpdates: []abci.ValidatorUpdate{
types.TM2PB.NewValidatorUpdate(val.PubKey, power),
},
}
}
return block.Header, types.BlockID{Hash: block.Hash(), PartsHeader: types.PartSetHeader{}}, abciResponses
}
func makeHeaderPartsResponsesParams(
state sm.State,
params types.ConsensusParams,
) (types.Header, types.BlockID, *sm.ABCIResponses) {
block := makeBlock(state, state.LastBlockHeight+1)
abciResponses := &sm.ABCIResponses{
EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(&params)},
}
return block.Header, types.BlockID{Hash: block.Hash(), PartsHeader: types.PartSetHeader{}}, abciResponses
}
func randomGenesisDoc() *types.GenesisDoc {
pubkey := ed25519.GenPrivKey().PubKey()
return &types.GenesisDoc{
GenesisTime: tmtime.Now(),
ChainID: "abc",
Validators: []types.GenesisValidator{
{
Address: pubkey.Address(),
PubKey: pubkey,
Power: 10,
Name: "myval",
},
},
ConsensusParams: types.DefaultConsensusParams(),
}
}
//----------------------------------------------------------------------------
type testApp struct {
abci.BaseApplication
CommitVotes []abci.VoteInfo
ByzantineValidators []abci.Evidence
ValidatorUpdates []abci.ValidatorUpdate
}
var _ abci.Application = (*testApp)(nil)
func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) {
return abci.ResponseInfo{}
}
func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
app.CommitVotes = req.LastCommitInfo.Votes
app.ByzantineValidators = req.ByzantineValidators
return abci.ResponseBeginBlock{}
}
func (app *testApp) EndBlock(req abci.RequestEndBlock) abci.ResponseEndBlock {
return abci.ResponseEndBlock{ValidatorUpdates: app.ValidatorUpdates}
}
func (app *testApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx {
return abci.ResponseDeliverTx{Events: []abci.Event{}}
}
func (app *testApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
return abci.ResponseCheckTx{}
}
func (app *testApp) Commit() abci.ResponseCommit {
return abci.ResponseCommit{}
}
func (app *testApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) {
return
}