Skip to content

Commit 6657459

Browse files
Marko Vukolicgaborh-da
Marko Vukolic
authored andcommitted
[FAB-1840] Refactor SBFT blockcutter support
This commit - renames Ordered to Validate in System, - uses a string -> bool map to store validated requests, - adds requests to that map in pending iteration (this was missing), - changes block cutter induced panics into viewchanges (for non-primary peers). Change-Id: Ie108f9cc9cc20a26253764d29745c281ad841357 Signed-off-by: Marko Vukolic <[email protected]> Signed-off-by: Gabor Hosszu <[email protected]>
1 parent dffcaf4 commit 6657459

File tree

8 files changed

+61
-70
lines changed

8 files changed

+61
-70
lines changed

orderer/sbft/backend/backend.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func (b *Backend) AddSbftPeer(chainID string, support multichain.ConsenterSuppor
247247
return s.New(b.GetMyId(), chainID, config, b)
248248
}
249249

250-
func (b *Backend) Ordered(chainID string, req *s.Request) ([][]*s.Request, [][]filter.Committer, bool) {
250+
func (b *Backend) Validate(chainID string, req *s.Request) ([][]*s.Request, [][]filter.Committer, bool) {
251251
// ([][]*cb.Envelope, [][]filter.Committer, bool) {
252252
// If the message is a valid normal message and fills a batch, the batch, committers, true is returned
253253
// If the message is a valid special message (like a config message) it terminates the current batch

orderer/sbft/simplebft/batch.go

+29
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"reflect"
2222

2323
"github.com/golang/protobuf/proto"
24+
"github.com/hyperledger/fabric/orderer/common/filter"
2425
)
2526

2627
func (s *SBFT) makeBatch(seq uint64, prevHash []byte, data [][]byte) *Batch {
@@ -90,3 +91,31 @@ func (b *Batch) DecodeHeader() *BatchHeader {
9091

9192
return batchheader
9293
}
94+
95+
func (s *SBFT) getCommittersFromBatch(reqBatch *Batch) (bool, []filter.Committer) {
96+
reqs := make([]*Request, 0, len(reqBatch.Payloads))
97+
for _, pl := range reqBatch.Payloads {
98+
req := &Request{Payload: pl}
99+
reqs = append(reqs, req)
100+
}
101+
batches := make([][]*Request, 0, 1)
102+
comms := [][]filter.Committer{}
103+
for _, r := range reqs {
104+
b, c, valid := s.sys.Validate(s.chainId, r)
105+
if !valid {
106+
return false, nil
107+
}
108+
batches = append(batches, b...)
109+
comms = append(comms, c...)
110+
}
111+
if len(batches) > 1 || len(batches) != len(comms) {
112+
return false, nil
113+
}
114+
115+
if len(batches) == 0 {
116+
_, committer := s.sys.Cut(s.chainId)
117+
return true, committer
118+
} else {
119+
return true, comms[0]
120+
}
121+
}

orderer/sbft/simplebft/connection.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (s *SBFT) handleHello(h *Hello, src uint64) {
7575

7676
if s.sys.LastBatch(s.chainId).DecodeHeader().Seq < bh.Seq {
7777
log.Debugf("replica %d: delivering batches %d after hello from replica %d", s.id, bh.Seq, src)
78-
blockOK, committers := s.getCommittersFromBlockCutter(h.Batch)
78+
blockOK, committers := s.getCommittersFromBatch(h.Batch)
7979
if blockOK {
8080
s.deliverBatch(h.Batch, committers)
8181
} else {

orderer/sbft/simplebft/newview.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func (s *SBFT) handleNewView(nv *NewView, src uint64) {
159159
}
160160
}
161161
// TODO we should not do this here, as prevBatch was already delivered
162-
blockOK, committers := s.getCommittersFromBlockCutter(prevBatch)
162+
blockOK, committers := s.getCommittersFromBatch(prevBatch)
163163
if !blockOK {
164164
log.Panic("Replica %d: our last checkpointed batch is erroneous (block cutter).", s.id)
165165
}
@@ -180,9 +180,10 @@ func (s *SBFT) handleNewView(nv *NewView, src uint64) {
180180
Seq: &SeqView{Seq: nv.Batch.DecodeHeader().Seq, View: s.view},
181181
Batch: nv.Batch,
182182
}
183-
blockOK, committers := s.getCommittersFromBlockCutter(nv.Batch)
183+
blockOK, committers := s.getCommittersFromBatch(nv.Batch)
184184
if !blockOK {
185-
log.Panic("Replica %d: new view %d batch erroneous (block cutter).", s.id, nv.View)
185+
log.Debugf("Replica %d: new view %d batch erroneous (block cutter).", s.id, nv.View)
186+
s.sendViewChange()
186187
}
187188

188189
s.handleCheckedPreprepare(pp, committers)

orderer/sbft/simplebft/preprepare.go

+7-49
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,13 @@ func (s *SBFT) handlePreprepare(pp *Preprepare, src uint64) {
7878
log.Infof("replica %d: preprepare batches prev hash does not match expected %s, got %s", s.id, hash2str(batchheader.PrevHash), hash2str(prevhash))
7979
return
8080
}
81-
committers := s.getCommitters(pp)
81+
82+
blockOK, committers := s.getCommittersFromBatch(pp.Batch)
83+
if !blockOK {
84+
log.Debugf("Replica %d found Byzantine block in preprepare, Seq: %d View: %d", s.id, pp.Seq.Seq, pp.Seq.View)
85+
s.sendViewChange()
86+
return
87+
}
8288
log.Infof("replica %d: handlePrepare", s.id)
8389
s.handleCheckedPreprepare(pp, committers)
8490
}
@@ -100,26 +106,6 @@ func (s *SBFT) acceptPreprepare(pp *Preprepare, committers []filter.Committer) {
100106
}
101107
}
102108

103-
func (s *SBFT) getCommitters(pp *Preprepare) []filter.Committer {
104-
// if we are the primary, we can be sure the block is OK
105-
// and we also have the committers
106-
// TODO what to do with the remaining ones???
107-
// how to mantain the mapping between batches and committers?
108-
var committers []filter.Committer
109-
110-
if !s.isPrimary() {
111-
blockOK, allcommitters := s.getCommittersFromBlockCutter(pp.Batch)
112-
if !blockOK {
113-
log.Panicf("Replica %d found Byzantine block, Seq: %d View: %d", s.id, pp.Seq.Seq, pp.Seq.View)
114-
}
115-
committers = allcommitters
116-
} else {
117-
committers = s.primarycommitters[0]
118-
s.primarycommitters = s.primarycommitters[1:]
119-
}
120-
return committers
121-
}
122-
123109
func (s *SBFT) handleCheckedPreprepare(pp *Preprepare, committers []filter.Committer) {
124110
s.acceptPreprepare(pp, committers)
125111
if !s.isPrimary() {
@@ -130,34 +116,6 @@ func (s *SBFT) handleCheckedPreprepare(pp *Preprepare, committers []filter.Commi
130116
s.maybeSendCommit()
131117
}
132118

133-
func (s *SBFT) getCommittersFromBlockCutter(reqBatch *Batch) (bool, []filter.Committer) {
134-
reqs := make([]*Request, 0, len(reqBatch.Payloads))
135-
for _, pl := range reqBatch.Payloads {
136-
req := &Request{Payload: pl}
137-
reqs = append(reqs, req)
138-
}
139-
batches := make([][]*Request, 0, 1)
140-
comms := [][]filter.Committer{}
141-
for _, r := range reqs {
142-
b, c, accepted := s.sys.Ordered(s.chainId, r)
143-
if !accepted {
144-
return false, nil
145-
}
146-
batches = append(batches, b...)
147-
comms = append(comms, c...)
148-
}
149-
if len(batches) > 1 || len(batches) != len(comms) {
150-
return false, nil
151-
}
152-
153-
if len(batches) == 0 {
154-
_, committer := s.sys.Cut(s.chainId)
155-
return true, committer
156-
} else {
157-
return true, comms[0]
158-
}
159-
}
160-
161119
////////////////////////////////////////////////
162120

163121
func (s *SBFT) requestTimeout() {

orderer/sbft/simplebft/request.go

+13-10
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ func (s *SBFT) handleRequest(req *Request, src uint64) {
3131
log.Infof("replica %d: inserting %x into pending", s.id, key)
3232
s.pending[key] = req
3333
if s.isPrimary() && s.activeView {
34-
s.passedToBC[key] = req
35-
batches, committers, accepted := s.sys.Ordered(s.chainId, req)
36-
if !accepted {
34+
batches, committers, valid := s.sys.Validate(s.chainId, req)
35+
if !valid {
3736
// this one is problematic, lets skip it
37+
delete(s.pending, key)
3838
return
3939
}
40+
s.validated[key] = valid
4041
if len(batches) == 0 {
4142
s.startBatchTimer()
4243
} else {
@@ -90,23 +91,25 @@ func (s *SBFT) maybeSendNextBatch() {
9091
if len(s.batches) == 0 {
9192
hasPending := len(s.pending) != 0
9293
for k, req := range s.pending {
93-
if s.passedToBC[k] == nil {
94-
batches, committers, accepted := s.sys.Ordered(s.chainId, req)
94+
if s.validated[k] == false {
95+
batches, committers, valid := s.sys.Validate(s.chainId, req)
9596
s.batches = append(s.batches, batches...)
9697
s.primarycommitters = append(s.primarycommitters, committers...)
97-
if !accepted {
98+
if !valid {
9899
log.Panicf("Replica %d: one of our own pending requests is erroneous.", s.id)
100+
delete(s.pending, k)
101+
continue
99102
}
103+
s.validated[k] = true
100104
}
101105
}
102106
if len(s.batches) == 0 {
103-
// if we have no pending, every req was included
104-
// in a batches
107+
// if we have no pending, every req was included in batches
105108
if !hasPending {
106109
return
107110
}
108-
// we have pending reqs that were just send to BC or
109-
// were already sent (they are in passedToBC)
111+
// we have pending reqs that were just sent for validation or
112+
// were already sent (they are in s.validated)
110113
batch, committers := s.sys.Cut(s.chainId)
111114
s.batches = append(s.batches, batch)
112115
s.primarycommitters = append(s.primarycommitters, committers)

orderer/sbft/simplebft/simplebft.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type System interface {
5252
Sign(data []byte) []byte
5353
CheckSig(data []byte, src uint64, sig []byte) error
5454
Reconnect(chainId string, replica uint64)
55-
Ordered(chainID string, req *Request) ([][]*Request, [][]filter.Committer, bool)
55+
Validate(chainID string, req *Request) ([][]*Request, [][]filter.Committer, bool)
5656
Cut(chainID string) ([]*Request, []filter.Committer)
5757
}
5858

@@ -77,7 +77,7 @@ type SBFT struct {
7777
viewChangeTimer Canceller
7878
replicaState []replicaInfo
7979
pending map[string]*Request
80-
passedToBC map[string]*Request
80+
validated map[string]bool
8181
chainId string
8282
primarycommitters [][]filter.Committer
8383
}
@@ -122,7 +122,7 @@ func New(id uint64, chainID string, config *Config, sys System) (*SBFT, error) {
122122
viewChangeTimer: dummyCanceller{},
123123
replicaState: make([]replicaInfo, config.N),
124124
pending: make(map[string]*Request),
125-
passedToBC: make(map[string]*Request),
125+
validated: make(map[string]bool),
126126
batches: make([][]*Request, 0, 3),
127127
primarycommitters: make([][]filter.Committer, 0),
128128
}
@@ -155,7 +155,7 @@ func New(id uint64, chainID string, config *Config, sys System) (*SBFT, error) {
155155
s.activeView = true
156156
if pp.Seq.Seq > s.seq() {
157157
// TODO double add to BC?
158-
_, committers := s.getCommittersFromBlockCutter(pp.Batch)
158+
_, committers := s.getCommittersFromBatch(pp.Batch)
159159
s.acceptPreprepare(pp, committers)
160160
}
161161
}
@@ -288,6 +288,6 @@ func (s *SBFT) deliverBatch(batch *Batch, committers []filter.Committer) {
288288
key := hash2str(hash(req))
289289
log.Infof("replica %d: attempting to remove %x from pending", s.id, key)
290290
delete(s.pending, key)
291-
delete(s.passedToBC, key)
291+
delete(s.validated, key)
292292
}
293293
}

orderer/sbft/simplebft/testsys_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func (t *testSystemAdapter) Deliver(chainId string, batch *Batch, committer []fi
168168
t.batches[chainId] = append(t.batches[chainId], batch)
169169
}
170170

171-
func (t *testSystemAdapter) Ordered(chainID string, req *Request) ([][]*Request, [][]filter.Committer, bool) {
171+
func (t *testSystemAdapter) Validate(chainID string, req *Request) ([][]*Request, [][]filter.Committer, bool) {
172172
r := t.reqs
173173
if t.reqs == nil || uint64(len(t.reqs)) == maxReqCount-uint64(1) {
174174
t.reqs = make([]*Request, 0, maxReqCount-1)

0 commit comments

Comments
 (0)