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  }