@ -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
}
// TestBeginBlockAbsent Validators ensures we send absent validators list.
func TestBeginBlockAbsent Validators ( 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
Absent Validators [ ] 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 . Absent Validators = req . Absent Validators
app . Validators = req . Validators
app . ByzantineValidators = req . ByzantineValidators
return abci . ResponseBeginBlock { }
}