mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-14 13:51:21 +00:00
state: send byzantine validators in BeginBlock
This commit is contained in:
@ -53,8 +53,8 @@ func TestEvidencePool(t *testing.T) {
|
|||||||
store := NewEvidenceStore(dbm.NewMemDB())
|
store := NewEvidenceStore(dbm.NewMemDB())
|
||||||
pool := NewEvidencePool(stateDB, store)
|
pool := NewEvidencePool(stateDB, store)
|
||||||
|
|
||||||
goodEvidence := newMockGoodEvidence(height, 0, valAddr)
|
goodEvidence := types.NewMockGoodEvidence(height, 0, valAddr)
|
||||||
badEvidence := MockBadEvidence{goodEvidence}
|
badEvidence := types.MockBadEvidence{goodEvidence}
|
||||||
|
|
||||||
err := pool.AddEvidence(badEvidence)
|
err := pool.AddEvidence(badEvidence)
|
||||||
assert.NotNil(err)
|
assert.NotNil(err)
|
||||||
|
@ -101,7 +101,7 @@ func _waitForEvidence(t *testing.T, wg *sync.WaitGroup, evs types.EvidenceList,
|
|||||||
func sendEvidence(t *testing.T, evpool *EvidencePool, valAddr []byte, n int) types.EvidenceList {
|
func sendEvidence(t *testing.T, evpool *EvidencePool, valAddr []byte, n int) types.EvidenceList {
|
||||||
evList := make([]types.Evidence, n)
|
evList := make([]types.Evidence, n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
ev := newMockGoodEvidence(int64(i+1), 0, valAddr)
|
ev := types.NewMockGoodEvidence(int64(i+1), 0, valAddr)
|
||||||
err := evpool.AddEvidence(ev)
|
err := evpool.AddEvidence(ev)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
evList[i] = ev
|
evList[i] = ev
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package evidence
|
package evidence
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -20,7 +18,7 @@ func TestStoreAddDuplicate(t *testing.T) {
|
|||||||
store := NewEvidenceStore(db)
|
store := NewEvidenceStore(db)
|
||||||
|
|
||||||
priority := int64(10)
|
priority := int64(10)
|
||||||
ev := newMockGoodEvidence(2, 1, []byte("val1"))
|
ev := types.NewMockGoodEvidence(2, 1, []byte("val1"))
|
||||||
|
|
||||||
added := store.AddNewEvidence(ev, priority)
|
added := store.AddNewEvidence(ev, priority)
|
||||||
assert.True(added)
|
assert.True(added)
|
||||||
@ -43,7 +41,7 @@ func TestStoreMark(t *testing.T) {
|
|||||||
assert.Equal(0, len(pendingEv))
|
assert.Equal(0, len(pendingEv))
|
||||||
|
|
||||||
priority := int64(10)
|
priority := int64(10)
|
||||||
ev := newMockGoodEvidence(2, 1, []byte("val1"))
|
ev := types.NewMockGoodEvidence(2, 1, []byte("val1"))
|
||||||
|
|
||||||
added := store.AddNewEvidence(ev, priority)
|
added := store.AddNewEvidence(ev, priority)
|
||||||
assert.True(added)
|
assert.True(added)
|
||||||
@ -89,15 +87,15 @@ func TestStorePriority(t *testing.T) {
|
|||||||
|
|
||||||
// sorted by priority and then height
|
// sorted by priority and then height
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
ev MockGoodEvidence
|
ev types.MockGoodEvidence
|
||||||
priority int64
|
priority int64
|
||||||
}{
|
}{
|
||||||
{newMockGoodEvidence(2, 1, []byte("val1")), 17},
|
{types.NewMockGoodEvidence(2, 1, []byte("val1")), 17},
|
||||||
{newMockGoodEvidence(5, 2, []byte("val2")), 15},
|
{types.NewMockGoodEvidence(5, 2, []byte("val2")), 15},
|
||||||
{newMockGoodEvidence(10, 2, []byte("val2")), 13},
|
{types.NewMockGoodEvidence(10, 2, []byte("val2")), 13},
|
||||||
{newMockGoodEvidence(100, 2, []byte("val2")), 11},
|
{types.NewMockGoodEvidence(100, 2, []byte("val2")), 11},
|
||||||
{newMockGoodEvidence(90, 2, []byte("val2")), 11},
|
{types.NewMockGoodEvidence(90, 2, []byte("val2")), 11},
|
||||||
{newMockGoodEvidence(80, 2, []byte("val2")), 11},
|
{types.NewMockGoodEvidence(80, 2, []byte("val2")), 11},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
@ -119,48 +117,6 @@ const (
|
|||||||
|
|
||||||
var _ = wire.RegisterInterface(
|
var _ = wire.RegisterInterface(
|
||||||
struct{ types.Evidence }{},
|
struct{ types.Evidence }{},
|
||||||
wire.ConcreteType{MockGoodEvidence{}, evidenceTypeMockGood},
|
wire.ConcreteType{types.MockGoodEvidence{}, evidenceTypeMockGood},
|
||||||
wire.ConcreteType{MockBadEvidence{}, evidenceTypeMockBad},
|
wire.ConcreteType{types.MockBadEvidence{}, evidenceTypeMockBad},
|
||||||
)
|
)
|
||||||
|
|
||||||
type MockGoodEvidence struct {
|
|
||||||
Height_ int64
|
|
||||||
Address_ []byte
|
|
||||||
Index_ int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMockGoodEvidence(height int64, index int, address []byte) MockGoodEvidence {
|
|
||||||
return MockGoodEvidence{height, address, index}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e MockGoodEvidence) Height() int64 { return e.Height_ }
|
|
||||||
func (e MockGoodEvidence) Address() []byte { return e.Address_ }
|
|
||||||
func (e MockGoodEvidence) Index() int { return e.Index_ }
|
|
||||||
func (e MockGoodEvidence) Hash() []byte {
|
|
||||||
return []byte(fmt.Sprintf("%d-%d", e.Height_, e.Index_))
|
|
||||||
}
|
|
||||||
func (e MockGoodEvidence) Verify(chainID string) error { return nil }
|
|
||||||
func (e MockGoodEvidence) Equal(ev types.Evidence) bool {
|
|
||||||
e2 := ev.(MockGoodEvidence)
|
|
||||||
return e.Height_ == e2.Height_ &&
|
|
||||||
bytes.Equal(e.Address_, e2.Address_) &&
|
|
||||||
e.Index_ == e2.Index_
|
|
||||||
}
|
|
||||||
func (e MockGoodEvidence) String() string {
|
|
||||||
return fmt.Sprintf("GoodEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MockBadEvidence struct {
|
|
||||||
MockGoodEvidence
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e MockBadEvidence) Verify(chainID string) error { return fmt.Errorf("MockBadEvidence") }
|
|
||||||
func (e MockBadEvidence) Equal(ev types.Evidence) bool {
|
|
||||||
e2 := ev.(MockBadEvidence)
|
|
||||||
return e.Height_ == e2.Height_ &&
|
|
||||||
bytes.Equal(e.Address_, e2.Address_) &&
|
|
||||||
e.Index_ == e2.Index_
|
|
||||||
}
|
|
||||||
func (e MockBadEvidence) String() string {
|
|
||||||
return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
|
||||||
}
|
|
||||||
|
@ -191,13 +191,20 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: determine which validators were byzantine
|
// TODO: determine which validators were byzantine
|
||||||
|
byzantineVals := make([]*abci.Evidence, len(block.Evidence.Evidence))
|
||||||
|
for i, ev := range block.Evidence.Evidence {
|
||||||
|
byzantineVals[i] = &abci.Evidence{
|
||||||
|
PubKey: ev.Address(), // XXX
|
||||||
|
Height: ev.Height(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Begin block
|
// Begin block
|
||||||
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
||||||
Hash: block.Hash(),
|
Hash: block.Hash(),
|
||||||
Header: types.TM2PB.Header(block.Header),
|
Header: types.TM2PB.Header(block.Header),
|
||||||
AbsentValidators: absentVals,
|
AbsentValidators: absentVals,
|
||||||
ByzantineValidators: nil,
|
ByzantineValidators: byzantineVals,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
|
logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
|
||||||
|
@ -82,6 +82,51 @@ func TestBeginBlockAbsentValidators(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestBeginBlockByzantineValidators ensures we send byzantine validators list.
|
||||||
|
func TestBeginBlockByzantineValidators(t *testing.T) {
|
||||||
|
app := &testApp{}
|
||||||
|
cc := proxy.NewLocalClientCreator(app)
|
||||||
|
proxyApp := proxy.NewAppConns(cc, nil)
|
||||||
|
err := proxyApp.Start()
|
||||||
|
require.Nil(t, err)
|
||||||
|
defer proxyApp.Stop()
|
||||||
|
|
||||||
|
state := state()
|
||||||
|
|
||||||
|
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")
|
||||||
|
ev1 := types.NewMockGoodEvidence(height1, idx1, val1)
|
||||||
|
ev2 := types.NewMockGoodEvidence(height2, idx2, val2)
|
||||||
|
|
||||||
|
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()}}},
|
||||||
|
{"multiple byzantine", []types.Evidence{ev1, ev2}, []*abci.Evidence{
|
||||||
|
{ev1.Address(), ev1.Height()},
|
||||||
|
{ev2.Address(), ev2.Height()}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
lastCommit := &types.Commit{BlockID: prevBlockID}
|
||||||
|
|
||||||
|
block, _ := state.MakeBlock(10, makeTxs(2), lastCommit)
|
||||||
|
block.Evidence.Evidence = tc.evidence
|
||||||
|
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger())
|
||||||
|
require.Nil(t, err, tc.desc)
|
||||||
|
|
||||||
|
// -> app must receive an index of the byzantine validator
|
||||||
|
assert.Equal(t, tc.expectedByzantineValidators, app.ByzantineValidators, tc.desc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
// make some bogus txs
|
// make some bogus txs
|
||||||
@ -115,7 +160,8 @@ var _ abci.Application = (*testApp)(nil)
|
|||||||
type testApp struct {
|
type testApp struct {
|
||||||
abci.BaseApplication
|
abci.BaseApplication
|
||||||
|
|
||||||
AbsentValidators []int32
|
AbsentValidators []int32
|
||||||
|
ByzantineValidators []*abci.Evidence
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDummyApplication() *testApp {
|
func NewDummyApplication() *testApp {
|
||||||
@ -128,6 +174,7 @@ func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) {
|
|||||||
|
|
||||||
func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||||
app.AbsentValidators = req.AbsentValidators
|
app.AbsentValidators = req.AbsentValidators
|
||||||
|
app.ByzantineValidators = req.ByzantineValidators
|
||||||
return abci.ResponseBeginBlock{}
|
return abci.ResponseBeginBlock{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,3 +167,50 @@ func (dve *DuplicateVoteEvidence) Equal(ev Evidence) bool {
|
|||||||
// just check their hashes
|
// just check their hashes
|
||||||
return bytes.Equal(merkle.SimpleHashFromBinary(dve), merkle.SimpleHashFromBinary(ev))
|
return bytes.Equal(merkle.SimpleHashFromBinary(dve), merkle.SimpleHashFromBinary(ev))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------
|
||||||
|
|
||||||
|
// UNSTABLE
|
||||||
|
type MockGoodEvidence struct {
|
||||||
|
Height_ int64
|
||||||
|
Address_ []byte
|
||||||
|
Index_ int
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNSTABLE
|
||||||
|
func NewMockGoodEvidence(height int64, index int, address []byte) MockGoodEvidence {
|
||||||
|
return MockGoodEvidence{height, address, index}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MockGoodEvidence) Height() int64 { return e.Height_ }
|
||||||
|
func (e MockGoodEvidence) Address() []byte { return e.Address_ }
|
||||||
|
func (e MockGoodEvidence) Index() int { return e.Index_ }
|
||||||
|
func (e MockGoodEvidence) Hash() []byte {
|
||||||
|
return []byte(fmt.Sprintf("%d-%d", e.Height_, e.Index_))
|
||||||
|
}
|
||||||
|
func (e MockGoodEvidence) Verify(chainID string) error { return nil }
|
||||||
|
func (e MockGoodEvidence) Equal(ev Evidence) bool {
|
||||||
|
e2 := ev.(MockGoodEvidence)
|
||||||
|
return e.Height_ == e2.Height_ &&
|
||||||
|
bytes.Equal(e.Address_, e2.Address_) &&
|
||||||
|
e.Index_ == e2.Index_
|
||||||
|
}
|
||||||
|
func (e MockGoodEvidence) String() string {
|
||||||
|
return fmt.Sprintf("GoodEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNSTABLE
|
||||||
|
type MockBadEvidence struct {
|
||||||
|
MockGoodEvidence
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e MockBadEvidence) Verify(chainID string) error { return fmt.Errorf("MockBadEvidence") }
|
||||||
|
func (e MockBadEvidence) Equal(ev Evidence) bool {
|
||||||
|
e2 := ev.(MockBadEvidence)
|
||||||
|
return e.Height_ == e2.Height_ &&
|
||||||
|
bytes.Equal(e.Address_, e2.Address_) &&
|
||||||
|
e.Index_ == e2.Index_
|
||||||
|
}
|
||||||
|
func (e MockBadEvidence) String() string {
|
||||||
|
return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user