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 }