Skip to content

Commit

Permalink
fix sbft primary crashing a correct replica
Browse files Browse the repository at this point in the history
A replica getting a checkpoint that does not match its preprepare should
not kill itself, as primary could be Byzantine.

Added a test case failing before which is fixed now.

Change-Id: I04deb5b063d3ccba14c0fbf21522b02cb600ad1c
Signed-off-by: Marko Vukolic <mvu@zurich.ibm.com>
  • Loading branch information
Marko Vukolic committed Dec 20, 2016
1 parent 0b98143 commit 5314ea2
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 3 deletions.
7 changes: 4 additions & 3 deletions orderer/sbft/simplebft/checkpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ func (s *SBFT) handleCheckpoint(c *Checkpoint, src uint64) {
c = s.cur.checkpoint[replicas[0]]

if !reflect.DeepEqual(c.Digest, s.cur.subject.Digest) {
log.Fatalf("replica %d: weak checkpoint %x does not match our state %x",
s.id, c.Digest, s.cur.subject.Digest)
// NOT REACHED
log.Warningf("replica %d: weak checkpoint %x does not match our state %x --- primary %d of view %d is probably Byzantine, sending view change",
s.id, c.Digest, s.cur.subject.Digest, s.primaryID(), s.view)
s.sendViewChange()
return
}

// ignore null requests
Expand Down
49 changes: 49 additions & 0 deletions orderer/sbft/simplebft/simplebft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,55 @@ func TestByzPrimary(t *testing.T) {
}
}

func TestByzPrimaryBullyingSingleReplica(t *testing.T) {
skipInShortMode(t)
N := uint64(10)
sys := newTestSystem(N)
var repls []*SBFT
var adapters []*testSystemAdapter
for i := uint64(0); i < N; i++ {
a := sys.NewAdapter(i)
s, err := New(i, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a)
if err != nil {
t.Fatal(err)
}
repls = append(repls, s)
adapters = append(adapters, a)
}

r1 := []byte{1, 2, 3}
r2 := []byte{5, 6, 7}

// change preprepare to 1
sys.filterFn = func(e testElem) (testElem, bool) {
if msg, ok := e.ev.(*testMsgEvent); ok {
if pp := msg.msg.GetPreprepare(); pp != nil && msg.src == 0 && msg.dst == 1 {
pp := *pp
batch := *pp.Batch
batch.Payloads = [][]byte{r2}
pp.Batch = &batch
h := merkleHashData(batch.Payloads)
bh := &BatchHeader{}
proto.Unmarshal(pp.Batch.Header, bh)
bh.DataHash = h
bhraw, _ := proto.Marshal(bh)
pp.Batch.Header = bhraw
msg.msg = &Msg{&Msg_Preprepare{&pp}}
}
}
return e, true
}

connectAll(sys)
repls[0].Request(r1)
sys.Run()
for _, a := range adapters {
if a.id != 1 && len(a.batches) != 1 {
t.Fatal("expected execution of 1 batch at all except replica 1")
}
}
}

func TestViewChange(t *testing.T) {
skipInShortMode(t)
N := uint64(4)
Expand Down

0 comments on commit 5314ea2

Please sign in to comment.