github.com/cranelv/ethereum_mpc@v0.0.0-20191031014521-23aeb1415092/consensus_pbft/pbft/mock_ledger_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 pbft
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"sync"
    23  	"time"
    24  	"github.com/ethereum/go-ethereum/consensus_pbft/pbftTypes"
    25  	"github.com/ethereum/go-ethereum/consensus_pbft"
    26  	"github.com/ethereum/go-ethereum/consensus_pbft/message"
    27  	"github.com/ethereum/go-ethereum/consensus_pbft/singletons"
    28  )
    29  
    30  type LedgerDirectory interface {
    31  	GetLedgerByPeerID(peerID *pbftTypes.PeerID) (consensus_pbft.ReadOnlyLedger, bool)
    32  }
    33  
    34  type HashLedgerDirectory struct {
    35  	remoteLedgers map[pbftTypes.PeerID]consensus_pbft.ReadOnlyLedger
    36  }
    37  
    38  func (hd *HashLedgerDirectory) GetLedgerByPeerID(peerID *pbftTypes.PeerID) (consensus_pbft.ReadOnlyLedger, bool) {
    39  	ledger, ok := hd.remoteLedgers[*peerID]
    40  	return ledger, ok
    41  }
    42  
    43  func (hd *HashLedgerDirectory) GetPeers() ([]pbftTypes.Peer, error) {
    44  	_, network, err := hd.GetNetworkNodes()
    45  	return network , err
    46  }
    47  
    48  func (hd *HashLedgerDirectory) GetPeerNode() (pbftTypes.Peer, error) {
    49  	self, _, err := hd.GetNetworkNodes()
    50  	return self, err
    51  }
    52  type testPeer struct {
    53  	ID pbftTypes.PeerID
    54  	Type pbftTypes.Peer_Type
    55  }
    56  func(pp* testPeer)GetPeerId() *pbftTypes.PeerID{
    57  	peerID := pbftTypes.PeerID(pp.ID)
    58  	return &peerID
    59  }
    60  func(pp* testPeer)GetType() pbftTypes.Peer_Type{
    61  	return pp.Type
    62  }
    63  
    64  func (hd *HashLedgerDirectory) GetNetworkNodes() (self pbftTypes.Peer, network []pbftTypes.Peer, err error) {
    65  	network = make([]pbftTypes.Peer, len(hd.remoteLedgers)+1)
    66  	i := 0
    67  	for peerID := range hd.remoteLedgers {
    68  		network[i] = &testPeer{
    69  			ID:peerID,
    70  			Type: pbftTypes.Peer_VALIDATOR,
    71  		}
    72  		i++
    73  	}
    74  	peerId := stringToPeerId("self")
    75  	network[i] = &testPeer{
    76  		ID: peerId,
    77  		Type: pbftTypes.Peer_VALIDATOR,
    78  	}
    79  
    80  	self = network[i]
    81  	return
    82  }
    83  
    84  func (hd *HashLedgerDirectory) GetNetworkNodeIDs() (self *pbftTypes.PeerID, network []*pbftTypes.PeerID, err error) {
    85  	oSelf, oNetwork, err := hd.GetNetworkNodes()
    86  	if nil != err {
    87  		return
    88  	}
    89  
    90  	self = oSelf.GetPeerId()
    91  	network = make([]*pbftTypes.PeerID, len(oNetwork))
    92  	for i, endpoint := range oNetwork {
    93  		network[i] = endpoint.GetPeerId()
    94  	}
    95  	return
    96  }
    97  
    98  type MockLedger struct {
    99  	cleanML       *MockLedger
   100  	blocks        map[uint64]*message.StateInfo
   101  	blockHeight   uint64
   102  	remoteLedgers LedgerDirectory
   103  
   104  	mutex *sync.Mutex
   105  
   106  	txID          interface{}
   107  	curBatch      []*message.Task
   108  	curResults    []*message.Result
   109  	preBatchState uint64
   110  
   111  	ce *consumerEndpoint // To support the ExecTx stuff
   112  }
   113  
   114  func NewMockLedger(remoteLedgers LedgerDirectory) *MockLedger {
   115  	mock := &MockLedger{}
   116  	mock.mutex = &sync.Mutex{}
   117  	mock.blocks = make(map[uint64]*message.StateInfo)
   118  	mock.blockHeight = 1
   119  	mock.blocks[0] = &message.StateInfo{Hash:"0x10021",Number:0}
   120  	mock.remoteLedgers = remoteLedgers
   121  
   122  	return mock
   123  }
   124  
   125  func (mock *MockLedger) BeginTaskBatch(id interface{}) error {
   126  	if mock.txID != nil {
   127  		return fmt.Errorf("Tx batch is already active")
   128  	}
   129  	mock.txID = id
   130  	mock.curBatch = nil
   131  	mock.curResults = nil
   132  	return nil
   133  }
   134  
   135  func (mock *MockLedger) Execute(tag interface{}, txs []*message.Task) {
   136  	go func() {
   137  		if mock.txID == nil {
   138  			mock.BeginTaskBatch(mock)
   139  		}
   140  
   141  		_, err := mock.ExecTasks(mock, txs)
   142  		if err != nil {
   143  			panic(err)
   144  		}
   145  		mock.ce.consumer.Executed(tag)
   146  	}()
   147  }
   148  
   149  func (mock *MockLedger) Commit(tag interface{}, meta []byte) {
   150  	go func() {
   151  		_, err := mock.CommitTaskBatch(mock, meta)
   152  		if err != nil {
   153  			panic(err)
   154  		}
   155  		mock.ce.consumer.Committed(tag, mock.GetStateInfo())
   156  	}()
   157  }
   158  
   159  func (mock *MockLedger) Rollback(tag interface{}) {
   160  	go func() {
   161  		mock.RollbackTaskBatch(mock)
   162  		mock.ce.consumer.RolledBack(tag)
   163  	}()
   164  }
   165  
   166  func (mock *MockLedger) ExecTasks(id interface{}, txs []*message.Task) ([]*message.Result, error) {
   167  	if !reflect.DeepEqual(mock.txID, id) {
   168  		return nil, fmt.Errorf("Invalid batch ID")
   169  	}
   170  
   171  	mock.curBatch = append(mock.curBatch, txs...)
   172  	var err error
   173  	var txResult []*message.Result
   174  	if nil != mock.ce && nil != mock.ce.execTasksResult {
   175  		txResult, err = mock.ce.execTasksResult(txs)
   176  	} else {
   177  		// This is basically a default fake default transaction execution
   178  		if nil == txs {
   179  			txs = []*message.Task{{Payload: []byte("DUMMY")}}
   180  		}
   181  
   182  		for _, task := range txs {
   183  			if task.Payload == nil {
   184  				task.Payload = []byte("DUMMY")
   185  			}
   186  
   187  			txResult = append(txResult, &message.Result{task.Type,task.TimeStamp,task.Payload})
   188  		}
   189  
   190  	}
   191  
   192  	mock.curResults = append(mock.curResults, txResult...)
   193  
   194  	return txResult, err
   195  }
   196  
   197  func (mock *MockLedger) CommitTaskBatch(id interface{}, metadata []byte) (*message.StateInfo, error) {
   198  	block, err := mock.commonCommitTx(id, metadata, false)
   199  	if nil == err {
   200  		mock.txID = nil
   201  		mock.curBatch = nil
   202  		mock.curResults = nil
   203  	}
   204  	return &message.StateInfo{Payload:block}, err
   205  }
   206  
   207  func (mock *MockLedger) commonCommitTx(id interface{}, metadata []byte, preview bool) (*message.StateInfo, error) {
   208  	if !reflect.DeepEqual(mock.txID, id) {
   209  		return nil, fmt.Errorf("Invalid batch ID")
   210  	}
   211  
   212  	previousBlockHash := pbftTypes.MessageDigest("Genesis")
   213  	if 0 < mock.blockHeight {
   214  		previousBlock, _ := mock.GetState(mock.blockHeight - 1)
   215  		previousBlockHash, _ = mock.HashBlock(previousBlock)
   216  	}
   217  
   218  	block := &message.Block{
   219  		ConsensusMetadata: metadata,
   220  		PreviousBlockHash: previousBlockHash,
   221  		StateResults:         mock.curResults, // Use the current result output in the hash
   222  		Tasks:      mock.curBatch,
   223  	}
   224  
   225  	if !preview {
   226  		hash, _ := mock.HashBlock(&message.StateInfo{Number : mock.blockHeight,Payload:block})
   227  		fmt.Printf("TEST LEDGER: Mock ledger is inserting block %d with hash %x\n", mock.blockHeight, hash)
   228  		mock.blocks[mock.blockHeight] = &message.StateInfo{Number : mock.blockHeight,Hash:hash,Payload:block}
   229  		mock.blockHeight++
   230  	}
   231  
   232  	return mock.blocks[mock.blockHeight], nil
   233  }
   234  
   235  func (mock *MockLedger) PreviewCommitTaskBatch(id interface{}, metadata []byte) ([]byte, error) {
   236  	b, err := mock.commonCommitTx(id, metadata, true)
   237  	if err != nil {
   238  		return nil, err
   239  	}
   240  	return mock.getBlockInfoBlob(mock.blockHeight+1, b), nil
   241  }
   242  
   243  func (mock *MockLedger) RollbackTaskBatch(id interface{}) error {
   244  	if !reflect.DeepEqual(mock.txID, id) {
   245  		return fmt.Errorf("Invalid batch ID")
   246  	}
   247  	mock.curBatch = nil
   248  	mock.curResults = nil
   249  	mock.txID = nil
   250  	return nil
   251  }
   252  
   253  func (mock *MockLedger) GetBlockchainSize() uint64 {
   254  	mock.mutex.Lock()
   255  	defer func() {
   256  		mock.mutex.Unlock()
   257  	}()
   258  	return mock.blockHeight
   259  }
   260  
   261  func (mock *MockLedger) GetState(id uint64) (*message.StateInfo, error) {
   262  	mock.mutex.Lock()
   263  	defer func() {
   264  		mock.mutex.Unlock()
   265  	}()
   266  	block, ok := mock.blocks[id]
   267  	if !ok {
   268  		return nil, fmt.Errorf("Block not found")
   269  	}
   270  	return block, nil
   271  }
   272  
   273  func (mock *MockLedger) HashBlock(block *message.StateInfo) (pbftTypes.MessageDigest, error) {
   274  	block.Hash = singletons.Hasher.Hash(block)
   275  	return block.Hash,nil
   276  }
   277  
   278  func (mock *MockLedger) GetStateInfo() *message.StateInfo {
   279  	b, _ := mock.GetState(mock.blockHeight - 1)
   280  	return  b
   281  }
   282  
   283  func (mock *MockLedger) GetBlockchainInfoBlob() []byte {
   284  	b, _ := mock.GetState(mock.blockHeight - 1)
   285  	return mock.getBlockInfoBlob(mock.blockHeight, b)
   286  }
   287  
   288  func (mock *MockLedger) getBlockInfoBlob(height uint64, block *message.StateInfo) []byte {
   289  	h, _ := singletons.Marshaler.Marshal(block)
   290  	return h
   291  }
   292  
   293  func (mock *MockLedger) GetBlockHeadMetadata() ([]byte, error) {
   294  	b, ok := mock.blocks[mock.blockHeight-1]
   295  	if !ok {
   296  		return nil, fmt.Errorf("could not retrieve block from mock ledger")
   297  	}
   298  	block := b.Payload.(*message.Block)
   299  	return block.ConsensusMetadata, nil
   300  }
   301  
   302  func (mock *MockLedger) simulateStateTransfer(info *message.StateInfo, peers []*pbftTypes.PeerID) {
   303  	if mock.blockHeight >= info.Height() && info.Height()>0 {
   304  		blockCursor := info.Height() - 1
   305  		validHash := info.Digest()
   306  		for {
   307  			info, ok := mock.blocks[blockCursor]
   308  			if !ok {
   309  				break
   310  			}
   311  			hash, _ := mock.HashBlock(info)
   312  			if hash == validHash {
   313  				break
   314  			}
   315  			blockCursor--
   316  			block := info.Payload.(*message.Block)
   317  			validHash = block.PreviousBlockHash
   318  			if blockCursor == ^uint64(0) {
   319  				return
   320  			}
   321  		}
   322  		panic(fmt.Sprintf("Asked to skip to a block (%d) which is lower than our current height of %d.  (Corrupt block at %d with hash %x)", info.Height, mock.blockHeight, blockCursor, validHash))
   323  	}
   324  
   325  	var remoteLedger consensus_pbft.ReadOnlyLedger
   326  	if len(peers) > 0 {
   327  		var ok bool
   328  		remoteLedger, ok = mock.remoteLedgers.GetLedgerByPeerID(peers[0])
   329  		if !ok {
   330  			panic("Asked for results from a peer which does not exist")
   331  		}
   332  	} else {
   333  //		panic("TODO, support state transfer from nil peers")
   334  	}
   335  	fmt.Printf("TEST LEDGER skipping to %+v", info)
   336  	p := 0
   337  	for n := mock.blockHeight; n < info.Height(); n++ {
   338  		block, err := remoteLedger.GetState(n)
   339  
   340  		if nil != err {
   341  			n--
   342  			fmt.Printf("TEST LEDGER: Block not ready yet")
   343  			time.Sleep(100 * time.Millisecond)
   344  			p++
   345  			if p > 10 {
   346  				panic("Tried to get a block 10 times, no luck")
   347  			}
   348  			continue
   349  		}
   350  
   351  		mock.blocks[n] = block
   352  	}
   353  	mock.blockHeight = info.Height()
   354  }