github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/orderer/sbft/simplebft/simplebft.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package simplebft 18 19 import ( 20 "fmt" 21 "math" 22 "reflect" 23 "time" 24 25 "github.com/golang/protobuf/proto" 26 "github.com/hyperledger/fabric/orderer/common/filter" 27 "github.com/op/go-logging" 28 ) 29 30 const preprepared string = "preprepared" 31 const prepared string = "prepared" 32 const committed string = "committed" 33 const viewchange string = "viewchange" 34 35 // Receiver defines the API that is exposed by SBFT to the system. 36 type Receiver interface { 37 Receive(msg *Msg, src uint64) 38 Request(req []byte) 39 Connection(replica uint64) 40 GetChainId() string 41 } 42 43 // System defines the API that needs to be provided for SBFT. 44 type System interface { 45 Send(chainId string, msg *Msg, dest uint64) 46 Timer(d time.Duration, f func()) Canceller 47 Deliver(chainId string, batch *Batch, committers []filter.Committer) 48 AddReceiver(chainId string, receiver Receiver) 49 Persist(chainId string, key string, data proto.Message) 50 Restore(chainId string, key string, out proto.Message) bool 51 LastBatch(chainId string) *Batch 52 Sign(data []byte) []byte 53 CheckSig(data []byte, src uint64, sig []byte) error 54 Reconnect(chainId string, replica uint64) 55 Validate(chainID string, req *Request) ([][]*Request, [][]filter.Committer, bool) 56 Cut(chainID string) ([]*Request, []filter.Committer) 57 } 58 59 // Canceller allows cancelling of a scheduled timer event. 60 type Canceller interface { 61 Cancel() 62 } 63 64 // SBFT is a simplified PBFT implementation. 65 type SBFT struct { 66 sys System 67 68 config Config 69 id uint64 70 view uint64 71 batches [][]*Request 72 batchTimer Canceller 73 cur reqInfo 74 activeView bool 75 lastNewViewSent *NewView 76 viewChangeTimeout time.Duration 77 viewChangeTimer Canceller 78 replicaState []replicaInfo 79 pending map[string]*Request 80 validated map[string]bool 81 chainId string 82 primarycommitters [][]filter.Committer 83 } 84 85 type reqInfo struct { 86 subject Subject 87 timeout Canceller 88 preprep *Preprepare 89 prep map[uint64]*Subject 90 commit map[uint64]*Subject 91 checkpoint map[uint64]*Checkpoint 92 prepared bool 93 committed bool 94 checkpointDone bool 95 committers []filter.Committer 96 } 97 98 type replicaInfo struct { 99 backLog []*Msg 100 hello *Hello 101 signedViewchange *Signed 102 viewchange *ViewChange 103 } 104 105 var log = logging.MustGetLogger("sbft") 106 107 type dummyCanceller struct{} 108 109 func (d dummyCanceller) Cancel() {} 110 111 // New creates a new SBFT instance. 112 func New(id uint64, chainID string, config *Config, sys System) (*SBFT, error) { 113 if config.F*3+1 > config.N { 114 return nil, fmt.Errorf("invalid combination of N (%d) and F (%d)", config.N, config.F) 115 } 116 117 s := &SBFT{ 118 config: *config, 119 sys: sys, 120 id: id, 121 chainId: chainID, 122 viewChangeTimer: dummyCanceller{}, 123 replicaState: make([]replicaInfo, config.N), 124 pending: make(map[string]*Request), 125 validated: make(map[string]bool), 126 batches: make([][]*Request, 0, 3), 127 primarycommitters: make([][]filter.Committer, 0), 128 } 129 s.sys.AddReceiver(chainID, s) 130 131 s.view = 0 132 s.cur.subject.Seq = &SeqView{} 133 s.cur.prepared = true 134 s.cur.committed = true 135 s.cur.checkpointDone = true 136 s.cur.timeout = dummyCanceller{} 137 s.activeView = true 138 139 svc := &Signed{} 140 if s.sys.Restore(s.chainId, viewchange, svc) { 141 vc := &ViewChange{} 142 err := proto.Unmarshal(svc.Data, vc) 143 if err != nil { 144 return nil, err 145 } 146 fmt.Println(fmt.Sprintf("rep %d VIEW %d %d", s.id, s.view, vc.View)) 147 s.view = vc.View 148 s.replicaState[s.id].signedViewchange = svc 149 s.activeView = false 150 } 151 152 pp := &Preprepare{} 153 if s.sys.Restore(s.chainId, preprepared, pp) && pp.Seq.View >= s.view { 154 s.view = pp.Seq.View 155 s.activeView = true 156 if pp.Seq.Seq > s.seq() { 157 // TODO double add to BC? 158 _, committers := s.getCommittersFromBatch(pp.Batch) 159 s.acceptPreprepare(pp, committers) 160 } 161 } 162 c := &Subject{} 163 if s.sys.Restore(s.chainId, prepared, c) && reflect.DeepEqual(c, &s.cur.subject) && c.Seq.View >= s.view { 164 s.cur.prepared = true 165 } 166 ex := &Subject{} 167 if s.sys.Restore(s.chainId, committed, ex) && reflect.DeepEqual(c, &s.cur.subject) && ex.Seq.View >= s.view { 168 s.cur.committed = true 169 } 170 171 s.cancelViewChangeTimer() 172 return s, nil 173 } 174 175 //////////////////////////////////////////////// 176 177 func (s *SBFT) GetChainId() string { 178 return s.chainId 179 } 180 181 func (s *SBFT) primaryIDView(v uint64) uint64 { 182 return v % s.config.N 183 } 184 185 func (s *SBFT) primaryID() uint64 { 186 return s.primaryIDView(s.view) 187 } 188 189 func (s *SBFT) isPrimary() bool { 190 return s.primaryID() == s.id 191 } 192 193 func (s *SBFT) seq() uint64 { 194 return s.sys.LastBatch(s.chainId).DecodeHeader().Seq 195 } 196 197 func (s *SBFT) nextSeq() SeqView { 198 return SeqView{Seq: s.seq() + 1, View: s.view} 199 } 200 201 func (s *SBFT) nextView() uint64 { 202 return s.view + 1 203 } 204 205 func (s *SBFT) commonCaseQuorum() int { 206 //When N=3F+1 this should be 2F+1 (N-F) 207 //More generally, we need every two common case quorums of size X to intersect in at least F+1 orderers, 208 //hence 2X>=N+F+1, or X is: 209 return int(math.Ceil(float64(s.config.N+s.config.F+1) / float64(2))) 210 } 211 212 func (s *SBFT) viewChangeQuorum() int { 213 //When N=3F+1 this should be 2F+1 (N-F) 214 //More generally, we need every view change quorum to intersect with every common case quorum at least F+1 orderers, hence: 215 //Y >= N-X+F+1 216 return int(s.config.N+s.config.F+1) - s.commonCaseQuorum() 217 } 218 219 func (s *SBFT) oneCorrectQuorum() int { 220 return int(s.config.F + 1) 221 } 222 223 func (s *SBFT) broadcast(m *Msg) { 224 for i := uint64(0); i < s.config.N; i++ { 225 s.sys.Send(s.chainId, m, i) 226 } 227 } 228 229 //////////////////////////////////////////////// 230 231 // Receive is the ingress method for SBFT messages. 232 func (s *SBFT) Receive(m *Msg, src uint64) { 233 log.Debugf("replica %d: received message from %d: %s", s.id, src, m) 234 235 if h := m.GetHello(); h != nil { 236 s.handleHello(h, src) 237 return 238 } else if req := m.GetRequest(); req != nil { 239 s.handleRequest(req, src) 240 return 241 } else if vs := m.GetViewChange(); vs != nil { 242 s.handleViewChange(vs, src) 243 return 244 } else if nv := m.GetNewView(); nv != nil { 245 s.handleNewView(nv, src) 246 return 247 } 248 249 if s.testBacklogMessage(m, src) { 250 log.Debugf("replica %d: message for future seq, storing for later", s.id) 251 s.recordBacklogMsg(m, src) 252 return 253 } 254 255 s.handleQueueableMessage(m, src) 256 } 257 258 func (s *SBFT) handleQueueableMessage(m *Msg, src uint64) { 259 if pp := m.GetPreprepare(); pp != nil { 260 s.handlePreprepare(pp, src) 261 return 262 } else if p := m.GetPrepare(); p != nil { 263 s.handlePrepare(p, src) 264 return 265 } else if c := m.GetCommit(); c != nil { 266 s.handleCommit(c, src) 267 return 268 } else if c := m.GetCheckpoint(); c != nil { 269 s.handleCheckpoint(c, src) 270 return 271 } 272 273 log.Warningf("replica %d: received invalid message from %d", s.id, src) 274 } 275 276 func (s *SBFT) deliverBatch(batch *Batch, committers []filter.Committer) { 277 if committers == nil { 278 log.Warningf("replica %d: commiter is nil", s.id) 279 panic("Committer is nil.") 280 } 281 s.cur.checkpointDone = true 282 s.cur.timeout.Cancel() 283 // s.primarycommitters[0] 284 s.sys.Deliver(s.chainId, batch, committers) 285 // s.primarycommitters = s.primarycommitters[1:] 286 287 for _, req := range batch.Payloads { 288 key := hash2str(hash(req)) 289 log.Infof("replica %d: attempting to remove %x from pending", s.id, key) 290 delete(s.pending, key) 291 delete(s.validated, key) 292 } 293 }