mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 07:25:10 +00:00
Move off chain data samples to basic chaincode
Signed-off-by: NIKHIL E GUPTA <ngupta@symbridge.com>
This commit is contained in:
parent
327e3a78aa
commit
6d196bd9df
8 changed files with 189 additions and 382 deletions
|
|
@ -10,9 +10,9 @@ CouchDB.
|
|||
|
||||
## Getting started
|
||||
|
||||
This sample uses Node Fabric SDK application code similar to the `fabcar` sample
|
||||
to connect to a running instance of the Fabric test network. Make sure that you
|
||||
are running the following commands from the `off_chain_data` directory.
|
||||
This sample uses Node Fabric SDK application code to connect to a running instance
|
||||
of the Fabric test network. Make sure that you are running the following
|
||||
commands from the `off_chain_data` directory.
|
||||
|
||||
### Starting the Network
|
||||
|
||||
|
|
@ -25,7 +25,8 @@ Use the following command to start the sample network:
|
|||
This command will deploy an instance of the Fabric test network. The network
|
||||
consists of an ordering service, two peer organizations with one peers each, and
|
||||
a CA for each org. The command also creates a channel named `mychannel`. The
|
||||
marbles chaincode will be installed on both peers and deployed to the channel.
|
||||
`asset-transfer-basic` chaincode will be installed on both peers and deployed to
|
||||
the channel.
|
||||
|
||||
### Configuration
|
||||
|
||||
|
|
@ -55,10 +56,11 @@ If you set the "use_couchdb" option to true in `config.json`, you can run the
|
|||
following command start a local instance of CouchDB using docker:
|
||||
|
||||
```
|
||||
docker run --publish 5990:5984 --detach --name offchaindb couchdb
|
||||
docker run --publish 5990:5984 --detach --name offchaindb couchdb:2.3.1
|
||||
docker start offchaindb
|
||||
```
|
||||
|
||||
|
||||
### Install dependencies
|
||||
|
||||
You need to install Node.js version 8.9.x to use the sample application code.
|
||||
|
|
@ -92,53 +94,7 @@ node blockEventListener.js
|
|||
|
||||
If the command is successful, you should see the output of the listener reading
|
||||
the configuration blocks of `mychannel` in addition to the blocks that recorded
|
||||
the approval and commitment of the marbles chaincode definition.
|
||||
|
||||
```
|
||||
Listening for block events, nextblock: 0
|
||||
Added block 0 to ProcessingMap
|
||||
Added block 1 to ProcessingMap
|
||||
Added block 2 to ProcessingMap
|
||||
Added block 3 to ProcessingMap
|
||||
Added block 4 to ProcessingMap
|
||||
Added block 5 to ProcessingMap
|
||||
Added block 6 to ProcessingMap
|
||||
------------------------------------------------
|
||||
Block Number: 0
|
||||
------------------------------------------------
|
||||
Block Number: 1
|
||||
------------------------------------------------
|
||||
Block Number: 2
|
||||
------------------------------------------------
|
||||
Block Number: 3
|
||||
Block Timestamp: 2019-08-08T19:47:56.148Z
|
||||
ChaincodeID: _lifecycle
|
||||
[]
|
||||
------------------------------------------------
|
||||
Block Number: 4
|
||||
Block Timestamp: 2019-08-08T19:48:00.234Z
|
||||
ChaincodeID: _lifecycle
|
||||
[]
|
||||
------------------------------------------------
|
||||
Block Number: 5
|
||||
Block Timestamp: 2019-08-08T19:48:14.092Z
|
||||
ChaincodeID: _lifecycle
|
||||
[ { key: 'namespaces/fields/marbles/Collections',
|
||||
is_delete: false,
|
||||
value: '\u0012\u0000' },
|
||||
{ key: 'namespaces/fields/marbles/EndorsementInfo',
|
||||
is_delete: false,
|
||||
value: '\u0012\r\n\u00031.0\u0010\u0001\u001a\u0004escc' },
|
||||
{ key: 'namespaces/fields/marbles/Sequence',
|
||||
is_delete: false,
|
||||
value: '\b\u0001' },
|
||||
{ key: 'namespaces/fields/marbles/ValidationInfo',
|
||||
is_delete: false,
|
||||
value: '\u00122\n\u0004vscc\u0012*\n(\u0012\f\u0012\n\b\u0002\u0012\u0002\b\u0000\u0012\u0002\b\u0001\u001a\u000b\u0012\t\n\u0007Org1MSP\u001a\u000b\u0012\t\n\u0007Org2MSP' },
|
||||
{ key: 'namespaces/metadata/marbles',
|
||||
is_delete: false,
|
||||
value: '\n\u0013ChaincodeDefinition\u0012\bSequence\u0012\u000fEndorsementInfo\u0012\u000eValidationInfo\u0012\u000bCollections' } ]
|
||||
```
|
||||
the approval and commitment of the assets chaincode definition.
|
||||
|
||||
`blockEventListener.js` creates a listener named "offchain-listener" on the
|
||||
channel `mychannel`. The listener writes each block added to the channel to a
|
||||
|
|
@ -157,7 +113,7 @@ read-write set.
|
|||
|
||||
The channel event listener also writes metadata from each block to a log file
|
||||
defined as channelid_chaincodeid.log. In this example, events will be written to
|
||||
a file named `mychannel_marbles.log`. This allows you to record a history of
|
||||
a file named `mychannel_basic.log`. This allows you to record a history of
|
||||
changes made by each block for each key in addition to storing the latest value
|
||||
of the world state.
|
||||
|
||||
|
|
@ -166,42 +122,42 @@ new window to execute the next parts of the demo.
|
|||
|
||||
### Generate data on the blockchain
|
||||
|
||||
Now that our listener is setup, we can generate data using the marbles chaincode
|
||||
Now that our listener is setup, we can generate data using the assets chaincode
|
||||
and use our application to replicate the data to our database. Open a new
|
||||
terminal and navigate to the `fabric-samples/off_chain_data` directory.
|
||||
|
||||
You can use the `addMarbles.js` file to add random sample data to blockchain.
|
||||
The file uses the configuration information stored in `addMarbles.json` to
|
||||
create a series of marbles. This file will be created during the first execution
|
||||
of `addMarbles.js` if it does not exist. This program can be run multiple times
|
||||
without changing the properties. The `nextMarbleNumber` will be incremented and
|
||||
stored in the `addMarbles.json` file.
|
||||
You can use the `addAssets.js` file to add random sample data to blockchain.
|
||||
The file uses the configuration information stored in `addAssets.json` to
|
||||
create a series of assets. This file will be created during the first execution
|
||||
of `addAssets.js` if it does not exist. This program can be run multiple times
|
||||
without changing the properties. The `nextAssetNumber` will be incremented and
|
||||
stored in the `addAssets.json` file.
|
||||
|
||||
```
|
||||
{
|
||||
"nextMarbleNumber": 100,
|
||||
"numberMarblesToAdd": 20
|
||||
"nextAssetNumber": 100,
|
||||
"numberAssetsToAdd": 20
|
||||
}
|
||||
```
|
||||
|
||||
Open a new window and run the following command to add 20 marbles to the
|
||||
Open a new window and run the following command to add 20 assets to the
|
||||
blockchain:
|
||||
|
||||
```
|
||||
node addMarbles.js
|
||||
node addAssets.js
|
||||
```
|
||||
|
||||
After the marbles have been added to the ledger, use the following command to
|
||||
transfer one of the marbles to a new owner:
|
||||
After the assets have been added to the ledger, use the following command to
|
||||
transfer one of the assets to a new owner:
|
||||
|
||||
```
|
||||
node transferMarble.js marble110 james
|
||||
node transferAsset.js asset110 james
|
||||
```
|
||||
|
||||
Now run the following command to delete the marble that was transferred:
|
||||
Now run the following command to delete the asset that was transferred:
|
||||
|
||||
```
|
||||
node deleteMarble.js marble110
|
||||
node deleteAsset.js asset110
|
||||
```
|
||||
|
||||
## Offchain CouchDB storage:
|
||||
|
|
@ -215,17 +171,17 @@ The first table is an offline representation of the current world state of the
|
|||
blockchain ledger. This table was created using the read-write set data from
|
||||
the blocks. If the listener is running, this table should be the same as the
|
||||
latest values in the state database running on your peer. The table is named
|
||||
after the channelid and chaincodeid, and is named mychannel_marbles in this
|
||||
after the channelid and chaincodeid, and is named mychannel_basic in this
|
||||
example. You can navigate to this table using your browser:
|
||||
http://127.0.0.1:5990/mychannel_marbles/_all_docs
|
||||
http://127.0.0.1:5990/mychannel_basic/_all_docs
|
||||
|
||||
A second table records each block as a historical record entry, and was created
|
||||
using the block data that was recorded in the log file. The table name appends
|
||||
history to the name of the first table, and is named mychannel_marbles_history
|
||||
history to the name of the first table, and is named mychannel_basic_history
|
||||
in this example. You can also navigate to this table using your browser:
|
||||
http://127.0.0.1:5990/mychannel_marbles_history/_all_docs
|
||||
http://127.0.0.1:5990/mychannel_basic_history/_all_docs
|
||||
|
||||
### Configure a map/reduce view for summarizing counts of marbles by color:
|
||||
### Configure a map/reduce view for summarizing counts of assets by color:
|
||||
|
||||
Now that we have state and history data replicated to tables in CouchDB, we
|
||||
can use the following commands query our off-chain data. We will also add an
|
||||
|
|
@ -236,16 +192,16 @@ created when events are received.
|
|||
Open a new terminal window and execute the following:
|
||||
|
||||
```
|
||||
curl -X PUT http://127.0.0.1:5990/mychannel_marbles/_design/colorviewdesign -d '{"views":{"colorview":{"map":"function (doc) { emit(doc.color, 1);}","reduce":"function ( keys , values , combine ) {return sum( values )}"}}}' -H 'Content-Type:application/json'
|
||||
curl -X PUT http://127.0.0.1:5990/mychannel_basic/_design/colorviewdesign -d '{"views":{"colorview":{"map":"function (doc) { emit(doc.color, 1);}","reduce":"function ( keys , values , combine ) {return sum( values )}"}}}' -H 'Content-Type:application/json'
|
||||
```
|
||||
|
||||
Execute a query to retrieve the total number of marbles (reduce function):
|
||||
Execute a query to retrieve the total number of assets (reduce function):
|
||||
|
||||
```
|
||||
curl -X GET http://127.0.0.1:5990/mychannel_marbles/_design/colorviewdesign/_view/colorview?reduce=true
|
||||
curl -X GET http://127.0.0.1:5990/mychannel_basic/_design/colorviewdesign/_view/colorview?reduce=true
|
||||
```
|
||||
|
||||
If successful, this command will return the number of marbles in the blockchain
|
||||
If successful, this command will return the number of assets in the blockchain
|
||||
world state, without having to query the blockchain ledger:
|
||||
|
||||
```
|
||||
|
|
@ -254,13 +210,13 @@ world state, without having to query the blockchain ledger:
|
|||
]}
|
||||
```
|
||||
|
||||
Execute a new query to retrieve the number of marbles by color (map function):
|
||||
Execute a new query to retrieve the number of assets by color (map function):
|
||||
|
||||
```
|
||||
curl -X GET http://127.0.0.1:5990/mychannel_marbles/_design/colorviewdesign/_view/colorview?group=true
|
||||
curl -X GET http://127.0.0.1:5990/mychannel_basic/_design/colorviewdesign/_view/colorview?group=true
|
||||
```
|
||||
|
||||
The command will return a list of marbles by color from the CouchDB database.
|
||||
The command will return a list of assets by color from the CouchDB database.
|
||||
|
||||
```
|
||||
{"rows":[
|
||||
|
|
@ -275,27 +231,27 @@ The command will return a list of marbles by color from the CouchDB database.
|
|||
|
||||
To run a more complex command that reads through the block history database, we
|
||||
will create an index of the blocknumber, sequence, and key fields. This index
|
||||
will support a query that traces the history of each marble. Execute the
|
||||
will support a query that traces the history of each asset. Execute the
|
||||
following command to create the index:
|
||||
|
||||
```
|
||||
curl -X POST http://127.0.0.1:5990/mychannel_marbles_history/_index -d '{"index":{"fields":["blocknumber", "sequence", "key"]},"name":"marble_history"}' -H 'Content-Type:application/json'
|
||||
curl -X POST http://127.0.0.1:5990/mychannel_basic_history/_index -d '{"index":{"fields":["blocknumber", "sequence", "key"]},"name":"asset_history"}' -H 'Content-Type:application/json'
|
||||
```
|
||||
|
||||
Now execute a query to retrieve the history for the marble we transferred and
|
||||
Now execute a query to retrieve the history for the asset we transferred and
|
||||
then deleted:
|
||||
|
||||
```
|
||||
curl -X POST http://127.0.0.1:5990/mychannel_marbles_history/_find -d '{"selector":{"key":{"$eq":"marble110"}}, "fields":["blocknumber","is_delete","value"],"sort":[{"blocknumber":"asc"}, {"sequence":"asc"}]}' -H 'Content-Type:application/json'
|
||||
curl -X POST http://127.0.0.1:5990/mychannel_basic_history/_find -d '{"selector":{"key":{"$eq":"asset110"}}, "fields":["blocknumber","is_delete","value"],"sort":[{"blocknumber":"asc"}, {"sequence":"asc"}]}' -H 'Content-Type:application/json'
|
||||
```
|
||||
|
||||
You should see the transaction history of the marble that was created,
|
||||
You should see the transaction history of the asset that was created,
|
||||
transferred, and then removed from the ledger.
|
||||
|
||||
```
|
||||
{"docs":[
|
||||
{"blocknumber":12,"is_delete":false,"value":"{\"docType\":\"marble\",\"name\":\"marble110\",\"color\":\"blue\",\"size\":60,\"owner\":\"debra\"}"},
|
||||
{"blocknumber":22,"is_delete":false,"value":"{\"docType\":\"marble\",\"name\":\"marble110\",\"color\":\"blue\",\"size\":60,\"owner\":\"james\"}"},
|
||||
{"blocknumber":12,"is_delete":false,"value":"{\"docType\":\"asset\",\"name\":\"asset110\",\"color\":\"blue\",\"size\":60,\"owner\":\"debra\"}"},
|
||||
{"blocknumber":22,"is_delete":false,"value":"{\"docType\":\"asset\",\"name\":\"asset110\",\"color\":\"blue\",\"size\":60,\"owner\":\"james\"}"},
|
||||
{"blocknumber":23,"is_delete":true,"value":""}
|
||||
]}
|
||||
```
|
||||
|
|
@ -309,19 +265,19 @@ have missed.
|
|||
|
||||
If you ran through the example steps above, navigate back to the terminal window
|
||||
where `blockEventListener.js` is running and close it. Once the listener is no
|
||||
longer running, use the following command to add 20 more marbles to the
|
||||
longer running, use the following command to add 20 more assets to the
|
||||
ledger:
|
||||
|
||||
```
|
||||
node addMarbles.js
|
||||
node addAssets.js
|
||||
```
|
||||
|
||||
The listener will not be able to add the new marbles to your CouchDB database.
|
||||
The listener will not be able to add the new assets to your CouchDB database.
|
||||
If you check the current state table using the reduce command, you will only
|
||||
be able to see the original marbles in your database.
|
||||
be able to see the original assets in your database.
|
||||
|
||||
```
|
||||
curl -X GET http://127.0.0.1:5990/mychannel_marbles/_design/colorviewdesign/_view/colorview?reduce=true
|
||||
curl -X GET http://127.0.0.1:5990/mychannel_basic/_design/colorviewdesign/_view/colorview?reduce=true
|
||||
```
|
||||
|
||||
To add the new data to your off-chain database, remove the `nextblock.txt`
|
||||
|
|
@ -337,15 +293,15 @@ You can new re-run the channel listener to read every block from the channel:
|
|||
node blockEventListener.js
|
||||
```
|
||||
|
||||
This will rebuild the CouchDB tables and include the 20 marbles that have been
|
||||
This will rebuild the CouchDB tables and include the 20 assets that have been
|
||||
added to the ledger. If you run the reduce command against your database one
|
||||
more time,
|
||||
|
||||
```
|
||||
curl -X GET http://127.0.0.1:5990/mychannel_marbles/_design/colorviewdesign/_view/colorview?reduce=true
|
||||
curl -X GET http://127.0.0.1:5990/mychannel_basic/_design/colorviewdesign/_view/colorview?reduce=true
|
||||
```
|
||||
|
||||
you will be able to see that all of the marbles have been added to your
|
||||
you will be able to see that all of the assets have been added to your
|
||||
database:
|
||||
|
||||
```
|
||||
|
|
@ -369,4 +325,4 @@ Running the script will complete the following actions:
|
|||
* Remove the certificates you generated by deleting the `wallet` folder.
|
||||
* Delete `nextblock.txt` so you can start with the first block next time you
|
||||
operate the listener.
|
||||
* Removes `addMarbles.json`.
|
||||
* Removes `addAssets.json`.
|
||||
|
|
|
|||
118
off_chain_data/addAssets.js
Normal file
118
off_chain_data/addAssets.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* addAssets.js will add random sample data to blockchain.
|
||||
*
|
||||
* $ node addAssets.js
|
||||
*
|
||||
* addAssets will add 10 Assets by default with a starting Asset name of "Asset100".
|
||||
* Additional Assets will be added by incrementing the number at the end of the Asset name.
|
||||
*
|
||||
* The properties for adding Assets are stored in addAssets.json. This file will be created
|
||||
* during the first execution of the utility if it does not exist. The utility can be run
|
||||
* multiple times without changing the properties. The nextAssetNumber will be incremented and
|
||||
* stored in the JSON file.
|
||||
*
|
||||
* {
|
||||
* "nextAssetNumber": 100,
|
||||
* "numberAssetsToAdd": 10
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Wallets, Gateway } = require('fabric-network');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const addAssetsConfigFile = path.resolve(__dirname, 'addAssets.json');
|
||||
|
||||
const colors=[ 'blue', 'red', 'yellow', 'green', 'white', 'purple' ];
|
||||
const owners=[ 'tom', 'fred', 'julie', 'james', 'janet', 'henry', 'alice', 'marie', 'sam', 'debra', 'nancy'];
|
||||
const sizes=[ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ];
|
||||
const appraisedValues=[ 300, 310, 320, 330, 340, 350, 360, 370, 380, 390 ];
|
||||
const docType='asset'
|
||||
|
||||
const config = require('./config.json');
|
||||
const channelid = config.channelid;
|
||||
|
||||
async function main() {
|
||||
|
||||
try {
|
||||
|
||||
let nextAssetNumber;
|
||||
let numberAssetsToAdd;
|
||||
let addAssetsConfig;
|
||||
|
||||
// check to see if there is a config json defined
|
||||
if (fs.existsSync(addAssetsConfigFile)) {
|
||||
// read file the next asset and number of assets to create
|
||||
let addAssetsConfigJSON = fs.readFileSync(addAssetsConfigFile, 'utf8');
|
||||
addAssetsConfig = JSON.parse(addAssetsConfigJSON);
|
||||
nextAssetNumber = addAssetsConfig.nextAssetNumber;
|
||||
numberAssetsToAdd = addAssetsConfig.numberAssetsToAdd;
|
||||
} else {
|
||||
nextAssetNumber = 100;
|
||||
numberAssetsToAdd = 20;
|
||||
// create a default config and save
|
||||
addAssetsConfig = new Object;
|
||||
addAssetsConfig.nextAssetNumber = nextAssetNumber;
|
||||
addAssetsConfig.numberAssetsToAdd = numberAssetsToAdd;
|
||||
fs.writeFileSync(addAssetsConfigFile, JSON.stringify(addAssetsConfig, null, 2));
|
||||
}
|
||||
|
||||
// Parse the connection profile.
|
||||
const ccpPath = path.resolve(__dirname, '..', 'test-network','organizations','peerOrganizations','org1.example.com', 'connection-org1.json');
|
||||
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
// Configure a wallet. This wallet must already be primed with an identity that
|
||||
// the application can use to interact with the peer node.
|
||||
const walletPath = path.resolve(__dirname, 'wallet');
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
|
||||
// Create a new gateway, and connect to the gateway peer node(s). The identity
|
||||
// specified must already exist in the specified wallet.
|
||||
const gateway = new Gateway();
|
||||
await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } });
|
||||
|
||||
// Get the network channel that the smart contract is deployed to.
|
||||
const network = await gateway.getNetwork(channelid);
|
||||
|
||||
// Get the smart contract from the network channel.
|
||||
const contract = network.getContract('basic');
|
||||
|
||||
for (var counter = nextAssetNumber; counter < nextAssetNumber + numberAssetsToAdd; counter++) {
|
||||
|
||||
var randomColor = Math.floor(Math.random() * (6));
|
||||
var randomOwner = Math.floor(Math.random() * (11));
|
||||
var randomSize = Math.floor(Math.random() * (10));
|
||||
var randomValue = Math.floor(Math.random() * (9));
|
||||
|
||||
// Submit the 'CreateAsset' transaction to the smart contract, and wait for it
|
||||
// to be committed to the ledger.
|
||||
await contract.submitTransaction('CreateAsset', docType+counter, colors[randomColor], ''+sizes[randomSize], owners[randomOwner],appraisedValues[randomValue]);
|
||||
console.log("Adding asset: " + docType + counter + " owner:" + owners[randomOwner] + " color:" + colors[randomColor] + " size:" + '' + sizes[randomSize] + " appraised value:" + '' + appraisedValues[randomValue] );
|
||||
|
||||
}
|
||||
|
||||
await gateway.disconnect();
|
||||
|
||||
addAssetsConfig.nextAssetNumber = nextAssetNumber + numberAssetsToAdd;
|
||||
|
||||
fs.writeFileSync(addAssetsConfigFile, JSON.stringify(addAssetsConfig, null, 2));
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Failed to submit transaction: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* Copyright IBM Corp. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* addMarbles.js will add random sample data to blockchain.
|
||||
*
|
||||
* $ node addMarbles.js
|
||||
*
|
||||
* addMarbles will add 10 marbles by default with a starting marble name of "marble100".
|
||||
* Additional marbles will be added by incrementing the number at the end of the marble name.
|
||||
*
|
||||
* The properties for adding marbles are stored in addMarbles.json. This file will be created
|
||||
* during the first execution of the utility if it does not exist. The utility can be run
|
||||
* multiple times without changing the properties. The nextMarbleNumber will be incremented and
|
||||
* stored in the JSON file.
|
||||
*
|
||||
* {
|
||||
* "nextMarbleNumber": 100,
|
||||
* "numberMarblesToAdd": 10
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { Wallets, Gateway } = require('fabric-network');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const addMarblesConfigFile = path.resolve(__dirname, 'addMarbles.json');
|
||||
|
||||
const colors=[ 'blue', 'red', 'yellow', 'green', 'white', 'purple' ];
|
||||
const owners=[ 'tom', 'fred', 'julie', 'james', 'janet', 'henry', 'alice', 'marie', 'sam', 'debra', 'nancy'];
|
||||
const sizes=[ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ];
|
||||
const docType='marble'
|
||||
|
||||
const config = require('./config.json');
|
||||
const channelid = config.channelid;
|
||||
|
||||
async function main() {
|
||||
|
||||
try {
|
||||
|
||||
let nextMarbleNumber;
|
||||
let numberMarblesToAdd;
|
||||
let addMarblesConfig;
|
||||
|
||||
// check to see if there is a config json defined
|
||||
if (fs.existsSync(addMarblesConfigFile)) {
|
||||
// read file the next marble and number of marbles to create
|
||||
let addMarblesConfigJSON = fs.readFileSync(addMarblesConfigFile, 'utf8');
|
||||
addMarblesConfig = JSON.parse(addMarblesConfigJSON);
|
||||
nextMarbleNumber = addMarblesConfig.nextMarbleNumber;
|
||||
numberMarblesToAdd = addMarblesConfig.numberMarblesToAdd;
|
||||
} else {
|
||||
nextMarbleNumber = 100;
|
||||
numberMarblesToAdd = 20;
|
||||
// create a default config and save
|
||||
addMarblesConfig = new Object;
|
||||
addMarblesConfig.nextMarbleNumber = nextMarbleNumber;
|
||||
addMarblesConfig.numberMarblesToAdd = numberMarblesToAdd;
|
||||
fs.writeFileSync(addMarblesConfigFile, JSON.stringify(addMarblesConfig, null, 2));
|
||||
}
|
||||
|
||||
// Parse the connection profile. This would be the path to the file downloaded
|
||||
// from the IBM Blockchain Platform operational console.
|
||||
const ccpPath = path.resolve(__dirname, '..', 'test-network','organizations','peerOrganizations','org1.example.com', 'connection-org1.json');
|
||||
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
// Configure a wallet. This wallet must already be primed with an identity that
|
||||
// the application can use to interact with the peer node.
|
||||
const walletPath = path.resolve(__dirname, 'wallet');
|
||||
const wallet = await Wallets.newFileSystemWallet(walletPath);
|
||||
|
||||
// Create a new gateway, and connect to the gateway peer node(s). The identity
|
||||
// specified must already exist in the specified wallet.
|
||||
const gateway = new Gateway();
|
||||
await gateway.connect(ccp, { wallet, identity: 'appUser', discovery: { enabled: true, asLocalhost: true } });
|
||||
|
||||
// Get the network channel that the smart contract is deployed to.
|
||||
const network = await gateway.getNetwork(channelid);
|
||||
|
||||
// Get the smart contract from the network channel.
|
||||
const contract = network.getContract('marbles');
|
||||
|
||||
for (var counter = nextMarbleNumber; counter < nextMarbleNumber + numberMarblesToAdd; counter++) {
|
||||
|
||||
var randomColor = Math.floor(Math.random() * (6));
|
||||
var randomOwner = Math.floor(Math.random() * (11));
|
||||
var randomSize = Math.floor(Math.random() * (10));
|
||||
|
||||
// Submit the 'initMarble' transaction to the smart contract, and wait for it
|
||||
// to be committed to the ledger.
|
||||
await contract.submitTransaction('initMarble', docType+counter, colors[randomColor], ''+sizes[randomSize], owners[randomOwner]);
|
||||
console.log("Adding marble: " + docType + counter + " owner:" + owners[randomOwner] + " color:" + colors[randomColor] + " size:" + '' + sizes[randomSize] );
|
||||
|
||||
}
|
||||
|
||||
await gateway.disconnect();
|
||||
|
||||
addMarblesConfig.nextMarbleNumber = nextMarbleNumber + numberMarblesToAdd;
|
||||
|
||||
fs.writeFileSync(addMarblesConfigFile, JSON.stringify(addMarblesConfig, null, 2));
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Failed to submit transaction: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
/*
|
||||
*
|
||||
* deleteMarble.js will delete a specified marble. Example:
|
||||
* deleteAsset.js will delete a specified asset. Example:
|
||||
*
|
||||
* $ node deleteMarble.js marble100
|
||||
* $ node deleteAsset.js asset100
|
||||
*
|
||||
* The utility is meant to demonstrate delete block events.
|
||||
*/
|
||||
|
|
@ -26,7 +26,7 @@ const channelid = config.channelid;
|
|||
async function main() {
|
||||
|
||||
if (process.argv[2] == undefined) {
|
||||
console.log("Usage: node deleteMarble marbleId");
|
||||
console.log("Usage: node deleteAsset AssetId");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -34,8 +34,7 @@ async function main() {
|
|||
|
||||
try {
|
||||
|
||||
// Parse the connection profile. This would be the path to the file downloaded
|
||||
// from the IBM Blockchain Platform operational console.
|
||||
// Parse the connection profile.
|
||||
const ccpPath = path.resolve(__dirname, '..', 'test-network','organizations','peerOrganizations','org1.example.com', 'connection-org1.json');
|
||||
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
|
|
@ -53,10 +52,10 @@ async function main() {
|
|||
const network = await gateway.getNetwork(channelid);
|
||||
|
||||
// Get the smart contract from the network channel.
|
||||
const contract = network.getContract('marbles');
|
||||
const contract = network.getContract('basic');
|
||||
|
||||
await contract.submitTransaction('delete', deletekey);
|
||||
console.log("Deleted marble: " + deletekey);
|
||||
await contract.submitTransaction('DeleteAsset', deletekey);
|
||||
console.log("Deleted asset: " + deletekey);
|
||||
|
||||
await gateway.disconnect();
|
||||
|
||||
|
|
@ -14,7 +14,7 @@ popd
|
|||
|
||||
# clean out any old identites in the wallets
|
||||
rm -rf wallet
|
||||
rm -rf addMarbles.json mychannel_marbles.log mychannel__lifecycle.log nextblock.txt
|
||||
rm -rf addAssets.json mychannel_basic.log mychannel__lifecycle.log nextblock.txt
|
||||
|
||||
docker stop offchaindb
|
||||
docker rm offchaindb
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
"author": "Hyperledger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"fabric-ca-client": "^2.1.0",
|
||||
"fabric-network": "^2.1.0"
|
||||
"fabric-ca-client": "^2.2.0",
|
||||
"fabric-network": "^2.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^4.2.0",
|
||||
|
|
|
|||
|
|
@ -7,161 +7,13 @@
|
|||
# Exit on first error
|
||||
set -e pipefail
|
||||
|
||||
# don't rewrite paths for Windows Git Bash users
|
||||
export MSYS_NO_PATHCONV=1
|
||||
starttime=$(date +%s)
|
||||
CC_SRC_LANGUAGE=golang
|
||||
CC_RUNTIME_LANGUAGE=golang
|
||||
CC_SRC_PATH=../chaincode/marbles02/go
|
||||
|
||||
echo Vendoring Go dependencies ...
|
||||
pushd ../chaincode/marbles02/go
|
||||
GO111MODULE=on go mod vendor
|
||||
popd
|
||||
echo Finished vendoring Go dependencies
|
||||
|
||||
# launch network; create channel and join peer to channel
|
||||
pushd ../test-network
|
||||
./network.sh down
|
||||
./network.sh up createChannel -ca -s couchdb
|
||||
|
||||
export PATH=${PWD}/../bin:${PWD}:$PATH
|
||||
export FABRIC_CFG_PATH=${PWD}/../config
|
||||
|
||||
# import environment variables
|
||||
. scripts/envVar.sh
|
||||
|
||||
echo "Packaging the marbles smart contract"
|
||||
|
||||
setGlobals 1
|
||||
|
||||
peer lifecycle chaincode package marbles.tar.gz \
|
||||
--path $CC_SRC_PATH \
|
||||
--lang $CC_RUNTIME_LANGUAGE \
|
||||
--label marblesv1
|
||||
|
||||
echo "Installing smart contract on peer0.org1.example.com"
|
||||
|
||||
peer lifecycle chaincode install marbles.tar.gz
|
||||
|
||||
|
||||
echo "Installing smart contract on peer0.org2.example.com"
|
||||
|
||||
setGlobals 2
|
||||
|
||||
peer lifecycle chaincode install marbles.tar.gz
|
||||
|
||||
|
||||
echo "Query the chaincode package id"
|
||||
|
||||
setGlobals 1
|
||||
|
||||
peer lifecycle chaincode queryinstalled >&log.txt
|
||||
|
||||
PACKAGE_ID=$(sed -n "/marblesv1/{s/^Package ID: //; s/, Label:.*$//; p;}" log.txt)
|
||||
|
||||
echo "Approving the chaincode definition for org1.example.com"
|
||||
|
||||
peer lifecycle chaincode approveformyorg \
|
||||
-o localhost:7050 \
|
||||
--ordererTLSHostnameOverride orderer.example.com \
|
||||
--channelID mychannel \
|
||||
--name marbles \
|
||||
--version 1.0 \
|
||||
--init-required \
|
||||
--signature-policy AND"('Org1MSP.member','Org2MSP.member')" \
|
||||
--sequence 1 \
|
||||
--package-id $PACKAGE_ID \
|
||||
--tls \
|
||||
--cafile ${ORDERER_CA}
|
||||
|
||||
echo "Approving the chaincode definition for org2.example.com"
|
||||
|
||||
setGlobals 2
|
||||
|
||||
peer lifecycle chaincode approveformyorg \
|
||||
-o localhost:7050 \
|
||||
--ordererTLSHostnameOverride orderer.example.com \
|
||||
--channelID mychannel \
|
||||
--name marbles \
|
||||
--version 1.0 \
|
||||
--init-required \
|
||||
--signature-policy AND"('Org1MSP.member','Org2MSP.member')" \
|
||||
--sequence 1 \
|
||||
--package-id $PACKAGE_ID \
|
||||
--tls \
|
||||
--cafile ${ORDERER_CA}
|
||||
|
||||
echo "Checking if the chaincode definition is ready to commit"
|
||||
|
||||
peer lifecycle chaincode checkcommitreadiness \
|
||||
--channelID mychannel \
|
||||
--name marbles \
|
||||
--version 1.0 \
|
||||
--sequence 1 \
|
||||
--output json \
|
||||
--init-required \
|
||||
--signature-policy AND"('Org1MSP.member','Org2MSP.member')" >&log.txt
|
||||
|
||||
rc=0
|
||||
for var in "\"Org1MSP\": true" "\"Org2MSP\": true"
|
||||
do
|
||||
grep "$var" log.txt &>/dev/null || let rc=1
|
||||
done
|
||||
|
||||
if test $rc -eq 0; then
|
||||
echo "Chaincode definition is ready to commit"
|
||||
else
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
parsePeerConnectionParameters 1 2
|
||||
|
||||
echo "Commit the chaincode definition to the channel"
|
||||
|
||||
peer lifecycle chaincode commit \
|
||||
-o localhost:7050 \
|
||||
--ordererTLSHostnameOverride orderer.example.com \
|
||||
--channelID mychannel \
|
||||
--name marbles \
|
||||
--version 1.0 \
|
||||
--init-required \
|
||||
--signature-policy AND"('Org1MSP.member','Org2MSP.member')" \
|
||||
--sequence 1 \
|
||||
--tls \
|
||||
--cafile ${ORDERER_CA} \
|
||||
$PEER_CONN_PARMS
|
||||
|
||||
echo "Check if the chaincode has been committed to the channel ..."
|
||||
|
||||
peer lifecycle chaincode querycommitted \
|
||||
--channelID mychannel \
|
||||
--name marbles >&log.txt
|
||||
|
||||
EXPECTED_RESULT="Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc"
|
||||
VALUE=$(grep -o "Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc" log.txt)
|
||||
echo "$VALUE"
|
||||
|
||||
if [ "$VALUE" = "Version: 1.0, Sequence: 1, Endorsement Plugin: escc, Validation Plugin: vscc" ] ; then
|
||||
echo "chaincode has been committed"
|
||||
else
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
echo "invoke the marbles chaincode init function ... "
|
||||
|
||||
peer chaincode invoke \
|
||||
-o localhost:7050 \
|
||||
--ordererTLSHostnameOverride orderer.example.com \
|
||||
-C mychannel \
|
||||
-n marbles \
|
||||
--isInit \
|
||||
-c '{"Args":["Init"]}' \
|
||||
--tls \
|
||||
--cafile ${ORDERER_CA} \
|
||||
$PEER_CONN_PARMS
|
||||
|
||||
rm log.txt
|
||||
./network.sh deployCC
|
||||
|
||||
popd
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* tranferMarble.js will transfer ownership a specified marble to a new ownder. Example:
|
||||
* tranferAsset.js will transfer ownership a specified asset to a new ownder. Example:
|
||||
*
|
||||
* $ node transferMarble.js marble102 jimmy
|
||||
* $ node transferAsset.js asset102 jimmy
|
||||
*
|
||||
* The utility is meant to demonstrate update block events.
|
||||
*/
|
||||
|
|
@ -25,7 +25,7 @@ const channelid = config.channelid;
|
|||
async function main() {
|
||||
|
||||
if (process.argv[2] == undefined && process.argv[3] == undefined) {
|
||||
console.log("Usage: node changeMarbleOwner.js marbleId owner");
|
||||
console.log("Usage: node transferAsset.js assetId owner");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -34,8 +34,7 @@ async function main() {
|
|||
|
||||
try {
|
||||
|
||||
// Parse the connection profile. This would be the path to the file downloaded
|
||||
// from the IBM Blockchain Platform operational console.
|
||||
// Parse the connection profile.
|
||||
const ccpPath = path.resolve(__dirname, '..', 'test-network','organizations','peerOrganizations','org1.example.com', 'connection-org1.json');
|
||||
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
|
||||
|
||||
|
|
@ -53,10 +52,10 @@ async function main() {
|
|||
const network = await gateway.getNetwork(channelid);
|
||||
|
||||
// Get the smart contract from the network channel.
|
||||
const contract = network.getContract('marbles');
|
||||
const contract = network.getContract('basic');
|
||||
|
||||
await contract.submitTransaction('transferMarble', updatekey, newowner);
|
||||
console.log("Transferred marble " + updatekey + " to " + newowner);
|
||||
await contract.submitTransaction('TransferAsset', updatekey, newowner);
|
||||
console.log("Transferred asset " + updatekey + " to " + newowner);
|
||||
|
||||
await gateway.disconnect();
|
||||
|
||||
Loading…
Reference in a new issue