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