Asset transfer private-data go-chaincode - Add unit tests (#290)

* Adding golang application for asset-transfer-basic sample. (#211)

Signed-off-by: Chongxin Luo <Chongxin.Luo@ibm.com>

Improved private data Go Chaincode in idiomatic go.

Adding go chaincode unit tests

Signed-off-by: Sijo Cherian <sijo@ibm.com>

* Added unit tests for query-asset chaincode functions

Signed-off-by: Sijo Cherian <sijo@ibm.com>

* Improved README

Signed-off-by: Sijo Cherian <sijo@ibm.com>

* Added unit tests for query-asset chaincode functions

Signed-off-by: Sijo Cherian <sijo@ibm.com>

* Fixed json.Marsal usage per review comments, Improved DeleteAsset validation

Added owner collection check for DeleteAsset chaincode
JS app now demos a new expected error on DeleteAsset by a non-owner org

Signed-off-by: Sijo Cherian <sijo@ibm.com>

Co-authored-by: Dereck <Chongxin.Luo@ibm.com>
Co-authored-by: Sijo Cherian <sijo@ibm.com>
This commit is contained in:
Sijo Cherian 2020-08-25 10:04:03 -04:00 committed by GitHub
parent 67811efc92
commit c1424748b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 4417 additions and 64 deletions

View file

@ -153,7 +153,21 @@ async function main() {
result = await contractOrg1.evaluateTransaction('ReadAssetPrivateDetails', org1PrivateCollectionName, assetID1); result = await contractOrg1.evaluateTransaction('ReadAssetPrivateDetails', org1PrivateCollectionName, assetID1);
console.log(' result: ' + prettyJSONString(result.toString())); console.log(' result: ' + prettyJSONString(result.toString()));
// Attempt Transfer the asset to Org2 , without Org2 adding AgreeToTransfer //
// Transaction should return an error: "failed transfer verification ..."
let buyerDetails = { assetID: assetID1, buyerMSP: mspOrg2 };
try {
console.log('\n--> Attempt Submit Transaction: TransferAsset ' + assetID1);
statefulTxn = contractOrg1.createTransaction('TransferAsset');
tmapData = Buffer.from(JSON.stringify(buyerDetails));
statefulTxn.setTransient({
asset_owner: tmapData
});
result = await statefulTxn.submit();
console.log('******** FAILED: above operation expected to return an error');
} catch (error) {
console.log(` Successfully caught the error: \n ${error}`);
}
console.log('\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~'); console.log('\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~');
console.log('\n--> Evaluate Transaction: ReadAsset ' + assetID1); console.log('\n--> Evaluate Transaction: ReadAsset ' + assetID1);
result = await contractOrg2.evaluateTransaction('ReadAsset', assetID1); result = await contractOrg2.evaluateTransaction('ReadAsset', assetID1);
@ -194,7 +208,7 @@ async function main() {
// Transfer the asset to Org2 // // Transfer the asset to Org2 //
// To transfer the asset, the owner needs to pass the MSP ID of new asset owner, and initiate the transfer // To transfer the asset, the owner needs to pass the MSP ID of new asset owner, and initiate the transfer
console.log('\n--> Submit Transaction: TransferAsset ' + assetID1); console.log('\n--> Submit Transaction: TransferAsset ' + assetID1);
let buyerDetails = { assetID: assetID1, buyerMSP: mspOrg2 };
statefulTxn = contractOrg1.createTransaction('TransferAsset'); statefulTxn = contractOrg1.createTransaction('TransferAsset');
tmapData = Buffer.from(JSON.stringify(buyerDetails)); tmapData = Buffer.from(JSON.stringify(buyerDetails));
statefulTxn.setTransient({ statefulTxn.setTransient({
@ -202,7 +216,6 @@ async function main() {
}); });
result = await statefulTxn.submit(); result = await statefulTxn.submit();
//Again ReadAsset : results will show that the buyer identity now owns the asset: //Again ReadAsset : results will show that the buyer identity now owns the asset:
console.log('\n--> Evaluate Transaction: ReadAsset ' + assetID1); console.log('\n--> Evaluate Transaction: ReadAsset ' + assetID1);
result = await contractOrg1.evaluateTransaction('ReadAsset', assetID1); result = await contractOrg1.evaluateTransaction('ReadAsset', assetID1);
@ -221,11 +234,23 @@ async function main() {
console.log(' result: ' + prettyJSONString(result.toString())); console.log(' result: ' + prettyJSONString(result.toString()));
console.log('\n********* Demo deleting asset **************'); console.log('\n********* Demo deleting asset **************');
// Delete Asset2
console.log('--> Submit Transaction: DeleteAsset ' + assetID2);
statefulTxn = contractOrg1.createTransaction('DeleteAsset');
let dataForDelete = { assetID: assetID2 }; let dataForDelete = { assetID: assetID2 };
try {
//Non-owner Org2 should not be able to DeleteAsset. Expect an error from DeleteAsset
console.log('--> Attempt Transaction: as Org2 DeleteAsset ' + assetID2);
statefulTxn = contractOrg2.createTransaction('DeleteAsset');
tmapData = Buffer.from(JSON.stringify(dataForDelete));
statefulTxn.setTransient({
asset_delete: tmapData
});
result = await statefulTxn.submit();
console.log('******** FAILED : expected to return an error');
} catch (error) {
console.log(` Successfully caught the error: \n ${error}`);
}
// Delete Asset2 as Org1
console.log('--> Submit Transaction: as Org1 DeleteAsset ' + assetID2);
statefulTxn = contractOrg1.createTransaction('DeleteAsset');
tmapData = Buffer.from(JSON.stringify(dataForDelete)); tmapData = Buffer.from(JSON.stringify(dataForDelete));
statefulTxn.setTransient({ statefulTxn.setTransient({
asset_delete: tmapData asset_delete: tmapData

View file

@ -38,7 +38,11 @@ You can use the test network script to deploy the private data smart contract to
./network.sh deployCC -ccn private -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-go/collections_config.json ./network.sh deployCC -ccn private -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-go/collections_config.json
``` ```
Note that we are using the `-ccep` flag to deploy the private data smart contract with a chaincode endorsement policy of `"OR('Org1MSP.peer','Org2MSP.peer')"`. This allows Org1 and Org2 to create an asset without receiving an endorsement from the other organization. The command also uses the `-cccg` flag to provide the path to the collection configuration file. The above command deploys the go chaincode with short name `private`, and specifies the private data collection configuration from file `collections_config.json` using `-cccg` flag.
Note that we are using the `-ccep` flag to deploy the private data smart contract with a chaincode endorsement policy of `"OR('Org1MSP.peer','Org2MSP.peer')"`. This allows Org1 and Org2 to create an asset without receiving an endorsement from the other organization.
Now you are ready to call the deployed smart contract.
Note that this sample workflow steps below, can also be executed via the application at `asset-transfer-private-data/application-javascript` folder, in fewer steps. To execute the workflow via CLI, read on.
## Register identities ## Register identities
@ -147,7 +151,7 @@ The query will return the value of the asset:
### Buyer from Org2 agrees to buy the asset ### Buyer from Org2 agrees to buy the asset
The buyer identity from Org2 is interested in buying the asset. Set the following environment variables to operate as the buyer: The buyer identity from Org2 is interested in buying the asset. In a new terminal, set the following environment variables to operate as the buyer:
``` ```
export CORE_PEER_LOCALMSPID="Org2MSP" export CORE_PEER_LOCALMSPID="Org2MSP"
@ -156,20 +160,17 @@ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.e
export CORE_PEER_ADDRESS=localhost:9051 export CORE_PEER_ADDRESS=localhost:9051
``` ```
Now that we are operating as a member of Org2, we can demonstrate that the asset appraisal is not stored on the Org2 peer: Now that we are operating as a member of Org2, we can demonstrate that the asset appraisal is not stored in Org2MSPPrivateCollection, on the Org2 peer:
``` ```
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org2MSPPrivateCollection","asset1"]}' peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org2MSPPrivateCollection","asset1"]}'
``` ```
The buyer only finds that asset1 does exist in the Org1 collection: The empty response shows that, the asset1 private details, does not exist in buyer private collection.
```
Error: endorsement failure during invoke. response: status:500 message:"appraisal value for asset1 does not exist in private data collection"
```
Nor is a member of Org2 able to read the Org1 private data collection: Nor can a member of Org2, able to read the Org1 private data collection:
``` ```
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org1MSPPrivateCollection","asset1"]}' peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org1MSPPrivateCollection","asset1"]}'
``` ```
By setting `"memberOnlyRead": true` in the collection configuration file, we specify that only members of Org1 can read data from the collection. A member who tries to read the collection would only get the following response. By setting `"memberOnlyRead": true` in the collection configuration file, we specify that only members of Org1 can read data from the collection. A Org2 member who tries to read the collection would only get the following response.
``` ```
Error: endorsement failure during query. response: status:500 message:"failed to read from asset details GET_STATE failed: transaction ID: 10d39a7d0b340455a19ca4198146702d68d884d41a0e60936f1599c1ddb9c99d: tx creator does not have read access permission on privatedata in chaincodeName:private collectionName: Org1MSPPrivateCollection" Error: endorsement failure during query. response: status:500 message:"failed to read from asset details GET_STATE failed: transaction ID: 10d39a7d0b340455a19ca4198146702d68d884d41a0e60936f1599c1ddb9c99d: tx creator does not have read access permission on privatedata in chaincodeName:private collectionName: Org1MSPPrivateCollection"
``` ```
@ -189,9 +190,9 @@ The invoke will return the following value:
{"assetID":"asset1","appraisedValue":100} {"assetID":"asset1","appraisedValue":100}
``` ```
## Transfer the asset to Org2 ## Org1 member transfers the asset to Org2
Now that buyer has agreed to buy the asset for appraised value, the owner from Org1 can transfer the asset to Org2. Set the following environment variables to operate as Org1: Now that buyer has agreed to buy the asset for appraised value, the owner from Org1 can transfer the asset to Org2. In the first terminal (with the following environment variables to operate as Org1):
``` ```
export CORE_PEER_LOCALMSPID="Org1MSP" export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/owner@org1.example.com/msp export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/owner@org1.example.com/msp
@ -199,7 +200,12 @@ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.e
export CORE_PEER_ADDRESS=localhost:7051 export CORE_PEER_ADDRESS=localhost:7051
``` ```
To transfer the asset, the owner needs to pass the MSP ID of new asset owner. The transfer function will read the client ID of the interested buyer from the transfer agreement. Now that buyer has agreed to buy the asset for appraised value, the owner from Org1 can read the data added by `AgreeToTransfer` to see buyer identity.
```
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadTransferAgreement","Args":["asset1"]}'
```
The owner from Org1 can now transfer the asset to Org2. To transfer the asset, the owner needs to pass the MSP ID of new asset owner Org. The transfer function will read the client ID of the interested buyer user from the transfer agreement.
``` ```
export ASSET_OWNER=$(echo -n "{\"assetID\":\"asset1\",\"buyerMSP\":\"Org2MSP\"}" | base64 | tr -d \\n) export ASSET_OWNER=$(echo -n "{\"assetID\":\"asset1\",\"buyerMSP\":\"Org2MSP\"}" | base64 | tr -d \\n)
``` ```
@ -209,7 +215,7 @@ The owner of the asset needs to initiate the transfer.
``` ```
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"TransferAsset","Args":[]}' --transient "{\"asset_owner\":\"$ASSET_OWNER\"}" --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"TransferAsset","Args":[]}' --transient "{\"asset_owner\":\"$ASSET_OWNER\"}" --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
``` ```
You can query `asset1` to see the results of the transfer. You can ReadAsset `asset1` to see the results of the transfer.
``` ```
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadAsset","Args":["asset1"]}' peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadAsset","Args":["asset1"]}'
``` ```
@ -229,10 +235,7 @@ You can also confirm that transfer removed the private details from the Org1 col
``` ```
peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org1MSPPrivateCollection","asset1"]}' peer chaincode query -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n private -c '{"function":"ReadAssetPrivateDetails","Args":["Org1MSPPrivateCollection","asset1"]}'
``` ```
Your query will return the following result: Your query will return empty result, since the asset private data is removed from the Org1 private data collection.
```
Error: endorsement failure during query. response: status:500 message:"appraisal value for asset1 does not exist in private data collection"
```
## Clean up ## Clean up

View file

@ -4,7 +4,7 @@ Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0 SPDX-License-Identifier: Apache-2.0
*/ */
package main package chaincode
import ( import (
"encoding/json" "encoding/json"
@ -20,7 +20,7 @@ func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, a
log.Printf("ReadAsset: collection %v, ID %v", assetCollection, assetID) log.Printf("ReadAsset: collection %v, ID %v", assetCollection, assetID)
assetJSON, err := ctx.GetStub().GetPrivateData(assetCollection, assetID) //get the asset from chaincode state assetJSON, err := ctx.GetStub().GetPrivateData(assetCollection, assetID) //get the asset from chaincode state
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read from asset %v", err) return nil, fmt.Errorf("failed to read asset: %v", err)
} }
//No Asset found, return empty response //No Asset found, return empty response
@ -44,7 +44,7 @@ func (s *SmartContract) ReadAssetPrivateDetails(ctx contractapi.TransactionConte
log.Printf("ReadAssetPrivateDetails: collection %v, ID %v", collection, assetID) log.Printf("ReadAssetPrivateDetails: collection %v, ID %v", collection, assetID)
assetDetailsJSON, err := ctx.GetStub().GetPrivateData(collection, assetID) // Get the asset from chaincode state assetDetailsJSON, err := ctx.GetStub().GetPrivateData(collection, assetID) // Get the asset from chaincode state
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read from asset details %v", err) return nil, fmt.Errorf("failed to read asset details: %v", err)
} }
if assetDetailsJSON == nil { if assetDetailsJSON == nil {
log.Printf("AssetPrivateDetails for %v does not exist in collection %v", assetID, collection) log.Printf("AssetPrivateDetails for %v does not exist in collection %v", assetID, collection)

View file

@ -0,0 +1,185 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package chaincode_test
import (
"encoding/json"
"fmt"
"testing"
"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
"github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode"
"github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode/mocks"
"github.com/stretchr/testify/require"
)
/*
For details on generating the mocks, see comments in the file asset_transfer_test.go
*/
func TestReadAsset(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetBytes, err := assetTransferCC.ReadAsset(transactionContext, "id1")
require.NoError(t, err)
require.Nil(t, assetBytes)
chaincodeStub.GetPrivateDataReturns(nil, fmt.Errorf("unable to retrieve asset"))
assetBytes, err = assetTransferCC.ReadAsset(transactionContext, "id1")
require.EqualError(t, err, "failed to read asset: unable to retrieve asset")
testAsset := &chaincode.Asset{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
Owner: myOrg1Clientid,
}
setReturnPrivateDataInStub(t, chaincodeStub, testAsset)
assetRead, err := assetTransferCC.ReadAsset(transactionContext, "id1")
require.NoError(t, err)
require.Equal(t, testAsset, assetRead)
}
func TestReadAssetPrivateDetails(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetBytes, err := assetTransferCC.ReadAssetPrivateDetails(transactionContext, myOrg1PrivCollection, "id1")
require.NoError(t, err)
require.Nil(t, assetBytes)
//read from the collection with no access
chaincodeStub.GetPrivateDataReturns(nil, fmt.Errorf("collection not found"))
assetBytes, err = assetTransferCC.ReadAssetPrivateDetails(transactionContext, myOrg2PrivCollection, "id1")
require.EqualError(t, err, "failed to read asset details: collection not found")
returnPrivData := &chaincode.AssetPrivateDetails{
ID: "id1",
AppraisedValue: 5,
}
setReturnAssetPrivateDetailsInStub(t, chaincodeStub, returnPrivData)
assetRead, err := assetTransferCC.ReadAssetPrivateDetails(transactionContext, myOrg1PrivCollection, "id1")
require.NoError(t, err)
require.Equal(t, returnPrivData, assetRead)
}
func TestReadTransferAgreement(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
//TransferAgreement does not exist
assetBytes, err := assetTransferCC.ReadTransferAgreement(transactionContext, "id1")
require.NoError(t, err)
require.Nil(t, assetBytes)
chaincodeStub.GetPrivateDataReturns([]byte(myOrg2Clientid), nil)
expectedData := &chaincode.TransferAgreement{
ID: "id1",
BuyerID: myOrg2Clientid,
}
dataRead, err := assetTransferCC.ReadTransferAgreement(transactionContext, "id1")
require.NoError(t, err)
require.Equal(t, expectedData, dataRead)
}
func TestQueryAssetByOwner(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
asset := &chaincode.Asset{Type: "valuableasset", ID: "asset1", Owner: "user1"}
asset1Bytes, err := json.Marshal(asset)
require.NoError(t, err)
iterator := &mocks.StateQueryIterator{}
iterator.HasNextReturnsOnCall(0, true)
iterator.HasNextReturnsOnCall(1, false)
iterator.NextReturns(&queryresult.KV{Value: asset1Bytes}, nil)
chaincodeStub.GetPrivateDataQueryResultReturns(iterator, nil)
assetTransferCC := &chaincode.SmartContract{}
assets, err := assetTransferCC.QueryAssetByOwner(transactionContext, "valuableasset", "user1")
require.NoError(t, err)
require.Equal(t, []*chaincode.Asset{asset}, assets)
iterator.HasNextReturns(true)
iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item"))
assets, err = assetTransferCC.QueryAssetByOwner(transactionContext, "valuableasset", "user1")
require.EqualError(t, err, "failed retrieving next item")
require.Nil(t, assets)
}
func TestQueryAssets(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
//Iterator with no records
iterator := &mocks.StateQueryIterator{}
iterator.HasNextReturns(false)
chaincodeStub.GetPrivateDataQueryResultReturns(iterator, nil)
assetTransferCC := &chaincode.SmartContract{}
assets, err := assetTransferCC.QueryAssets(transactionContext, "querystr")
require.NoError(t, err)
require.Equal(t, []*chaincode.Asset{}, assets)
iterator = &mocks.StateQueryIterator{}
chaincodeStub.GetPrivateDataQueryResultReturns(iterator, nil)
iterator.HasNextReturns(true)
iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item"))
assets, err = assetTransferCC.QueryAssets(transactionContext, "querystr")
require.EqualError(t, err, "failed retrieving next item")
require.Nil(t, assets)
asset := &chaincode.Asset{Type: "valuableasset", ID: "asset1", Owner: "user1"}
asset1Bytes, err := json.Marshal(asset)
require.NoError(t, err)
iterator = &mocks.StateQueryIterator{}
chaincodeStub.GetPrivateDataQueryResultReturns(iterator, nil)
iterator.HasNextReturnsOnCall(0, true)
iterator.HasNextReturnsOnCall(1, false)
iterator.NextReturns(&queryresult.KV{Value: asset1Bytes}, nil)
assets, err = assetTransferCC.QueryAssets(transactionContext, "querystr")
require.NoError(t, err)
require.Equal(t, []*chaincode.Asset{asset}, assets)
}
func TestGetAssetByRange(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
//Iterator with no records
iterator := &mocks.StateQueryIterator{}
iterator.HasNextReturns(false)
chaincodeStub.GetPrivateDataByRangeReturns(iterator, nil)
assetTransferCC := &chaincode.SmartContract{}
assets, err := assetTransferCC.GetAssetByRange(transactionContext, "st", "end")
require.NoError(t, err)
require.Equal(t, []*chaincode.Asset{}, assets)
iterator = &mocks.StateQueryIterator{}
chaincodeStub.GetPrivateDataByRangeReturns(iterator, nil)
iterator.HasNextReturns(true)
iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item"))
assets, err = assetTransferCC.GetAssetByRange(transactionContext, "st", "end")
require.EqualError(t, err, "failed retrieving next item")
require.Nil(t, assets)
asset := &chaincode.Asset{Type: "valuableasset", ID: "asset1", Owner: "user1"}
asset1Bytes, err := json.Marshal(asset)
require.NoError(t, err)
iterator = &mocks.StateQueryIterator{}
chaincodeStub.GetPrivateDataByRangeReturns(iterator, nil)
iterator.HasNextReturnsOnCall(0, true)
iterator.HasNextReturnsOnCall(1, false)
iterator.NextReturns(&queryresult.KV{Value: asset1Bytes}, nil)
assets, err = assetTransferCC.GetAssetByRange(transactionContext, "st", "end")
require.NoError(t, err)
require.Equal(t, []*chaincode.Asset{asset}, assets)
}

View file

@ -4,7 +4,7 @@ Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0 SPDX-License-Identifier: Apache-2.0
*/ */
package main package chaincode
import ( import (
"bytes" "bytes"
@ -19,6 +19,11 @@ import (
const assetCollection = "assetCollection" const assetCollection = "assetCollection"
const transferAgreementObjectType = "transferAgreement" const transferAgreementObjectType = "transferAgreement"
// SmartContract of this fabric sample
type SmartContract struct {
contractapi.Contract
}
// Asset describes main asset details that are visible to all organizations // Asset describes main asset details that are visible to all organizations
type Asset struct { type Asset struct {
Type string `json:"objectType"` //Type is used to distinguish the various types of objects in state database Type string `json:"objectType"` //Type is used to distinguish the various types of objects in state database
@ -40,11 +45,6 @@ type TransferAgreement struct {
BuyerID string `json:"buyerID"` BuyerID string `json:"buyerID"`
} }
// SmartContract of this fabric sample
type SmartContract struct {
contractapi.Contract
}
// CreateAsset creates a new asset by placing the main asset details in the assetCollection // CreateAsset creates a new asset by placing the main asset details in the assetCollection
// that can be read by both organizations. The appraisal value is stored in the owners org specific collection. // that can be read by both organizations. The appraisal value is stored in the owners org specific collection.
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface) error { func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface) error {
@ -116,7 +116,7 @@ func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface)
} }
// Make submitting client the owner // Make submitting client the owner
asset := &Asset{ asset := Asset{
Type: assetInput.Type, Type: assetInput.Type,
ID: assetInput.ID, ID: assetInput.ID,
Color: assetInput.Color, Color: assetInput.Color,
@ -138,7 +138,7 @@ func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface)
} }
// Save asset details to collection visible to owning organization // Save asset details to collection visible to owning organization
assetPrivateDetails := &AssetPrivateDetails{ assetPrivateDetails := AssetPrivateDetails{
ID: assetInput.ID, ID: assetInput.ID,
AppraisedValue: assetInput.AppraisedValue, AppraisedValue: assetInput.AppraisedValue,
} }
@ -202,6 +202,14 @@ func (s *SmartContract) AgreeToTransfer(ctx contractapi.TransactionContextInterf
return fmt.Errorf("appraisedValue field must be a positive integer") return fmt.Errorf("appraisedValue field must be a positive integer")
} }
// Read asset from the private data collection
asset, err := s.ReadAsset(ctx, valueJSON.ID)
if err != nil {
return fmt.Errorf("error reading asset: %v", err)
}
if asset == nil {
return fmt.Errorf("%v does not exist", valueJSON.ID)
}
// Verify that the client is submitting request to peer in their organization // Verify that the client is submitting request to peer in their organization
err = verifyClientOrgMatchesPeerOrg(ctx) err = verifyClientOrgMatchesPeerOrg(ctx)
if err != nil { if err != nil {
@ -273,9 +281,11 @@ func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterfac
// Read asset from the private data collection // Read asset from the private data collection
asset, err := s.ReadAsset(ctx, assetTransferInput.ID) asset, err := s.ReadAsset(ctx, assetTransferInput.ID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get asset: %v", err) return fmt.Errorf("error reading asset: %v", err)
}
if asset == nil {
return fmt.Errorf("%v does not exist", assetTransferInput.ID)
} }
// Verify that the client is submitting request to peer in their organization // Verify that the client is submitting request to peer in their organization
err = verifyClientOrgMatchesPeerOrg(ctx) err = verifyClientOrgMatchesPeerOrg(ctx)
if err != nil { if err != nil {
@ -433,10 +443,18 @@ func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface)
return fmt.Errorf("asset not found: %v", assetDeleteInput.ID) return fmt.Errorf("asset not found: %v", assetDeleteInput.ID)
} }
var assetToDelete Asset ownerCollection, err := getCollectionName(ctx) // Get owners collection
err = json.Unmarshal([]byte(valAsbytes), &assetToDelete)
if err != nil { if err != nil {
return fmt.Errorf("failed to unmarshal JSON: %v", err) return fmt.Errorf("failed to infer private collection name for the org: %v", err)
}
//check the asset is in the caller org's private collection
valAsbytes, err = ctx.GetStub().GetPrivateData(ownerCollection, assetDeleteInput.ID)
if err != nil {
return fmt.Errorf("failed to read asset from owner's Collection: %v", err)
}
if valAsbytes == nil {
return fmt.Errorf("asset not found in owner's private Collection %v: %v", ownerCollection, assetDeleteInput.ID)
} }
// delete the asset from state // delete the asset from state
@ -446,12 +464,7 @@ func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface)
} }
// Finally, delete private details of asset // Finally, delete private details of asset
ownerCollection, err := getCollectionName(ctx) // Get owners collection err = ctx.GetStub().DelPrivateData(ownerCollection, assetDeleteInput.ID)
if err != nil {
return fmt.Errorf("failed to infer private collection name for the org: %v", err)
}
err = ctx.GetStub().DelPrivateData(ownerCollection, assetDeleteInput.ID) // Delete the asset
if err != nil { if err != nil {
return err return err
} }
@ -486,7 +499,7 @@ func (s *SmartContract) DeleteTranferAgreement(ctx contractapi.TransactionContex
} }
if len(assetDeleteInput.ID) == 0 { if len(assetDeleteInput.ID) == 0 {
return fmt.Errorf("ID field must be a non-empty string") return fmt.Errorf("transient input ID field must be a non-empty string")
} }
// Verify that the client is submitting request to peer in their organization // Verify that the client is submitting request to peer in their organization
@ -561,17 +574,3 @@ func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface)
return nil return nil
} }
func main() {
chaincode, err := contractapi.NewChaincode(new(SmartContract))
if err != nil {
log.Panicf("error creating the chaincode: %v", err)
return
}
if err := chaincode.Start(); err != nil {
log.Panicf("error starting the chaincode: %v", err)
}
}

View file

@ -0,0 +1,444 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package chaincode_test
import (
"encoding/json"
"os"
"testing"
"github.com/hyperledger/fabric-chaincode-go/pkg/cid"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode"
"github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode/mocks"
"github.com/stretchr/testify/require"
)
/*
These unit tests use mocks to simulate chaincode-api & fabric interactions
The mocks are generated using counterfeiter directives in the comments (starting with "go:generate counterfeiter")
All files in mocks/* are generated by running following, in the directory with your directive:
`go generate`
*/
//go:generate counterfeiter -o mocks/transaction.go -fake-name TransactionContext . transactionContext
type transactionContext interface {
contractapi.TransactionContextInterface
}
//go:generate counterfeiter -o mocks/chaincodestub.go -fake-name ChaincodeStub . chaincodeStub
type chaincodeStub interface {
shim.ChaincodeStubInterface
}
//go:generate counterfeiter -o mocks/statequeryiterator.go -fake-name StateQueryIterator . stateQueryIterator
type stateQueryIterator interface {
shim.StateQueryIteratorInterface
}
//go:generate counterfeiter -o mocks/clientIdentity.go -fake-name ClientIdentity . clientIdentity
type clientIdentity interface {
cid.ClientIdentity
}
const assetCollectionName = "assetCollection"
const transferAgreementObjectType = "transferAgreement"
const myOrg1Msp = "Org1Testmsp"
const myOrg1Clientid = "myOrg1Userid"
const myOrg1PrivCollection = "Org1TestmspPrivateCollection"
const myOrg2Msp = "Org2Testmsp"
const myOrg2Clientid = "myOrg2Userid"
const myOrg2PrivCollection = "Org2TestmspPrivateCollection"
type assetTransientInput struct {
Type string `json:"objectType"`
ID string `json:"assetID"`
Color string `json:"color"`
Size int `json:"size"`
AppraisedValue int `json:"appraisedValue"`
}
type assetTransferTransientInput struct {
ID string `json:"assetID"`
BuyerMSP string `json:"buyerMSP"`
}
func TestCreateAssetBadInput(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
// No transient map
err := assetTransferCC.CreateAsset(transactionContext)
require.EqualError(t, err, "asset not found in the transient map input")
// transient map with incomplete asset data
assetPropMap := map[string][]byte{
"asset_properties": []byte("ill formatted property"),
}
chaincodeStub.GetTransientReturns(assetPropMap, nil)
err = assetTransferCC.CreateAsset(transactionContext)
require.Error(t, err, "Expected error: transient map with incomplete asset data")
require.Contains(t, err.Error(), "failed to unmarshal JSON")
testAsset := &assetTransientInput{
Type: "testfulasset",
}
setReturnAssetPropsInTransientMap(t, chaincodeStub, testAsset)
err = assetTransferCC.CreateAsset(transactionContext)
require.EqualError(t, err, "assetID field must be a non-empty string")
testAsset = &assetTransientInput{
ID: "id1",
Color: "gray",
}
setReturnAssetPropsInTransientMap(t, chaincodeStub, testAsset)
err = assetTransferCC.CreateAsset(transactionContext)
require.EqualError(t, err, "objectType field must be a non-empty string")
// case when asset exists, GetPrivateData returns a valid data from ledger
testAsset = &assetTransientInput{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
AppraisedValue: 500,
}
setReturnAssetPropsInTransientMap(t, chaincodeStub, testAsset)
chaincodeStub.GetPrivateDataReturns([]byte{}, nil)
err = assetTransferCC.CreateAsset(transactionContext)
require.EqualError(t, err, "this asset already exists: id1")
}
func TestCreateAssetSuccessful(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
testAsset := &assetTransientInput{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
AppraisedValue: 500,
}
setReturnAssetPropsInTransientMap(t, chaincodeStub, testAsset)
err := assetTransferCC.CreateAsset(transactionContext)
require.NoError(t, err)
//Validate PutPrivateData calls
calledCollection, calledId, _ := chaincodeStub.PutPrivateDataArgsForCall(0)
require.Equal(t, assetCollectionName, calledCollection)
require.Equal(t, "id1", calledId)
expectedPrivateDetails := &chaincode.AssetPrivateDetails{
ID: "id1",
AppraisedValue: 500,
}
assetBytes, err := json.Marshal(expectedPrivateDetails)
calledCollection, calledId, calledAssetBytes := chaincodeStub.PutPrivateDataArgsForCall(1)
require.Equal(t, myOrg1PrivCollection, calledCollection)
require.Equal(t, "id1", calledId)
require.Equal(t, assetBytes, calledAssetBytes)
}
func TestAgreeToTransferBadInput(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetPrivDetail := &chaincode.AssetPrivateDetails{
ID: "id1",
//no AppraisedValue
}
setReturnAssetPrivateDetailsInTransientMap(t, chaincodeStub, assetPrivDetail)
origAsset := chaincode.Asset{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
Owner: myOrg1Clientid,
}
setReturnPrivateDataInStub(t, chaincodeStub, &origAsset)
err := assetTransferCC.AgreeToTransfer(transactionContext)
require.EqualError(t, err, "appraisedValue field must be a positive integer")
assetPrivDetail = &chaincode.AssetPrivateDetails{
//no ID
AppraisedValue: 500,
}
setReturnAssetPrivateDetailsInTransientMap(t, chaincodeStub, assetPrivDetail)
err = assetTransferCC.AgreeToTransfer(transactionContext)
require.EqualError(t, err, "assetID field must be a non-empty string")
assetPrivDetail = &chaincode.AssetPrivateDetails{
ID: "id1",
AppraisedValue: 500,
}
setReturnAssetPrivateDetailsInTransientMap(t, chaincodeStub, assetPrivDetail)
//asset does not exist
setReturnPrivateDataInStub(t, chaincodeStub, nil)
err = assetTransferCC.AgreeToTransfer(transactionContext)
require.EqualError(t, err, "id1 does not exist")
}
func TestAgreeToTransferSuccessful(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetPrivDetail := &chaincode.AssetPrivateDetails{
ID: "id1",
AppraisedValue: 500,
}
setReturnAssetPrivateDetailsInTransientMap(t, chaincodeStub, assetPrivDetail)
origAsset := chaincode.Asset{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
Owner: myOrg1Clientid,
}
setReturnPrivateDataInStub(t, chaincodeStub, &origAsset)
chaincodeStub.CreateCompositeKeyReturns(transferAgreementObjectType+"id1", nil)
err := assetTransferCC.AgreeToTransfer(transactionContext)
require.NoError(t, err)
expectedDataBytes, err := json.Marshal(assetPrivDetail)
calledCollection, calledId, calledWithDataBytes := chaincodeStub.PutPrivateDataArgsForCall(0)
require.Equal(t, myOrg1PrivCollection, calledCollection)
require.Equal(t, "id1", calledId)
require.Equal(t, expectedDataBytes, calledWithDataBytes)
calledCollection, calledId, calledWithDataBytes = chaincodeStub.PutPrivateDataArgsForCall(1)
require.Equal(t, assetCollectionName, calledCollection)
require.Equal(t, transferAgreementObjectType+"id1", calledId)
require.Equal(t, []byte(myOrg1Clientid), calledWithDataBytes)
}
func TestTransferAssetBadInput(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetNewOwner := &assetTransferTransientInput{
ID: "id1",
BuyerMSP: "",
}
setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner)
setReturnPrivateDataInStub(t, chaincodeStub, &chaincode.Asset{})
err := assetTransferCC.TransferAsset(transactionContext)
require.EqualError(t, err, "buyerMSP field must be a non-empty string")
assetNewOwner = &assetTransferTransientInput{
ID: "id1",
BuyerMSP: myOrg2Msp,
}
setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner)
//asset does not exist
setReturnPrivateDataInStub(t, chaincodeStub, nil)
err = assetTransferCC.TransferAsset(transactionContext)
require.EqualError(t, err, "id1 does not exist")
}
func TestTransferAssetSuccessful(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetNewOwner := &assetTransferTransientInput{
ID: "id1",
BuyerMSP: myOrg2Msp,
}
setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner)
origAsset := chaincode.Asset{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
Owner: myOrg1Clientid,
}
setReturnPrivateDataInStub(t, chaincodeStub, &origAsset)
//to ensure we pass data hash verification
chaincodeStub.GetPrivateDataHashReturns([]byte("datahash"), nil)
//to ensure that ReadTransferAgreement call returns org2 client ID
chaincodeStub.GetPrivateDataReturnsOnCall(1, []byte(myOrg2Clientid), nil)
chaincodeStub.CreateCompositeKeyReturns(transferAgreementObjectType+"id1", nil)
err := assetTransferCC.TransferAsset(transactionContext)
require.NoError(t, err)
//Validate PutPrivateData calls
expectedNewAsset := origAsset
expectedNewAsset.Owner = myOrg2Clientid
expectedNewAssetBytes, err := json.Marshal(expectedNewAsset)
require.NoError(t, err)
calledCollection, calledId, calledWithAssetBytes := chaincodeStub.PutPrivateDataArgsForCall(0)
require.Equal(t, assetCollectionName, calledCollection)
require.Equal(t, "id1", calledId)
require.Equal(t, expectedNewAssetBytes, calledWithAssetBytes)
calledCollection, calledId = chaincodeStub.DelPrivateDataArgsForCall(0)
require.Equal(t, myOrg1PrivCollection, calledCollection)
require.Equal(t, "id1", calledId)
calledCollection, calledId = chaincodeStub.DelPrivateDataArgsForCall(1)
require.Equal(t, assetCollectionName, calledCollection)
require.Equal(t, transferAgreementObjectType+"id1", calledId)
}
func TestTransferAssetByNonOwner(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetNewOwner := &assetTransferTransientInput{
ID: "id1",
BuyerMSP: myOrg1Msp,
}
setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner)
//Try to transfer asset owned by Org2
org2Asset := chaincode.Asset{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
Owner: myOrg2Clientid,
}
setReturnPrivateDataInStub(t, chaincodeStub, &org2Asset)
err := assetTransferCC.TransferAsset(transactionContext)
require.EqualError(t, err, "failed transfer verification: error: submitting client identity does not own asset")
}
func TestTransferAssetWithoutAnAgreement(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetNewOwner := &assetTransferTransientInput{
ID: "id1",
BuyerMSP: myOrg1Msp,
}
setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner)
orgAsset := chaincode.Asset{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
Owner: myOrg1Clientid,
}
setReturnPrivateDataInStub(t, chaincodeStub, &orgAsset)
//to ensure we pass data hash verification
chaincodeStub.GetPrivateDataHashReturns([]byte("datahash"), nil)
chaincodeStub.CreateCompositeKeyReturns(transferAgreementObjectType+"id1", nil)
//ReadTransferAgreement call returns no buyer client ID
chaincodeStub.GetPrivateDataReturnsOnCall(1, []byte{}, nil)
err := assetTransferCC.TransferAsset(transactionContext)
require.EqualError(t, err, "BuyerID not found in TransferAgreement for id1")
}
func TestTransferAssetNonMatchingAppraisalValue(t *testing.T) {
transactionContext, chaincodeStub := prepMocksAsOrg1()
assetTransferCC := chaincode.SmartContract{}
assetNewOwner := &assetTransferTransientInput{
ID: "id1",
BuyerMSP: myOrg2Msp,
}
setReturnAssetOwnerInTransientMap(t, chaincodeStub, assetNewOwner)
orgAsset := chaincode.Asset{
ID: "id1",
Type: "testfulasset",
Color: "gray",
Size: 7,
Owner: myOrg1Clientid,
}
setReturnPrivateDataInStub(t, chaincodeStub, &orgAsset)
chaincodeStub.CreateCompositeKeyReturns(transferAgreementObjectType+"id1", nil)
//data hash different in each collection
chaincodeStub.GetPrivateDataHashReturnsOnCall(0, []byte("datahash1"), nil)
chaincodeStub.GetPrivateDataHashReturnsOnCall(1, []byte("datahash2"), nil)
err := assetTransferCC.TransferAsset(transactionContext)
require.Error(t, err, "Expected failed hash verification")
require.Contains(t, err.Error(), "failed transfer verification: hash for appraised value")
}
func prepMocksAsOrg1() (*mocks.TransactionContext, *mocks.ChaincodeStub) {
return prepMocks(myOrg1Msp, myOrg1Clientid)
}
func prepMocksAsOrg2() (*mocks.TransactionContext, *mocks.ChaincodeStub) {
return prepMocks(myOrg2Msp, myOrg2Clientid)
}
func prepMocks(orgMSP, clientId string) (*mocks.TransactionContext, *mocks.ChaincodeStub) {
chaincodeStub := &mocks.ChaincodeStub{}
transactionContext := &mocks.TransactionContext{}
transactionContext.GetStubReturns(chaincodeStub)
clientIdentity := &mocks.ClientIdentity{}
clientIdentity.GetMSPIDReturns(orgMSP, nil)
clientIdentity.GetIDReturns(clientId, nil)
//set matching msp ID using peer shim env variable
os.Setenv("CORE_PEER_LOCALMSPID", orgMSP)
transactionContext.GetClientIdentityReturns(clientIdentity)
return transactionContext, chaincodeStub
}
func setReturnAssetPrivateDetailsInTransientMap(t *testing.T, chaincodeStub *mocks.ChaincodeStub, assetPrivDetail *chaincode.AssetPrivateDetails) []byte {
assetOwnerBytes := []byte{}
if assetPrivDetail != nil {
var err error
assetOwnerBytes, err = json.Marshal(assetPrivDetail)
require.NoError(t, err)
}
assetPropMap := map[string][]byte{
"asset_value": assetOwnerBytes,
}
chaincodeStub.GetTransientReturns(assetPropMap, nil)
return assetOwnerBytes
}
func setReturnAssetOwnerInTransientMap(t *testing.T, chaincodeStub *mocks.ChaincodeStub, assetOwner *assetTransferTransientInput) []byte {
assetOwnerBytes := []byte{}
if assetOwner != nil {
var err error
assetOwnerBytes, err = json.Marshal(assetOwner)
require.NoError(t, err)
}
assetPropMap := map[string][]byte{
"asset_owner": assetOwnerBytes,
}
chaincodeStub.GetTransientReturns(assetPropMap, nil)
return assetOwnerBytes
}
func setReturnAssetPropsInTransientMap(t *testing.T, chaincodeStub *mocks.ChaincodeStub, testAsset *assetTransientInput) []byte {
assetBytes := []byte{}
if testAsset != nil {
var err error
assetBytes, err = json.Marshal(testAsset)
require.NoError(t, err)
}
assetPropMap := map[string][]byte{
"asset_properties": assetBytes,
}
chaincodeStub.GetTransientReturns(assetPropMap, nil)
return assetBytes
}
func setReturnPrivateDataInStub(t *testing.T, chaincodeStub *mocks.ChaincodeStub, testAsset *chaincode.Asset) []byte {
if testAsset == nil {
chaincodeStub.GetPrivateDataReturns(nil, nil)
return nil
} else {
var err error
assetBytes, err := json.Marshal(testAsset)
require.NoError(t, err)
chaincodeStub.GetPrivateDataReturns(assetBytes, nil)
return assetBytes
}
}
func setReturnAssetPrivateDetailsInStub(t *testing.T, chaincodeStub *mocks.ChaincodeStub, testAsset *chaincode.AssetPrivateDetails) []byte {
if testAsset == nil {
chaincodeStub.GetPrivateDataReturns(nil, nil)
return nil
} else {
var err error
assetBytes, err := json.Marshal(testAsset)
require.NoError(t, err)
chaincodeStub.GetPrivateDataReturns(assetBytes, nil)
return assetBytes
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,399 @@
// Code generated by counterfeiter. DO NOT EDIT.
package mocks
import (
"crypto/x509"
"sync"
)
type ClientIdentity struct {
AssertAttributeValueStub func(string, string) error
assertAttributeValueMutex sync.RWMutex
assertAttributeValueArgsForCall []struct {
arg1 string
arg2 string
}
assertAttributeValueReturns struct {
result1 error
}
assertAttributeValueReturnsOnCall map[int]struct {
result1 error
}
GetAttributeValueStub func(string) (string, bool, error)
getAttributeValueMutex sync.RWMutex
getAttributeValueArgsForCall []struct {
arg1 string
}
getAttributeValueReturns struct {
result1 string
result2 bool
result3 error
}
getAttributeValueReturnsOnCall map[int]struct {
result1 string
result2 bool
result3 error
}
GetIDStub func() (string, error)
getIDMutex sync.RWMutex
getIDArgsForCall []struct {
}
getIDReturns struct {
result1 string
result2 error
}
getIDReturnsOnCall map[int]struct {
result1 string
result2 error
}
GetMSPIDStub func() (string, error)
getMSPIDMutex sync.RWMutex
getMSPIDArgsForCall []struct {
}
getMSPIDReturns struct {
result1 string
result2 error
}
getMSPIDReturnsOnCall map[int]struct {
result1 string
result2 error
}
GetX509CertificateStub func() (*x509.Certificate, error)
getX509CertificateMutex sync.RWMutex
getX509CertificateArgsForCall []struct {
}
getX509CertificateReturns struct {
result1 *x509.Certificate
result2 error
}
getX509CertificateReturnsOnCall map[int]struct {
result1 *x509.Certificate
result2 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *ClientIdentity) AssertAttributeValue(arg1 string, arg2 string) error {
fake.assertAttributeValueMutex.Lock()
ret, specificReturn := fake.assertAttributeValueReturnsOnCall[len(fake.assertAttributeValueArgsForCall)]
fake.assertAttributeValueArgsForCall = append(fake.assertAttributeValueArgsForCall, struct {
arg1 string
arg2 string
}{arg1, arg2})
fake.recordInvocation("AssertAttributeValue", []interface{}{arg1, arg2})
fake.assertAttributeValueMutex.Unlock()
if fake.AssertAttributeValueStub != nil {
return fake.AssertAttributeValueStub(arg1, arg2)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.assertAttributeValueReturns
return fakeReturns.result1
}
func (fake *ClientIdentity) AssertAttributeValueCallCount() int {
fake.assertAttributeValueMutex.RLock()
defer fake.assertAttributeValueMutex.RUnlock()
return len(fake.assertAttributeValueArgsForCall)
}
func (fake *ClientIdentity) AssertAttributeValueCalls(stub func(string, string) error) {
fake.assertAttributeValueMutex.Lock()
defer fake.assertAttributeValueMutex.Unlock()
fake.AssertAttributeValueStub = stub
}
func (fake *ClientIdentity) AssertAttributeValueArgsForCall(i int) (string, string) {
fake.assertAttributeValueMutex.RLock()
defer fake.assertAttributeValueMutex.RUnlock()
argsForCall := fake.assertAttributeValueArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2
}
func (fake *ClientIdentity) AssertAttributeValueReturns(result1 error) {
fake.assertAttributeValueMutex.Lock()
defer fake.assertAttributeValueMutex.Unlock()
fake.AssertAttributeValueStub = nil
fake.assertAttributeValueReturns = struct {
result1 error
}{result1}
}
func (fake *ClientIdentity) AssertAttributeValueReturnsOnCall(i int, result1 error) {
fake.assertAttributeValueMutex.Lock()
defer fake.assertAttributeValueMutex.Unlock()
fake.AssertAttributeValueStub = nil
if fake.assertAttributeValueReturnsOnCall == nil {
fake.assertAttributeValueReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.assertAttributeValueReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *ClientIdentity) GetAttributeValue(arg1 string) (string, bool, error) {
fake.getAttributeValueMutex.Lock()
ret, specificReturn := fake.getAttributeValueReturnsOnCall[len(fake.getAttributeValueArgsForCall)]
fake.getAttributeValueArgsForCall = append(fake.getAttributeValueArgsForCall, struct {
arg1 string
}{arg1})
fake.recordInvocation("GetAttributeValue", []interface{}{arg1})
fake.getAttributeValueMutex.Unlock()
if fake.GetAttributeValueStub != nil {
return fake.GetAttributeValueStub(arg1)
}
if specificReturn {
return ret.result1, ret.result2, ret.result3
}
fakeReturns := fake.getAttributeValueReturns
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
}
func (fake *ClientIdentity) GetAttributeValueCallCount() int {
fake.getAttributeValueMutex.RLock()
defer fake.getAttributeValueMutex.RUnlock()
return len(fake.getAttributeValueArgsForCall)
}
func (fake *ClientIdentity) GetAttributeValueCalls(stub func(string) (string, bool, error)) {
fake.getAttributeValueMutex.Lock()
defer fake.getAttributeValueMutex.Unlock()
fake.GetAttributeValueStub = stub
}
func (fake *ClientIdentity) GetAttributeValueArgsForCall(i int) string {
fake.getAttributeValueMutex.RLock()
defer fake.getAttributeValueMutex.RUnlock()
argsForCall := fake.getAttributeValueArgsForCall[i]
return argsForCall.arg1
}
func (fake *ClientIdentity) GetAttributeValueReturns(result1 string, result2 bool, result3 error) {
fake.getAttributeValueMutex.Lock()
defer fake.getAttributeValueMutex.Unlock()
fake.GetAttributeValueStub = nil
fake.getAttributeValueReturns = struct {
result1 string
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *ClientIdentity) GetAttributeValueReturnsOnCall(i int, result1 string, result2 bool, result3 error) {
fake.getAttributeValueMutex.Lock()
defer fake.getAttributeValueMutex.Unlock()
fake.GetAttributeValueStub = nil
if fake.getAttributeValueReturnsOnCall == nil {
fake.getAttributeValueReturnsOnCall = make(map[int]struct {
result1 string
result2 bool
result3 error
})
}
fake.getAttributeValueReturnsOnCall[i] = struct {
result1 string
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *ClientIdentity) GetID() (string, error) {
fake.getIDMutex.Lock()
ret, specificReturn := fake.getIDReturnsOnCall[len(fake.getIDArgsForCall)]
fake.getIDArgsForCall = append(fake.getIDArgsForCall, struct {
}{})
fake.recordInvocation("GetID", []interface{}{})
fake.getIDMutex.Unlock()
if fake.GetIDStub != nil {
return fake.GetIDStub()
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.getIDReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *ClientIdentity) GetIDCallCount() int {
fake.getIDMutex.RLock()
defer fake.getIDMutex.RUnlock()
return len(fake.getIDArgsForCall)
}
func (fake *ClientIdentity) GetIDCalls(stub func() (string, error)) {
fake.getIDMutex.Lock()
defer fake.getIDMutex.Unlock()
fake.GetIDStub = stub
}
func (fake *ClientIdentity) GetIDReturns(result1 string, result2 error) {
fake.getIDMutex.Lock()
defer fake.getIDMutex.Unlock()
fake.GetIDStub = nil
fake.getIDReturns = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *ClientIdentity) GetIDReturnsOnCall(i int, result1 string, result2 error) {
fake.getIDMutex.Lock()
defer fake.getIDMutex.Unlock()
fake.GetIDStub = nil
if fake.getIDReturnsOnCall == nil {
fake.getIDReturnsOnCall = make(map[int]struct {
result1 string
result2 error
})
}
fake.getIDReturnsOnCall[i] = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *ClientIdentity) GetMSPID() (string, error) {
fake.getMSPIDMutex.Lock()
ret, specificReturn := fake.getMSPIDReturnsOnCall[len(fake.getMSPIDArgsForCall)]
fake.getMSPIDArgsForCall = append(fake.getMSPIDArgsForCall, struct {
}{})
fake.recordInvocation("GetMSPID", []interface{}{})
fake.getMSPIDMutex.Unlock()
if fake.GetMSPIDStub != nil {
return fake.GetMSPIDStub()
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.getMSPIDReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *ClientIdentity) GetMSPIDCallCount() int {
fake.getMSPIDMutex.RLock()
defer fake.getMSPIDMutex.RUnlock()
return len(fake.getMSPIDArgsForCall)
}
func (fake *ClientIdentity) GetMSPIDCalls(stub func() (string, error)) {
fake.getMSPIDMutex.Lock()
defer fake.getMSPIDMutex.Unlock()
fake.GetMSPIDStub = stub
}
func (fake *ClientIdentity) GetMSPIDReturns(result1 string, result2 error) {
fake.getMSPIDMutex.Lock()
defer fake.getMSPIDMutex.Unlock()
fake.GetMSPIDStub = nil
fake.getMSPIDReturns = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *ClientIdentity) GetMSPIDReturnsOnCall(i int, result1 string, result2 error) {
fake.getMSPIDMutex.Lock()
defer fake.getMSPIDMutex.Unlock()
fake.GetMSPIDStub = nil
if fake.getMSPIDReturnsOnCall == nil {
fake.getMSPIDReturnsOnCall = make(map[int]struct {
result1 string
result2 error
})
}
fake.getMSPIDReturnsOnCall[i] = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *ClientIdentity) GetX509Certificate() (*x509.Certificate, error) {
fake.getX509CertificateMutex.Lock()
ret, specificReturn := fake.getX509CertificateReturnsOnCall[len(fake.getX509CertificateArgsForCall)]
fake.getX509CertificateArgsForCall = append(fake.getX509CertificateArgsForCall, struct {
}{})
fake.recordInvocation("GetX509Certificate", []interface{}{})
fake.getX509CertificateMutex.Unlock()
if fake.GetX509CertificateStub != nil {
return fake.GetX509CertificateStub()
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.getX509CertificateReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *ClientIdentity) GetX509CertificateCallCount() int {
fake.getX509CertificateMutex.RLock()
defer fake.getX509CertificateMutex.RUnlock()
return len(fake.getX509CertificateArgsForCall)
}
func (fake *ClientIdentity) GetX509CertificateCalls(stub func() (*x509.Certificate, error)) {
fake.getX509CertificateMutex.Lock()
defer fake.getX509CertificateMutex.Unlock()
fake.GetX509CertificateStub = stub
}
func (fake *ClientIdentity) GetX509CertificateReturns(result1 *x509.Certificate, result2 error) {
fake.getX509CertificateMutex.Lock()
defer fake.getX509CertificateMutex.Unlock()
fake.GetX509CertificateStub = nil
fake.getX509CertificateReturns = struct {
result1 *x509.Certificate
result2 error
}{result1, result2}
}
func (fake *ClientIdentity) GetX509CertificateReturnsOnCall(i int, result1 *x509.Certificate, result2 error) {
fake.getX509CertificateMutex.Lock()
defer fake.getX509CertificateMutex.Unlock()
fake.GetX509CertificateStub = nil
if fake.getX509CertificateReturnsOnCall == nil {
fake.getX509CertificateReturnsOnCall = make(map[int]struct {
result1 *x509.Certificate
result2 error
})
}
fake.getX509CertificateReturnsOnCall[i] = struct {
result1 *x509.Certificate
result2 error
}{result1, result2}
}
func (fake *ClientIdentity) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.assertAttributeValueMutex.RLock()
defer fake.assertAttributeValueMutex.RUnlock()
fake.getAttributeValueMutex.RLock()
defer fake.getAttributeValueMutex.RUnlock()
fake.getIDMutex.RLock()
defer fake.getIDMutex.RUnlock()
fake.getMSPIDMutex.RLock()
defer fake.getMSPIDMutex.RUnlock()
fake.getX509CertificateMutex.RLock()
defer fake.getX509CertificateMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *ClientIdentity) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}

View file

@ -0,0 +1,232 @@
// Code generated by counterfeiter. DO NOT EDIT.
package mocks
import (
"sync"
"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
)
type StateQueryIterator struct {
CloseStub func() error
closeMutex sync.RWMutex
closeArgsForCall []struct {
}
closeReturns struct {
result1 error
}
closeReturnsOnCall map[int]struct {
result1 error
}
HasNextStub func() bool
hasNextMutex sync.RWMutex
hasNextArgsForCall []struct {
}
hasNextReturns struct {
result1 bool
}
hasNextReturnsOnCall map[int]struct {
result1 bool
}
NextStub func() (*queryresult.KV, error)
nextMutex sync.RWMutex
nextArgsForCall []struct {
}
nextReturns struct {
result1 *queryresult.KV
result2 error
}
nextReturnsOnCall map[int]struct {
result1 *queryresult.KV
result2 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *StateQueryIterator) Close() error {
fake.closeMutex.Lock()
ret, specificReturn := fake.closeReturnsOnCall[len(fake.closeArgsForCall)]
fake.closeArgsForCall = append(fake.closeArgsForCall, struct {
}{})
fake.recordInvocation("Close", []interface{}{})
fake.closeMutex.Unlock()
if fake.CloseStub != nil {
return fake.CloseStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.closeReturns
return fakeReturns.result1
}
func (fake *StateQueryIterator) CloseCallCount() int {
fake.closeMutex.RLock()
defer fake.closeMutex.RUnlock()
return len(fake.closeArgsForCall)
}
func (fake *StateQueryIterator) CloseCalls(stub func() error) {
fake.closeMutex.Lock()
defer fake.closeMutex.Unlock()
fake.CloseStub = stub
}
func (fake *StateQueryIterator) CloseReturns(result1 error) {
fake.closeMutex.Lock()
defer fake.closeMutex.Unlock()
fake.CloseStub = nil
fake.closeReturns = struct {
result1 error
}{result1}
}
func (fake *StateQueryIterator) CloseReturnsOnCall(i int, result1 error) {
fake.closeMutex.Lock()
defer fake.closeMutex.Unlock()
fake.CloseStub = nil
if fake.closeReturnsOnCall == nil {
fake.closeReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.closeReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *StateQueryIterator) HasNext() bool {
fake.hasNextMutex.Lock()
ret, specificReturn := fake.hasNextReturnsOnCall[len(fake.hasNextArgsForCall)]
fake.hasNextArgsForCall = append(fake.hasNextArgsForCall, struct {
}{})
fake.recordInvocation("HasNext", []interface{}{})
fake.hasNextMutex.Unlock()
if fake.HasNextStub != nil {
return fake.HasNextStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.hasNextReturns
return fakeReturns.result1
}
func (fake *StateQueryIterator) HasNextCallCount() int {
fake.hasNextMutex.RLock()
defer fake.hasNextMutex.RUnlock()
return len(fake.hasNextArgsForCall)
}
func (fake *StateQueryIterator) HasNextCalls(stub func() bool) {
fake.hasNextMutex.Lock()
defer fake.hasNextMutex.Unlock()
fake.HasNextStub = stub
}
func (fake *StateQueryIterator) HasNextReturns(result1 bool) {
fake.hasNextMutex.Lock()
defer fake.hasNextMutex.Unlock()
fake.HasNextStub = nil
fake.hasNextReturns = struct {
result1 bool
}{result1}
}
func (fake *StateQueryIterator) HasNextReturnsOnCall(i int, result1 bool) {
fake.hasNextMutex.Lock()
defer fake.hasNextMutex.Unlock()
fake.HasNextStub = nil
if fake.hasNextReturnsOnCall == nil {
fake.hasNextReturnsOnCall = make(map[int]struct {
result1 bool
})
}
fake.hasNextReturnsOnCall[i] = struct {
result1 bool
}{result1}
}
func (fake *StateQueryIterator) Next() (*queryresult.KV, error) {
fake.nextMutex.Lock()
ret, specificReturn := fake.nextReturnsOnCall[len(fake.nextArgsForCall)]
fake.nextArgsForCall = append(fake.nextArgsForCall, struct {
}{})
fake.recordInvocation("Next", []interface{}{})
fake.nextMutex.Unlock()
if fake.NextStub != nil {
return fake.NextStub()
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.nextReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *StateQueryIterator) NextCallCount() int {
fake.nextMutex.RLock()
defer fake.nextMutex.RUnlock()
return len(fake.nextArgsForCall)
}
func (fake *StateQueryIterator) NextCalls(stub func() (*queryresult.KV, error)) {
fake.nextMutex.Lock()
defer fake.nextMutex.Unlock()
fake.NextStub = stub
}
func (fake *StateQueryIterator) NextReturns(result1 *queryresult.KV, result2 error) {
fake.nextMutex.Lock()
defer fake.nextMutex.Unlock()
fake.NextStub = nil
fake.nextReturns = struct {
result1 *queryresult.KV
result2 error
}{result1, result2}
}
func (fake *StateQueryIterator) NextReturnsOnCall(i int, result1 *queryresult.KV, result2 error) {
fake.nextMutex.Lock()
defer fake.nextMutex.Unlock()
fake.NextStub = nil
if fake.nextReturnsOnCall == nil {
fake.nextReturnsOnCall = make(map[int]struct {
result1 *queryresult.KV
result2 error
})
}
fake.nextReturnsOnCall[i] = struct {
result1 *queryresult.KV
result2 error
}{result1, result2}
}
func (fake *StateQueryIterator) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.closeMutex.RLock()
defer fake.closeMutex.RUnlock()
fake.hasNextMutex.RLock()
defer fake.hasNextMutex.RUnlock()
fake.nextMutex.RLock()
defer fake.nextMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *StateQueryIterator) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}

View file

@ -0,0 +1,164 @@
// Code generated by counterfeiter. DO NOT EDIT.
package mocks
import (
"sync"
"github.com/hyperledger/fabric-chaincode-go/pkg/cid"
"github.com/hyperledger/fabric-chaincode-go/shim"
)
type TransactionContext struct {
GetClientIdentityStub func() cid.ClientIdentity
getClientIdentityMutex sync.RWMutex
getClientIdentityArgsForCall []struct {
}
getClientIdentityReturns struct {
result1 cid.ClientIdentity
}
getClientIdentityReturnsOnCall map[int]struct {
result1 cid.ClientIdentity
}
GetStubStub func() shim.ChaincodeStubInterface
getStubMutex sync.RWMutex
getStubArgsForCall []struct {
}
getStubReturns struct {
result1 shim.ChaincodeStubInterface
}
getStubReturnsOnCall map[int]struct {
result1 shim.ChaincodeStubInterface
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *TransactionContext) GetClientIdentity() cid.ClientIdentity {
fake.getClientIdentityMutex.Lock()
ret, specificReturn := fake.getClientIdentityReturnsOnCall[len(fake.getClientIdentityArgsForCall)]
fake.getClientIdentityArgsForCall = append(fake.getClientIdentityArgsForCall, struct {
}{})
fake.recordInvocation("GetClientIdentity", []interface{}{})
fake.getClientIdentityMutex.Unlock()
if fake.GetClientIdentityStub != nil {
return fake.GetClientIdentityStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.getClientIdentityReturns
return fakeReturns.result1
}
func (fake *TransactionContext) GetClientIdentityCallCount() int {
fake.getClientIdentityMutex.RLock()
defer fake.getClientIdentityMutex.RUnlock()
return len(fake.getClientIdentityArgsForCall)
}
func (fake *TransactionContext) GetClientIdentityCalls(stub func() cid.ClientIdentity) {
fake.getClientIdentityMutex.Lock()
defer fake.getClientIdentityMutex.Unlock()
fake.GetClientIdentityStub = stub
}
func (fake *TransactionContext) GetClientIdentityReturns(result1 cid.ClientIdentity) {
fake.getClientIdentityMutex.Lock()
defer fake.getClientIdentityMutex.Unlock()
fake.GetClientIdentityStub = nil
fake.getClientIdentityReturns = struct {
result1 cid.ClientIdentity
}{result1}
}
func (fake *TransactionContext) GetClientIdentityReturnsOnCall(i int, result1 cid.ClientIdentity) {
fake.getClientIdentityMutex.Lock()
defer fake.getClientIdentityMutex.Unlock()
fake.GetClientIdentityStub = nil
if fake.getClientIdentityReturnsOnCall == nil {
fake.getClientIdentityReturnsOnCall = make(map[int]struct {
result1 cid.ClientIdentity
})
}
fake.getClientIdentityReturnsOnCall[i] = struct {
result1 cid.ClientIdentity
}{result1}
}
func (fake *TransactionContext) GetStub() shim.ChaincodeStubInterface {
fake.getStubMutex.Lock()
ret, specificReturn := fake.getStubReturnsOnCall[len(fake.getStubArgsForCall)]
fake.getStubArgsForCall = append(fake.getStubArgsForCall, struct {
}{})
fake.recordInvocation("GetStub", []interface{}{})
fake.getStubMutex.Unlock()
if fake.GetStubStub != nil {
return fake.GetStubStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.getStubReturns
return fakeReturns.result1
}
func (fake *TransactionContext) GetStubCallCount() int {
fake.getStubMutex.RLock()
defer fake.getStubMutex.RUnlock()
return len(fake.getStubArgsForCall)
}
func (fake *TransactionContext) GetStubCalls(stub func() shim.ChaincodeStubInterface) {
fake.getStubMutex.Lock()
defer fake.getStubMutex.Unlock()
fake.GetStubStub = stub
}
func (fake *TransactionContext) GetStubReturns(result1 shim.ChaincodeStubInterface) {
fake.getStubMutex.Lock()
defer fake.getStubMutex.Unlock()
fake.GetStubStub = nil
fake.getStubReturns = struct {
result1 shim.ChaincodeStubInterface
}{result1}
}
func (fake *TransactionContext) GetStubReturnsOnCall(i int, result1 shim.ChaincodeStubInterface) {
fake.getStubMutex.Lock()
defer fake.getStubMutex.Unlock()
fake.GetStubStub = nil
if fake.getStubReturnsOnCall == nil {
fake.getStubReturnsOnCall = make(map[int]struct {
result1 shim.ChaincodeStubInterface
})
}
fake.getStubReturnsOnCall[i] = struct {
result1 shim.ChaincodeStubInterface
}{result1}
}
func (fake *TransactionContext) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.getClientIdentityMutex.RLock()
defer fake.getClientIdentityMutex.RUnlock()
fake.getStubMutex.RLock()
defer fake.getStubMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *TransactionContext) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}

View file

@ -1,4 +1,4 @@
module github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/go module github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go
go 1.14 go 1.14
@ -11,14 +11,15 @@ require (
github.com/golang/protobuf v1.4.2 // indirect github.com/golang/protobuf v1.4.2 // indirect
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a github.com/hyperledger/fabric-chaincode-go v0.0.0-20200511190512-bcfeb58dd83a
github.com/hyperledger/fabric-contract-api-go v1.1.0 github.com/hyperledger/fabric-contract-api-go v1.1.0
github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 // indirect github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23
github.com/mailru/easyjson v0.7.1 // indirect github.com/mailru/easyjson v0.7.1 // indirect
github.com/rogpeppe/go-internal v1.6.0 // indirect github.com/rogpeppe/go-internal v1.6.0 // indirect
github.com/stretchr/testify v1.5.1
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect
golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 // indirect golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666 // indirect
google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986 // indirect google.golang.org/genproto v0.0.0-20200721032028-5044d0edf986 // indirect
google.golang.org/grpc v1.30.0 // indirect google.golang.org/grpc v1.30.0 // indirect
google.golang.org/protobuf v1.25.0 // indirect google.golang.org/protobuf v1.25.0
gopkg.in/yaml.v2 v2.3.0 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect
) )

View file

@ -0,0 +1,23 @@
/*
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"log"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-samples/asset-transfer-private-data/chaincode-go/chaincode"
)
func main() {
assetChaincode, err := contractapi.NewChaincode(&chaincode.SmartContract{})
if err != nil {
log.Panicf("Error creating asset-transfer-private-data chaincode: %v", err)
}
if err := assetChaincode.Start(); err != nil {
log.Panicf("Error starting asset-transfer-private-data chaincode: %v", err)
}
}