Browse Source

state: send byzantine validators in BeginBlock

pull/1036/head
Ethan Buchman 7 years ago
parent
commit
28bbeac763
6 changed files with 117 additions and 60 deletions
  1. +2
    -2
      evidence/pool_test.go
  2. +1
    -1
      evidence/reactor_test.go
  3. +11
    -55
      evidence/store_test.go
  4. +8
    -1
      state/execution.go
  5. +48
    -1
      state/execution_test.go
  6. +47
    -0
      types/evidence.go

+ 2
- 2
evidence/pool_test.go View File

@ -53,8 +53,8 @@ func TestEvidencePool(t *testing.T) {
store := NewEvidenceStore(dbm.NewMemDB())
pool := NewEvidencePool(stateDB, store)
goodEvidence := newMockGoodEvidence(height, 0, valAddr)
badEvidence := MockBadEvidence{goodEvidence}
goodEvidence := types.NewMockGoodEvidence(height, 0, valAddr)
badEvidence := types.MockBadEvidence{goodEvidence}
err := pool.AddEvidence(badEvidence)
assert.NotNil(err)


+ 1
- 1
evidence/reactor_test.go View File

@ -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 {
evList := make([]types.Evidence, n)
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)
assert.Nil(t, err)
evList[i] = ev


+ 11
- 55
evidence/store_test.go View File

@ -1,8 +1,6 @@
package evidence
import (
"bytes"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
@ -20,7 +18,7 @@ func TestStoreAddDuplicate(t *testing.T) {
store := NewEvidenceStore(db)
priority := int64(10)
ev := newMockGoodEvidence(2, 1, []byte("val1"))
ev := types.NewMockGoodEvidence(2, 1, []byte("val1"))
added := store.AddNewEvidence(ev, priority)
assert.True(added)
@ -43,7 +41,7 @@ func TestStoreMark(t *testing.T) {
assert.Equal(0, len(pendingEv))
priority := int64(10)
ev := newMockGoodEvidence(2, 1, []byte("val1"))
ev := types.NewMockGoodEvidence(2, 1, []byte("val1"))
added := store.AddNewEvidence(ev, priority)
assert.True(added)
@ -89,15 +87,15 @@ func TestStorePriority(t *testing.T) {
// sorted by priority and then height
cases := []struct {
ev MockGoodEvidence
ev types.MockGoodEvidence
priority int64
}{
{newMockGoodEvidence(2, 1, []byte("val1")), 17},
{newMockGoodEvidence(5, 2, []byte("val2")), 15},
{newMockGoodEvidence(10, 2, []byte("val2")), 13},
{newMockGoodEvidence(100, 2, []byte("val2")), 11},
{newMockGoodEvidence(90, 2, []byte("val2")), 11},
{newMockGoodEvidence(80, 2, []byte("val2")), 11},
{types.NewMockGoodEvidence(2, 1, []byte("val1")), 17},
{types.NewMockGoodEvidence(5, 2, []byte("val2")), 15},
{types.NewMockGoodEvidence(10, 2, []byte("val2")), 13},
{types.NewMockGoodEvidence(100, 2, []byte("val2")), 11},
{types.NewMockGoodEvidence(90, 2, []byte("val2")), 11},
{types.NewMockGoodEvidence(80, 2, []byte("val2")), 11},
}
for _, c := range cases {
@ -119,48 +117,6 @@ const (
var _ = wire.RegisterInterface(
struct{ types.Evidence }{},
wire.ConcreteType{MockGoodEvidence{}, evidenceTypeMockGood},
wire.ConcreteType{MockBadEvidence{}, evidenceTypeMockBad},
wire.ConcreteType{types.MockGoodEvidence{}, evidenceTypeMockGood},
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_)
}

+ 8
- 1
state/execution.go View File

@ -191,13 +191,20 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
}
// 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
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
Hash: block.Hash(),
Header: types.TM2PB.Header(block.Header),
AbsentValidators: absentVals,
ByzantineValidators: nil,
ByzantineValidators: byzantineVals,
})
if err != nil {
logger.Error("Error in proxyAppConn.BeginBlock", "err", err)


+ 48
- 1
state/execution_test.go View File

@ -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
@ -115,7 +160,8 @@ var _ abci.Application = (*testApp)(nil)
type testApp struct {
abci.BaseApplication
AbsentValidators []int32
AbsentValidators []int32
ByzantineValidators []*abci.Evidence
}
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 {
app.AbsentValidators = req.AbsentValidators
app.ByzantineValidators = req.ByzantineValidators
return abci.ResponseBeginBlock{}
}


+ 47
- 0
types/evidence.go View File

@ -167,3 +167,50 @@ func (dve *DuplicateVoteEvidence) Equal(ev Evidence) bool {
// just check their hashes
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_)
}

Loading…
Cancel
Save