github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/orderer/sbft/simplebft/testsys_test.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 "crypto/ecdsa" 21 "crypto/elliptic" 22 crand "crypto/rand" 23 "crypto/sha256" 24 "encoding/asn1" 25 "fmt" 26 "math/big" 27 "math/rand" 28 "reflect" 29 "runtime" 30 "time" 31 32 "github.com/golang/protobuf/proto" 33 "github.com/hyperledger/fabric/orderer/common/filter" 34 ) 35 36 const defaultMaxReqCount = uint64(5) 37 38 var maxReqCount uint64 39 40 type testSystemAdapter struct { 41 id uint64 42 sys *testSystem 43 44 // chainId to instance mapping 45 receivers map[string]Receiver 46 batches map[string][]*Batch 47 persistence map[string][]byte 48 49 arrivals map[uint64]time.Duration 50 reqs []*Request 51 52 key *ecdsa.PrivateKey 53 } 54 55 func (t *testSystemAdapter) AddReceiver(chainId string, recv Receiver) { 56 if t.receivers == nil { 57 t.receivers = make(map[string]Receiver) 58 } 59 if t.receivers[chainId] != nil { 60 // remove all events for us 61 t.sys.queue.filter(func(e testElem) bool { 62 switch e := e.ev.(type) { 63 case *testTimer: 64 if e.id == t.id { 65 return false 66 } 67 case *testMsgEvent: 68 if e.dst == t.id { 69 return false 70 } 71 } 72 return true 73 }) 74 } 75 76 t.receivers[chainId] = recv 77 } 78 79 func (t *testSystemAdapter) getArrival(dest uint64) time.Duration { 80 // XXX for now, define fixed variance per destination 81 arr, ok := t.arrivals[dest] 82 if !ok { 83 inflight := 20 * time.Millisecond 84 variance := 1 * time.Millisecond 85 if dest == t.id { 86 inflight = 0 87 } 88 variance = time.Duration(t.sys.rand.Int31n(int32(variance))) 89 arr = inflight + variance 90 t.arrivals[dest] = arr 91 } 92 return arr 93 } 94 95 func (t *testSystemAdapter) Send(chainId string, msg *Msg, dest uint64) { 96 arr := t.getArrival(dest) 97 ev := &testMsgEvent{ 98 inflight: arr, 99 src: t.id, 100 dst: dest, 101 msg: msg, 102 chainId: chainId, 103 } 104 // simulate time for marshalling (and unmarshalling) 105 bytes, _ := proto.Marshal(msg) 106 m2 := &Msg{} 107 _ = proto.Unmarshal(bytes, m2) 108 t.sys.enqueue(arr, ev) 109 } 110 111 type testMsgEvent struct { 112 inflight time.Duration 113 src, dst uint64 114 msg *Msg 115 chainId string 116 } 117 118 func (ev *testMsgEvent) Exec(t *testSystem) { 119 r := t.adapters[ev.dst] 120 if r == nil { 121 testLog.Errorf("message to non-existing %s", ev) 122 return 123 } 124 r.receivers[ev.chainId].Receive(ev.msg, ev.src) 125 } 126 127 func (ev *testMsgEvent) String() string { 128 return fmt.Sprintf("Message<from %d, to %d, inflight %s, %v", 129 ev.src, ev.dst, ev.inflight, ev.msg) 130 } 131 132 type testTimer struct { 133 id uint64 134 tf func() 135 cancelled bool 136 } 137 138 func (t *testTimer) Cancel() { 139 t.cancelled = true 140 } 141 142 func (t *testTimer) Exec(_ *testSystem) { 143 if !t.cancelled { 144 t.tf() 145 } 146 } 147 148 func (t *testTimer) String() string { 149 fun := runtime.FuncForPC(reflect.ValueOf(t.tf).Pointer()).Name() 150 return fmt.Sprintf("Timer<on %d, cancelled %v, fun %s>", t.id, t.cancelled, fun) 151 } 152 153 func (t *testSystemAdapter) Timer(d time.Duration, tf func()) Canceller { 154 tt := &testTimer{id: t.id, tf: tf} 155 if !t.sys.disableTimers { 156 t.sys.enqueue(d, tt) 157 } 158 return tt 159 } 160 161 func (t *testSystemAdapter) Deliver(chainId string, batch *Batch, committer []filter.Committer) { 162 if t.batches == nil { 163 t.batches = make(map[string][]*Batch) 164 } 165 if t.batches[chainId] == nil { 166 t.batches[chainId] = make([]*Batch, 0, 1) 167 } 168 t.batches[chainId] = append(t.batches[chainId], batch) 169 } 170 171 func (t *testSystemAdapter) Validate(chainID string, req *Request) ([][]*Request, [][]filter.Committer, bool) { 172 r := t.reqs 173 if t.reqs == nil || uint64(len(t.reqs)) == maxReqCount-uint64(1) { 174 t.reqs = make([]*Request, 0, maxReqCount-1) 175 } 176 if uint64(len(r)) == maxReqCount-uint64(1) { 177 c := [][]filter.Committer{{}} 178 return [][]*Request{append(r, req)}, c, true 179 } 180 t.reqs = append(t.reqs, req) 181 return nil, nil, true 182 } 183 184 func (t *testSystemAdapter) Cut(chainID string) ([]*Request, []filter.Committer) { 185 r := t.reqs 186 t.reqs = make([]*Request, 0, maxReqCount) 187 return r, []filter.Committer{} 188 } 189 190 func (t *testSystemAdapter) Persist(chainId string, key string, data proto.Message) { 191 compk := fmt.Sprintf("chain-%s-%s", chainId, key) 192 if data == nil { 193 delete(t.persistence, compk) 194 } else { 195 bytes, err := proto.Marshal(data) 196 if err != nil { 197 panic(err) 198 } 199 t.persistence[compk] = bytes 200 } 201 } 202 203 func (t *testSystemAdapter) Restore(chainId string, key string, out proto.Message) bool { 204 compk := fmt.Sprintf("chain-%s-%s", chainId, key) 205 val, ok := t.persistence[compk] 206 if !ok { 207 return false 208 } 209 err := proto.Unmarshal(val, out) 210 return (err == nil) 211 } 212 213 func (t *testSystemAdapter) LastBatch(chainId string) *Batch { 214 if len(t.batches[chainId]) == 0 { 215 return t.receivers[chainId].(*SBFT).makeBatch(0, nil, nil) 216 } 217 return t.batches[chainId][len(t.batches[chainId])-1] 218 } 219 220 func (t *testSystemAdapter) Sign(data []byte) []byte { 221 hash := sha256.Sum256(data) 222 r, s, err := ecdsa.Sign(crand.Reader, t.key, hash[:]) 223 if err != nil { 224 panic(err) 225 } 226 sig, err := asn1.Marshal(struct{ R, S *big.Int }{r, s}) 227 if err != nil { 228 panic(err) 229 } 230 return sig 231 } 232 233 func (t *testSystemAdapter) CheckSig(data []byte, src uint64, sig []byte) error { 234 rs := struct{ R, S *big.Int }{} 235 rest, err := asn1.Unmarshal(sig, &rs) 236 if err != nil { 237 return err 238 } 239 if len(rest) != 0 { 240 return fmt.Errorf("invalid signature") 241 } 242 hash := sha256.Sum256(data) 243 ok := ecdsa.Verify(&t.sys.adapters[src].key.PublicKey, hash[:], rs.R, rs.S) 244 if !ok { 245 return fmt.Errorf("invalid signature") 246 } 247 return nil 248 } 249 250 func (t *testSystemAdapter) Reconnect(chainId string, replica uint64) { 251 testLog.Infof("dropping connection from %d to %d", replica, t.id) 252 t.sys.queue.filter(func(e testElem) bool { 253 switch e := e.ev.(type) { 254 case *testMsgEvent: 255 if e.dst == t.id && e.src == replica { 256 return false 257 } 258 } 259 return true 260 }) 261 arr := t.sys.adapters[replica].arrivals[t.id] * 10 262 t.sys.enqueue(arr, &testTimer{id: t.id, tf: func() { 263 testLog.Infof("reconnecting %d to %d", replica, t.id) 264 t.sys.adapters[replica].receivers[chainId].Connection(t.id) 265 }}) 266 } 267 268 // ============================================== 269 270 type testEvent interface { 271 Exec(t *testSystem) 272 } 273 274 // ============================================== 275 276 type testSystem struct { 277 rand *rand.Rand 278 now time.Duration 279 queue *calendarQueue 280 adapters map[uint64]*testSystemAdapter 281 filterFn func(testElem) (testElem, bool) 282 disableTimers bool 283 } 284 285 type testElem struct { 286 at time.Duration 287 ev testEvent 288 } 289 290 func (t testElem) String() string { 291 return fmt.Sprintf("Event<%s: %s>", t.at, t.ev) 292 } 293 294 func newTestSystem(n uint64) *testSystem { 295 return newTestSystemWithBatchSize(n, defaultMaxReqCount) 296 } 297 298 func newTestSystemWithBatchSize(n uint64, batchSize uint64) *testSystem { 299 return newTestSystemWithParams(n, batchSize, false) 300 } 301 302 func newTestSystemWOTimers(n uint64) *testSystem { 303 return newTestSystemWithParams(n, defaultMaxReqCount, true) 304 } 305 306 func newTestSystemWOTimersWithBatchSize(n uint64, batchSize uint64) *testSystem { 307 return newTestSystemWithParams(n, batchSize, true) 308 } 309 310 func newTestSystemWithParams(n uint64, batchSize uint64, disableTimers bool) *testSystem { 311 maxReqCount = batchSize 312 return &testSystem{ 313 rand: rand.New(rand.NewSource(0)), 314 adapters: make(map[uint64]*testSystemAdapter), 315 queue: newCalendarQueue(time.Millisecond/time.Duration(n*n), int(n*n)), 316 disableTimers: disableTimers, 317 } 318 } 319 320 func (t *testSystem) NewAdapter(id uint64) *testSystemAdapter { 321 key, err := ecdsa.GenerateKey(elliptic.P256(), crand.Reader) 322 if err != nil { 323 panic(err) 324 } 325 a := &testSystemAdapter{ 326 id: id, 327 sys: t, 328 arrivals: make(map[uint64]time.Duration), 329 persistence: make(map[string][]byte), 330 key: key, 331 } 332 t.adapters[id] = a 333 return a 334 } 335 336 func (t *testSystem) enqueue(d time.Duration, ev testEvent) { 337 e := testElem{at: t.now + d, ev: ev} 338 if t.filterFn != nil { 339 var keep bool 340 e, keep = t.filterFn(e) 341 if !keep { 342 return 343 } 344 } 345 testLog.Debugf("enqueuing %s\n", e) 346 t.queue.Add(e) 347 } 348 349 func (t *testSystem) Run() { 350 for { 351 e, ok := t.queue.Pop() 352 if !ok { 353 break 354 } 355 t.now = e.at 356 testLog.Debugf("executing %s\n", e) 357 e.ev.Exec(t) 358 } 359 360 testLog.Debugf("max len: %d", t.queue.maxLen) 361 t.queue.maxLen = 0 362 }