github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/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 if err := validateSimpleKeys(startKey, endKey); err != nil { 213 return nil, err 214 } 215 return NewMockStateRangeQueryIterator(stub, startKey, endKey), nil 216 } 217 218 // GetQueryResult function can be invoked by a chaincode to perform a 219 // rich query against state database. Only supported by state database implementations 220 // that support rich query. The query string is in the syntax of the underlying 221 // state database. An iterator is returned which can be used to iterate (next) over 222 // the query result set 223 func (stub *MockStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) { 224 // Not implemented since the mock engine does not have a query engine. 225 // However, a very simple query engine that supports string matching 226 // could be implemented to test that the framework supports queries 227 return nil, errors.New("Not Implemented") 228 } 229 230 // GetHistoryForKey function can be invoked by a chaincode to return a history of 231 // key values across time. GetHistoryForKey is intended to be used for read-only queries. 232 func (stub *MockStub) GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error) { 233 return nil, errors.New("Not Implemented") 234 } 235 236 //GetStateByPartialCompositeKey function can be invoked by a chaincode to query the 237 //state based on a given partial composite key. This function returns an 238 //iterator which can be used to iterate over all composite keys whose prefix 239 //matches the given partial composite key. This function should be used only for 240 //a partial composite key. For a full composite key, an iter with empty response 241 //would be returned. 242 func (stub *MockStub) GetStateByPartialCompositeKey(objectType string, attributes []string) (StateQueryIteratorInterface, error) { 243 partialCompositeKey, err := stub.CreateCompositeKey(objectType, attributes) 244 if err != nil { 245 return nil, err 246 } 247 return NewMockStateRangeQueryIterator(stub, partialCompositeKey, partialCompositeKey+string(maxUnicodeRuneValue)), nil 248 } 249 250 // CreateCompositeKey combines the list of attributes 251 //to form a composite key. 252 func (stub *MockStub) CreateCompositeKey(objectType string, attributes []string) (string, error) { 253 return createCompositeKey(objectType, attributes) 254 } 255 256 // SplitCompositeKey splits the composite key into attributes 257 // on which the composite key was formed. 258 func (stub *MockStub) SplitCompositeKey(compositeKey string) (string, []string, error) { 259 return splitCompositeKey(compositeKey) 260 } 261 262 // InvokeChaincode calls a peered chaincode. 263 // E.g. stub1.InvokeChaincode("stub2Hash", funcArgs, channel) 264 // Before calling this make sure to create another MockStub stub2, call stub2.MockInit(uuid, func, args) 265 // and register it with stub1 by calling stub1.MockPeerChaincode("stub2Hash", stub2) 266 func (stub *MockStub) InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response { 267 // Internally we use chaincode name as a composite name 268 if channel != "" { 269 chaincodeName = chaincodeName + "/" + channel 270 } 271 // TODO "args" here should possibly be a serialized pb.ChaincodeInput 272 otherStub := stub.Invokables[chaincodeName] 273 mockLogger.Debug("MockStub", stub.Name, "Invoking peer chaincode", otherStub.Name, args) 274 // function, strings := getFuncArgs(args) 275 res := otherStub.MockInvoke(stub.TxID, args) 276 mockLogger.Debug("MockStub", stub.Name, "Invoked peer chaincode", otherStub.Name, "got", fmt.Sprintf("%+v", res)) 277 return res 278 } 279 280 // Not implemented 281 func (stub *MockStub) GetCreator() ([]byte, error) { 282 return nil, nil 283 } 284 285 // Not implemented 286 func (stub *MockStub) GetTransient() (map[string][]byte, error) { 287 return nil, nil 288 } 289 290 // Not implemented 291 func (stub *MockStub) GetBinding() ([]byte, error) { 292 return nil, nil 293 } 294 295 // Not implemented 296 func (stub *MockStub) GetSignedProposal() (*pb.SignedProposal, error) { 297 return stub.signedProposal, nil 298 } 299 300 func (stub *MockStub) setSignedProposal(sp *pb.SignedProposal) { 301 stub.signedProposal = sp 302 } 303 304 // Not implemented 305 func (stub *MockStub) GetArgsSlice() ([]byte, error) { 306 return nil, nil 307 } 308 309 func (stub *MockStub) setTxTimestamp(time *timestamp.Timestamp) { 310 stub.TxTimestamp = time 311 } 312 313 func (stub *MockStub) GetTxTimestamp() (*timestamp.Timestamp, error) { 314 if stub.TxTimestamp == nil { 315 return nil, errors.New("TxTimestamp not set.") 316 } 317 return stub.TxTimestamp, nil 318 } 319 320 // Not implemented 321 func (stub *MockStub) SetEvent(name string, payload []byte) error { 322 return nil 323 } 324 325 // Constructor to initialise the internal State map 326 func NewMockStub(name string, cc Chaincode) *MockStub { 327 mockLogger.Debug("MockStub(", name, cc, ")") 328 s := new(MockStub) 329 s.Name = name 330 s.cc = cc 331 s.State = make(map[string][]byte) 332 s.Invokables = make(map[string]*MockStub) 333 s.Keys = list.New() 334 335 return s 336 } 337 338 /***************************** 339 Range Query Iterator 340 *****************************/ 341 342 type MockStateRangeQueryIterator struct { 343 Closed bool 344 Stub *MockStub 345 StartKey string 346 EndKey string 347 Current *list.Element 348 } 349 350 // HasNext returns true if the range query iterator contains additional keys 351 // and values. 352 func (iter *MockStateRangeQueryIterator) HasNext() bool { 353 if iter.Closed { 354 // previously called Close() 355 mockLogger.Error("HasNext() but already closed") 356 return false 357 } 358 359 if iter.Current == nil { 360 mockLogger.Error("HasNext() couldn't get Current") 361 return false 362 } 363 364 current := iter.Current 365 for current != nil { 366 // if this is an open-ended query for all keys, return true 367 if iter.StartKey == "" && iter.EndKey == "" { 368 return true 369 } 370 comp1 := strings.Compare(current.Value.(string), iter.StartKey) 371 comp2 := strings.Compare(current.Value.(string), iter.EndKey) 372 if comp1 >= 0 { 373 if comp2 <= 0 { 374 mockLogger.Debug("HasNext() got next") 375 return true 376 } else { 377 mockLogger.Debug("HasNext() but no next") 378 return false 379 380 } 381 } 382 current = current.Next() 383 } 384 385 // we've reached the end of the underlying values 386 mockLogger.Debug("HasNext() but no next") 387 return false 388 } 389 390 // Next returns the next key and value in the range query iterator. 391 func (iter *MockStateRangeQueryIterator) Next() (*queryresult.KV, error) { 392 if iter.Closed == true { 393 mockLogger.Error("MockStateRangeQueryIterator.Next() called after Close()") 394 return nil, errors.New("MockStateRangeQueryIterator.Next() called after Close()") 395 } 396 397 if iter.HasNext() == false { 398 mockLogger.Error("MockStateRangeQueryIterator.Next() called when it does not HaveNext()") 399 return nil, errors.New("MockStateRangeQueryIterator.Next() called when it does not HaveNext()") 400 } 401 402 for iter.Current != nil { 403 comp1 := strings.Compare(iter.Current.Value.(string), iter.StartKey) 404 comp2 := strings.Compare(iter.Current.Value.(string), iter.EndKey) 405 // compare to start and end keys. or, if this is an open-ended query for 406 // all keys, it should always return the key and value 407 if (comp1 >= 0 && comp2 <= 0) || (iter.StartKey == "" && iter.EndKey == "") { 408 key := iter.Current.Value.(string) 409 value, err := iter.Stub.GetState(key) 410 iter.Current = iter.Current.Next() 411 return &queryresult.KV{Key: key, Value: value}, err 412 } 413 iter.Current = iter.Current.Next() 414 } 415 mockLogger.Error("MockStateRangeQueryIterator.Next() went past end of range") 416 return nil, errors.New("MockStateRangeQueryIterator.Next() went past end of range") 417 } 418 419 // Close closes the range query iterator. This should be called when done 420 // reading from the iterator to free up resources. 421 func (iter *MockStateRangeQueryIterator) Close() error { 422 if iter.Closed == true { 423 mockLogger.Error("MockStateRangeQueryIterator.Close() called after Close()") 424 return errors.New("MockStateRangeQueryIterator.Close() called after Close()") 425 } 426 427 iter.Closed = true 428 return nil 429 } 430 431 func (iter *MockStateRangeQueryIterator) Print() { 432 mockLogger.Debug("MockStateRangeQueryIterator {") 433 mockLogger.Debug("Closed?", iter.Closed) 434 mockLogger.Debug("Stub", iter.Stub) 435 mockLogger.Debug("StartKey", iter.StartKey) 436 mockLogger.Debug("EndKey", iter.EndKey) 437 mockLogger.Debug("Current", iter.Current) 438 mockLogger.Debug("HasNext?", iter.HasNext()) 439 mockLogger.Debug("}") 440 } 441 442 func NewMockStateRangeQueryIterator(stub *MockStub, startKey string, endKey string) *MockStateRangeQueryIterator { 443 mockLogger.Debug("NewMockStateRangeQueryIterator(", stub, startKey, endKey, ")") 444 iter := new(MockStateRangeQueryIterator) 445 iter.Closed = false 446 iter.Stub = stub 447 iter.StartKey = startKey 448 iter.EndKey = endKey 449 iter.Current = stub.Keys.Front() 450 451 iter.Print() 452 453 return iter 454 } 455 456 func getBytes(function string, args []string) [][]byte { 457 bytes := make([][]byte, 0, len(args)+1) 458 bytes = append(bytes, []byte(function)) 459 for _, s := range args { 460 bytes = append(bytes, []byte(s)) 461 } 462 return bytes 463 } 464 465 func getFuncArgs(bytes [][]byte) (string, []string) { 466 mockLogger.Debugf("getFuncArgs(%x)", bytes) 467 function := string(bytes[0]) 468 args := make([]string, len(bytes)-1) 469 for i := 1; i < len(bytes); i++ { 470 mockLogger.Debugf("getFuncArgs - i:%x, len(bytes):%x", i, len(bytes)) 471 args[i-1] = string(bytes[i]) 472 } 473 return function, args 474 }