github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/core/chaincode/shim/mockstub.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 shim provides APIs for the chaincode to access its state
    18  // variables, transaction context and call other chaincodes.
    19  package shim
    20  
    21  import (
    22  	"container/list"
    23  	"errors"
    24  	"fmt"
    25  	"strings"
    26  
    27  	"github.com/golang/protobuf/ptypes/timestamp"
    28  	pb "github.com/hyperledger/fabric/protos/peer"
    29  	"github.com/op/go-logging"
    30  )
    31  
    32  // Logger for the shim package.
    33  var mockLogger = logging.MustGetLogger("mock")
    34  
    35  // MockStub is an implementation of ChaincodeStubInterface for unit testing chaincode.
    36  // Use this instead of ChaincodeStub in your chaincode's unit test calls to Init or Invoke.
    37  type MockStub struct {
    38  	// arguments the stub was called with
    39  	args [][]byte
    40  
    41  	// A pointer back to the chaincode that will invoke this, set by constructor.
    42  	// If a peer calls this stub, the chaincode will be invoked from here.
    43  	cc Chaincode
    44  
    45  	// A nice name that can be used for logging
    46  	Name string
    47  
    48  	// State keeps name value pairs
    49  	State map[string][]byte
    50  
    51  	// Keys stores the list of mapped values in lexical order
    52  	Keys *list.List
    53  
    54  	// registered list of other MockStub chaincodes that can be called from this MockStub
    55  	Invokables map[string]*MockStub
    56  
    57  	// stores a transaction uuid while being Invoked / Deployed
    58  	// TODO if a chaincode uses recursion this may need to be a stack of TxIDs or possibly a reference counting map
    59  	TxID string
    60  }
    61  
    62  func (stub *MockStub) GetTxID() string {
    63  	return stub.TxID
    64  }
    65  
    66  func (stub *MockStub) GetArgs() [][]byte {
    67  	return stub.args
    68  }
    69  
    70  func (stub *MockStub) GetStringArgs() []string {
    71  	args := stub.GetArgs()
    72  	strargs := make([]string, 0, len(args))
    73  	for _, barg := range args {
    74  		strargs = append(strargs, string(barg))
    75  	}
    76  	return strargs
    77  }
    78  
    79  func (stub *MockStub) GetFunctionAndParameters() (function string, params []string) {
    80  	allargs := stub.GetStringArgs()
    81  	function = ""
    82  	params = []string{}
    83  	if len(allargs) >= 1 {
    84  		function = allargs[0]
    85  		params = allargs[1:]
    86  	}
    87  	return
    88  }
    89  
    90  // Used to indicate to a chaincode that it is part of a transaction.
    91  // This is important when chaincodes invoke each other.
    92  // MockStub doesn't support concurrent transactions at present.
    93  func (stub *MockStub) MockTransactionStart(txid string) {
    94  	stub.TxID = txid
    95  }
    96  
    97  // End a mocked transaction, clearing the UUID.
    98  func (stub *MockStub) MockTransactionEnd(uuid string) {
    99  	stub.TxID = ""
   100  }
   101  
   102  // Register a peer chaincode with this MockStub
   103  // invokableChaincodeName is the name or hash of the peer
   104  // otherStub is a MockStub of the peer, already intialised
   105  func (stub *MockStub) MockPeerChaincode(invokableChaincodeName string, otherStub *MockStub) {
   106  	stub.Invokables[invokableChaincodeName] = otherStub
   107  }
   108  
   109  // Initialise this chaincode,  also starts and ends a transaction.
   110  func (stub *MockStub) MockInit(uuid string, args [][]byte) pb.Response {
   111  	stub.args = args
   112  	stub.MockTransactionStart(uuid)
   113  	res := stub.cc.Init(stub)
   114  	stub.MockTransactionEnd(uuid)
   115  	return res
   116  }
   117  
   118  // Invoke this chaincode, also starts and ends a transaction.
   119  func (stub *MockStub) MockInvoke(uuid string, args [][]byte) pb.Response {
   120  	stub.args = args
   121  	stub.MockTransactionStart(uuid)
   122  	res := stub.cc.Invoke(stub)
   123  	stub.MockTransactionEnd(uuid)
   124  	return res
   125  }
   126  
   127  // GetState retrieves the value for a given key from the ledger
   128  func (stub *MockStub) GetState(key string) ([]byte, error) {
   129  	value := stub.State[key]
   130  	mockLogger.Debug("MockStub", stub.Name, "Getting", key, value)
   131  	return value, nil
   132  }
   133  
   134  // PutState writes the specified `value` and `key` into the ledger.
   135  func (stub *MockStub) PutState(key string, value []byte) error {
   136  	if stub.TxID == "" {
   137  		mockLogger.Error("Cannot PutState without a transactions - call stub.MockTransactionStart()?")
   138  		return errors.New("Cannot PutState without a transactions - call stub.MockTransactionStart()?")
   139  	}
   140  
   141  	mockLogger.Debug("MockStub", stub.Name, "Putting", key, value)
   142  	stub.State[key] = value
   143  
   144  	// insert key into ordered list of keys
   145  	for elem := stub.Keys.Front(); elem != nil; elem = elem.Next() {
   146  		elemValue := elem.Value.(string)
   147  		comp := strings.Compare(key, elemValue)
   148  		mockLogger.Debug("MockStub", stub.Name, "Compared", key, elemValue, " and got ", comp)
   149  		if comp < 0 {
   150  			// key < elem, insert it before elem
   151  			stub.Keys.InsertBefore(key, elem)
   152  			mockLogger.Debug("MockStub", stub.Name, "Key", key, " inserted before", elem.Value)
   153  			break
   154  		} else if comp == 0 {
   155  			// keys exists, no need to change
   156  			mockLogger.Debug("MockStub", stub.Name, "Key", key, "already in State")
   157  			break
   158  		} else { // comp > 0
   159  			// key > elem, keep looking unless this is the end of the list
   160  			if elem.Next() == nil {
   161  				stub.Keys.PushBack(key)
   162  				mockLogger.Debug("MockStub", stub.Name, "Key", key, "appended")
   163  				break
   164  			}
   165  		}
   166  	}
   167  
   168  	// special case for empty Keys list
   169  	if stub.Keys.Len() == 0 {
   170  		stub.Keys.PushFront(key)
   171  		mockLogger.Debug("MockStub", stub.Name, "Key", key, "is first element in list")
   172  	}
   173  
   174  	return nil
   175  }
   176  
   177  // DelState removes the specified `key` and its value from the ledger.
   178  func (stub *MockStub) DelState(key string) error {
   179  	mockLogger.Debug("MockStub", stub.Name, "Deleting", key, stub.State[key])
   180  	delete(stub.State, key)
   181  
   182  	for elem := stub.Keys.Front(); elem != nil; elem = elem.Next() {
   183  		if strings.Compare(key, elem.Value.(string)) == 0 {
   184  			stub.Keys.Remove(elem)
   185  		}
   186  	}
   187  
   188  	return nil
   189  }
   190  
   191  func (stub *MockStub) GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error) {
   192  	return NewMockStateRangeQueryIterator(stub, startKey, endKey), nil
   193  }
   194  
   195  // GetQueryResult function can be invoked by a chaincode to perform a
   196  // rich query against state database.  Only supported by state database implementations
   197  // that support rich query.  The query string is in the syntax of the underlying
   198  // state database. An iterator is returned which can be used to iterate (next) over
   199  // the query result set
   200  func (stub *MockStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) {
   201  	// Not implemented since the mock engine does not have a query engine.
   202  	// However, a very simple query engine that supports string matching
   203  	// could be implemented to test that the framework supports queries
   204  	return nil, errors.New("Not Implemented")
   205  }
   206  
   207  // GetHistoryForKey function can be invoked by a chaincode to return a history of
   208  // key values across time. GetHistoryForKey is intended to be used for read-only queries.
   209  func (stub *MockStub) GetHistoryForKey(key string) (StateQueryIteratorInterface, error) {
   210  	return nil, errors.New("Not Implemented")
   211  }
   212  
   213  //GetStateByPartialCompositeKey function can be invoked by a chaincode to query the
   214  //state based on a given partial composite key. This function returns an
   215  //iterator which can be used to iterate over all composite keys whose prefix
   216  //matches the given partial composite key. This function should be used only for
   217  //a partial composite key. For a full composite key, an iter with empty response
   218  //would be returned.
   219  func (stub *MockStub) GetStateByPartialCompositeKey(objectType string, attributes []string) (StateQueryIteratorInterface, error) {
   220  	return getStateByPartialCompositeKey(stub, objectType, attributes)
   221  }
   222  
   223  // CreateCompositeKey combines the list of attributes
   224  //to form a composite key.
   225  func (stub *MockStub) CreateCompositeKey(objectType string, attributes []string) (string, error) {
   226  	return createCompositeKey(objectType, attributes)
   227  }
   228  
   229  // SplitCompositeKey splits the composite key into attributes
   230  // on which the composite key was formed.
   231  func (stub *MockStub) SplitCompositeKey(compositeKey string) (string, []string, error) {
   232  	return splitCompositeKey(compositeKey)
   233  }
   234  
   235  // InvokeChaincode calls a peered chaincode.
   236  // E.g. stub1.InvokeChaincode("stub2Hash", funcArgs, channel)
   237  // Before calling this make sure to create another MockStub stub2, call stub2.MockInit(uuid, func, args)
   238  // and register it with stub1 by calling stub1.MockPeerChaincode("stub2Hash", stub2)
   239  func (stub *MockStub) InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response {
   240  	// Internally we use chaincode name as a composite name
   241  	if channel != "" {
   242  		chaincodeName = chaincodeName + "/" + channel
   243  	}
   244  	// TODO "args" here should possibly be a serialized pb.ChaincodeInput
   245  	otherStub := stub.Invokables[chaincodeName]
   246  	mockLogger.Debug("MockStub", stub.Name, "Invoking peer chaincode", otherStub.Name, args)
   247  	//	function, strings := getFuncArgs(args)
   248  	res := otherStub.MockInvoke(stub.TxID, args)
   249  	mockLogger.Debug("MockStub", stub.Name, "Invoked peer chaincode", otherStub.Name, "got", fmt.Sprintf("%+v", res))
   250  	return res
   251  }
   252  
   253  // Not implemented
   254  func (stub *MockStub) GetCreator() ([]byte, error) {
   255  	return nil, nil
   256  }
   257  
   258  // Not implemented
   259  func (stub *MockStub) GetTransient() (map[string][]byte, error) {
   260  	return nil, nil
   261  }
   262  
   263  // Not implemented
   264  func (stub *MockStub) GetBinding() ([]byte, error) {
   265  	return nil, nil
   266  }
   267  
   268  // Not implemented
   269  func (stub *MockStub) GetArgsSlice() ([]byte, error) {
   270  	return nil, nil
   271  }
   272  
   273  // Not implemented
   274  func (stub *MockStub) GetTxTimestamp() (*timestamp.Timestamp, error) {
   275  	return nil, nil
   276  }
   277  
   278  // Not implemented
   279  func (stub *MockStub) SetEvent(name string, payload []byte) error {
   280  	return nil
   281  }
   282  
   283  // Constructor to initialise the internal State map
   284  func NewMockStub(name string, cc Chaincode) *MockStub {
   285  	mockLogger.Debug("MockStub(", name, cc, ")")
   286  	s := new(MockStub)
   287  	s.Name = name
   288  	s.cc = cc
   289  	s.State = make(map[string][]byte)
   290  	s.Invokables = make(map[string]*MockStub)
   291  	s.Keys = list.New()
   292  
   293  	return s
   294  }
   295  
   296  /*****************************
   297   Range Query Iterator
   298  *****************************/
   299  
   300  type MockStateRangeQueryIterator struct {
   301  	Closed   bool
   302  	Stub     *MockStub
   303  	StartKey string
   304  	EndKey   string
   305  	Current  *list.Element
   306  }
   307  
   308  // HasNext returns true if the range query iterator contains additional keys
   309  // and values.
   310  func (iter *MockStateRangeQueryIterator) HasNext() bool {
   311  	if iter.Closed {
   312  		// previously called Close()
   313  		mockLogger.Error("HasNext() but already closed")
   314  		return false
   315  	}
   316  
   317  	if iter.Current == nil {
   318  		mockLogger.Error("HasNext() couldn't get Current")
   319  		return false
   320  	}
   321  
   322  	current := iter.Current
   323  	for current != nil {
   324  		// if this is an open-ended query for all keys, return true
   325  		if iter.StartKey == "" && iter.EndKey == "" {
   326  			return true
   327  		}
   328  		comp1 := strings.Compare(current.Value.(string), iter.StartKey)
   329  		comp2 := strings.Compare(current.Value.(string), iter.EndKey)
   330  		if comp1 >= 0 {
   331  			if comp2 <= 0 {
   332  				mockLogger.Debug("HasNext() got next")
   333  				return true
   334  			} else {
   335  				mockLogger.Debug("HasNext() but no next")
   336  				return false
   337  
   338  			}
   339  		}
   340  		current = current.Next()
   341  	}
   342  
   343  	// we've reached the end of the underlying values
   344  	mockLogger.Debug("HasNext() but no next")
   345  	return false
   346  }
   347  
   348  // Next returns the next key and value in the range query iterator.
   349  func (iter *MockStateRangeQueryIterator) Next() (string, []byte, error) {
   350  	if iter.Closed == true {
   351  		mockLogger.Error("MockStateRangeQueryIterator.Next() called after Close()")
   352  		return "", nil, errors.New("MockStateRangeQueryIterator.Next() called after Close()")
   353  	}
   354  
   355  	if iter.HasNext() == false {
   356  		mockLogger.Error("MockStateRangeQueryIterator.Next() called when it does not HaveNext()")
   357  		return "", nil, errors.New("MockStateRangeQueryIterator.Next() called when it does not HaveNext()")
   358  	}
   359  
   360  	for iter.Current != nil {
   361  		comp1 := strings.Compare(iter.Current.Value.(string), iter.StartKey)
   362  		comp2 := strings.Compare(iter.Current.Value.(string), iter.EndKey)
   363  		// compare to start and end keys. or, if this is an open-ended query for
   364  		// all keys, it should always return the key and value
   365  		if (comp1 >= 0 && comp2 <= 0) || (iter.StartKey == "" && iter.EndKey == "") {
   366  			key := iter.Current.Value.(string)
   367  			value, err := iter.Stub.GetState(key)
   368  			iter.Current = iter.Current.Next()
   369  			return key, value, err
   370  		}
   371  		iter.Current = iter.Current.Next()
   372  	}
   373  	mockLogger.Error("MockStateRangeQueryIterator.Next() went past end of range")
   374  	return "", nil, errors.New("MockStateRangeQueryIterator.Next() went past end of range")
   375  }
   376  
   377  // Close closes the range query iterator. This should be called when done
   378  // reading from the iterator to free up resources.
   379  func (iter *MockStateRangeQueryIterator) Close() error {
   380  	if iter.Closed == true {
   381  		mockLogger.Error("MockStateRangeQueryIterator.Close() called after Close()")
   382  		return errors.New("MockStateRangeQueryIterator.Close() called after Close()")
   383  	}
   384  
   385  	iter.Closed = true
   386  	return nil
   387  }
   388  
   389  func (iter *MockStateRangeQueryIterator) Print() {
   390  	mockLogger.Debug("MockStateRangeQueryIterator {")
   391  	mockLogger.Debug("Closed?", iter.Closed)
   392  	mockLogger.Debug("Stub", iter.Stub)
   393  	mockLogger.Debug("StartKey", iter.StartKey)
   394  	mockLogger.Debug("EndKey", iter.EndKey)
   395  	mockLogger.Debug("Current", iter.Current)
   396  	mockLogger.Debug("HasNext?", iter.HasNext())
   397  	mockLogger.Debug("}")
   398  }
   399  
   400  func NewMockStateRangeQueryIterator(stub *MockStub, startKey string, endKey string) *MockStateRangeQueryIterator {
   401  	mockLogger.Debug("NewMockStateRangeQueryIterator(", stub, startKey, endKey, ")")
   402  	iter := new(MockStateRangeQueryIterator)
   403  	iter.Closed = false
   404  	iter.Stub = stub
   405  	iter.StartKey = startKey
   406  	iter.EndKey = endKey
   407  	iter.Current = stub.Keys.Front()
   408  
   409  	iter.Print()
   410  
   411  	return iter
   412  }
   413  
   414  func getBytes(function string, args []string) [][]byte {
   415  	bytes := make([][]byte, 0, len(args)+1)
   416  	bytes = append(bytes, []byte(function))
   417  	for _, s := range args {
   418  		bytes = append(bytes, []byte(s))
   419  	}
   420  	return bytes
   421  }
   422  
   423  func getFuncArgs(bytes [][]byte) (string, []string) {
   424  	mockLogger.Debugf("getFuncArgs(%x)", bytes)
   425  	function := string(bytes[0])
   426  	args := make([]string, len(bytes)-1)
   427  	for i := 1; i < len(bytes); i++ {
   428  		mockLogger.Debugf("getFuncArgs - i:%x, len(bytes):%x", i, len(bytes))
   429  		args[i-1] = string(bytes[i])
   430  	}
   431  	return function, args
   432  }