|
|
@ -1,6 +1,7 @@ |
|
|
|
package state |
|
|
|
|
|
|
|
import ( |
|
|
|
"fmt" |
|
|
|
"testing" |
|
|
|
"time" |
|
|
|
|
|
|
@ -19,7 +20,6 @@ import ( |
|
|
|
) |
|
|
|
|
|
|
|
var ( |
|
|
|
privKey = crypto.GenPrivKeyEd25519FromSecret([]byte("execution_test")) |
|
|
|
chainID = "execution_chain" |
|
|
|
testPartSize = 65536 |
|
|
|
nTxsPerBlock = 10 |
|
|
@ -32,7 +32,7 @@ func TestApplyBlock(t *testing.T) { |
|
|
|
require.Nil(t, err) |
|
|
|
defer proxyApp.Stop() |
|
|
|
|
|
|
|
state, stateDB := state(), dbm.NewMemDB() |
|
|
|
state, stateDB := state(1, 1) |
|
|
|
|
|
|
|
blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), |
|
|
|
MockMempool{}, MockEvidencePool{}) |
|
|
@ -46,8 +46,8 @@ func TestApplyBlock(t *testing.T) { |
|
|
|
// TODO check state and mempool
|
|
|
|
} |
|
|
|
|
|
|
|
// TestBeginBlockAbsentValidators ensures we send absent validators list.
|
|
|
|
func TestBeginBlockAbsentValidators(t *testing.T) { |
|
|
|
// TestBeginBlockValidators ensures we send absent validators list.
|
|
|
|
func TestBeginBlockValidators(t *testing.T) { |
|
|
|
app := &testApp{} |
|
|
|
cc := proxy.NewLocalClientCreator(app) |
|
|
|
proxyApp := proxy.NewAppConns(cc, nil) |
|
|
@ -55,32 +55,46 @@ func TestBeginBlockAbsentValidators(t *testing.T) { |
|
|
|
require.Nil(t, err) |
|
|
|
defer proxyApp.Stop() |
|
|
|
|
|
|
|
state := state() |
|
|
|
state, stateDB := state(2, 2) |
|
|
|
|
|
|
|
prevHash := state.LastBlockID.Hash |
|
|
|
prevParts := types.PartSetHeader{} |
|
|
|
prevBlockID := types.BlockID{prevHash, prevParts} |
|
|
|
|
|
|
|
now := time.Now().UTC() |
|
|
|
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} |
|
|
|
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now} |
|
|
|
|
|
|
|
testCases := []struct { |
|
|
|
desc string |
|
|
|
lastCommitPrecommits []*types.Vote |
|
|
|
expectedAbsentValidators []int32 |
|
|
|
expectedAbsentValidators []int |
|
|
|
}{ |
|
|
|
{"none absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}, {ValidatorIndex: 1, Timestamp: now}}, []int32{}}, |
|
|
|
{"one absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}, nil}, []int32{1}}, |
|
|
|
{"multiple absent", []*types.Vote{nil, nil}, []int32{0, 1}}, |
|
|
|
{"none absent", []*types.Vote{vote0, vote1}, []int{}}, |
|
|
|
{"one absent", []*types.Vote{vote0, nil}, []int{1}}, |
|
|
|
{"multiple absent", []*types.Vote{nil, nil}, []int{0, 1}}, |
|
|
|
} |
|
|
|
|
|
|
|
for _, tc := range testCases { |
|
|
|
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits} |
|
|
|
|
|
|
|
// block for height 2
|
|
|
|
block, _ := state.MakeBlock(2, makeTxs(2), lastCommit) |
|
|
|
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger()) |
|
|
|
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB) |
|
|
|
require.Nil(t, err, tc.desc) |
|
|
|
|
|
|
|
// -> app must receive an index of the absent validator
|
|
|
|
assert.Equal(t, tc.expectedAbsentValidators, app.AbsentValidators, tc.desc) |
|
|
|
// -> app receives a list of validators with a bool indicating if they signed
|
|
|
|
ctr := 0 |
|
|
|
for i, v := range app.Validators { |
|
|
|
if ctr < len(tc.expectedAbsentValidators) && |
|
|
|
tc.expectedAbsentValidators[ctr] == i { |
|
|
|
|
|
|
|
assert.False(t, v.SignedLastBlock) |
|
|
|
ctr++ |
|
|
|
} else { |
|
|
|
assert.True(t, v.SignedLastBlock) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -93,35 +107,41 @@ func TestBeginBlockByzantineValidators(t *testing.T) { |
|
|
|
require.Nil(t, err) |
|
|
|
defer proxyApp.Stop() |
|
|
|
|
|
|
|
state := state() |
|
|
|
state, stateDB := state(2, 12) |
|
|
|
|
|
|
|
prevHash := state.LastBlockID.Hash |
|
|
|
prevParts := types.PartSetHeader{} |
|
|
|
prevBlockID := types.BlockID{prevHash, prevParts} |
|
|
|
|
|
|
|
height1, idx1, val1 := int64(8), 0, []byte("val1") |
|
|
|
height2, idx2, val2 := int64(3), 1, []byte("val2") |
|
|
|
height1, idx1, val1 := int64(8), 0, state.Validators.Validators[0].Address |
|
|
|
height2, idx2, val2 := int64(3), 1, state.Validators.Validators[1].Address |
|
|
|
ev1 := types.NewMockGoodEvidence(height1, idx1, val1) |
|
|
|
ev2 := types.NewMockGoodEvidence(height2, idx2, val2) |
|
|
|
|
|
|
|
now := time.Now() |
|
|
|
valSet := state.Validators |
|
|
|
testCases := []struct { |
|
|
|
desc string |
|
|
|
evidence []types.Evidence |
|
|
|
expectedByzantineValidators []abci.Evidence |
|
|
|
}{ |
|
|
|
{"none byzantine", []types.Evidence{}, []abci.Evidence{}}, |
|
|
|
{"one byzantine", []types.Evidence{ev1}, []abci.Evidence{{ev1.Address(), ev1.Height()}}}, |
|
|
|
{"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1, valSet, now)}}, |
|
|
|
{"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{ |
|
|
|
{ev1.Address(), ev1.Height()}, |
|
|
|
{ev2.Address(), ev2.Height()}}}, |
|
|
|
types.TM2PB.Evidence(ev1, valSet, now), |
|
|
|
types.TM2PB.Evidence(ev2, valSet, now)}}, |
|
|
|
} |
|
|
|
|
|
|
|
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} |
|
|
|
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now} |
|
|
|
votes := []*types.Vote{vote0, vote1} |
|
|
|
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes} |
|
|
|
for _, tc := range testCases { |
|
|
|
lastCommit := &types.Commit{BlockID: prevBlockID} |
|
|
|
|
|
|
|
block, _ := state.MakeBlock(10, makeTxs(2), lastCommit) |
|
|
|
block.Time = now |
|
|
|
block.Evidence.Evidence = tc.evidence |
|
|
|
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger()) |
|
|
|
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB) |
|
|
|
require.Nil(t, err, tc.desc) |
|
|
|
|
|
|
|
// -> app must receive an index of the byzantine validator
|
|
|
@ -139,15 +159,30 @@ func makeTxs(height int64) (txs []types.Tx) { |
|
|
|
return txs |
|
|
|
} |
|
|
|
|
|
|
|
func state() State { |
|
|
|
func state(nVals, height int) (State, dbm.DB) { |
|
|
|
vals := make([]types.GenesisValidator, nVals) |
|
|
|
for i := 0; i < nVals; i++ { |
|
|
|
secret := []byte(fmt.Sprintf("test%d", i)) |
|
|
|
pk := crypto.GenPrivKeyEd25519FromSecret(secret) |
|
|
|
vals[i] = types.GenesisValidator{ |
|
|
|
pk.PubKey(), 1000, fmt.Sprintf("test%d", i), |
|
|
|
} |
|
|
|
} |
|
|
|
s, _ := MakeGenesisState(&types.GenesisDoc{ |
|
|
|
ChainID: chainID, |
|
|
|
Validators: []types.GenesisValidator{ |
|
|
|
{privKey.PubKey(), 10000, "test"}, |
|
|
|
}, |
|
|
|
AppHash: nil, |
|
|
|
ChainID: chainID, |
|
|
|
Validators: vals, |
|
|
|
AppHash: nil, |
|
|
|
}) |
|
|
|
return s |
|
|
|
|
|
|
|
// save validators to db for 2 heights
|
|
|
|
stateDB := dbm.NewMemDB() |
|
|
|
SaveState(stateDB, s) |
|
|
|
|
|
|
|
for i := 1; i < height; i++ { |
|
|
|
s.LastBlockHeight += 1 |
|
|
|
SaveState(stateDB, s) |
|
|
|
} |
|
|
|
return s, stateDB |
|
|
|
} |
|
|
|
|
|
|
|
func makeBlock(state State, height int64) *types.Block { |
|
|
@ -162,7 +197,7 @@ var _ abci.Application = (*testApp)(nil) |
|
|
|
type testApp struct { |
|
|
|
abci.BaseApplication |
|
|
|
|
|
|
|
AbsentValidators []int32 |
|
|
|
Validators []abci.SigningValidator |
|
|
|
ByzantineValidators []abci.Evidence |
|
|
|
} |
|
|
|
|
|
|
@ -175,7 +210,7 @@ func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) { |
|
|
|
} |
|
|
|
|
|
|
|
func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock { |
|
|
|
app.AbsentValidators = req.AbsentValidators |
|
|
|
app.Validators = req.Validators |
|
|
|
app.ByzantineValidators = req.ByzantineValidators |
|
|
|
return abci.ResponseBeginBlock{} |
|
|
|
} |
|
|
|