Compare commits

...

5 commits
main ... v2.2.3

Author SHA1 Message Date
Justin Yang
ad8fc2fba7
test-network: Make the regexp of checking version more strict (backpo… (#516)
* Updated dependencies for Json and fabric-chaincode-shim:2.+ in java samples (#481)

* fixed json dependencies for java

Signed-off-by: fraVlaca <ocsenarf@outlook.com>

* updated dependency for asset-tranfer-sbe: now declaing also org.hyperledger.fabric.protos.common

Signed-off-by: fraVlaca <ocsenarf@outlook.com>

* "corrected typo of last commit and added testImplementation 'org.hyperledger.fabric.protos.common'"

Signed-off-by: fraVlaca <ocsenarf@outlook.com>

* included correct dependecy for fabric-protos and added com.google.protobuf as well

Signed-off-by: fraVlaca <ocsenarf@outlook.com>
Signed-off-by: Justin Yang <justin.yang@themedium.io>

* test-network: Make the regexp of checking version more strict (backport #515)

Signed-off-by: Justin Yang <justin.yang@themedium.io>

* Updated dependencies fabric-chaincode-shim:2.2.+ in java samples from 2.+

Signed-off-by: Justin Yang <justin.yang@themedium.io>

Co-authored-by: fraVlaca <86831094+fraVlaca@users.noreply.github.com>
2021-11-01 08:40:29 +00:00
denyeart
e496083c0b
Remove .env Files and Explicitly Name Network (#417) (#469)
There have been lots of changes and quirks with the
docker-compose .env file, this change removes the file
and explicitly creates and assigns the networks in the
compose yaml files.

Signed-off-by: Brett Logan <lindluni@github.com>
Signed-off-by: David Enyeart <enyeart@us.ibm.com>

Co-authored-by: Brett Logan <lindluni@github.com>
2021-08-30 11:59:19 -04:00
denyeart
46b92e22da
Update asset-transfer-basic go chaincode dependencies (release-2.2) (#461)
Update asset-transfer-basic go chaincode dependencies to latest
commits from release-2.2 dependency branches.

Signed-off-by: David Enyeart <enyeart@us.ibm.com>
2021-08-11 13:54:35 +01:00
Dave Kelsey
42c7d4a142
New HSM Typescript Sample (#458)
Add a new sample in typescript to show how to use an HSM within a client
node application

Signed-off-by: D <d_kelsey@uk.ibm.com>

Co-authored-by: D <d_kelsey@uk.ibm.com>
2021-07-06 13:39:42 +01:00
Varad Ramamoorthy
b2a89cffbc
expose operations port (#454)
Signed-off-by: Varad Ramamoorthy <varad@us.ibm.com>
2021-07-06 08:38:57 +01:00
26 changed files with 888 additions and 45 deletions

View file

@ -0,0 +1,15 @@
#
# SPDX-License-Identifier: Apache-2.0
#
# Coverage directory used by tools like istanbul
coverage
# Dependency directories
node_modules/
jspm_packages/
# Compiled TypeScript files
dist

View file

@ -0,0 +1,263 @@
# Asset Transfer Basic typescript HSM sample
This sample takes the Asset Transfer basic example and re-works it to focus on how
you would use a Hardware Security Modules within your node client application.
## About the Sample
This typescript sample application is able to use any of the asset transfer basic
chaincode samples. It will show how to register users with a Fabric CA and enroll users which will store keys in an HSM (In this case the sample uses SoftHSM which is an HSM implementation that should be used for development and testing purposes only). It also demonstrates setting up a wallet that will store identities that can then be used to transact on the fabric network which are HSM managed.
## C Compilers
In order for the client application to run successfully you must ensure you have C compilers and Python 3 (Note that Python 2 may still work however Python 2 is out of support and could stop working in the future) installed otherwise the node dependency `pkcs11js` will not be built and the application will fail. The failure will look like
```
Loaded the network configuration located at /home/dave/temp/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/connection-org1.json
******** FAILED to run the application: Error: Cannot find module 'pkcs11js'
Require stack:
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-common/lib/impl/bccsp_pkcs11.js
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-common/lib/Utils.js
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-common/index.js
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-ca-client/lib/FabricCAServices.js
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/node_modules/fabric-ca-client/index.js
- /home/dave/temp/fabric-samples/asset-transfer-basic/application-typescript-hsm/dist/app.js
```
how to install the required C Compilers and Python will depend on your operating system and version.
## Configuring and running a Hardware Security Module
This sample sets the hsmOptions for the wallet as follows
```javascript
const softHSMOptions: HsmOptions = {
lib: await findSoftHSMPKCS11Lib(),
pin: process.env.PKCS11_PIN || '98765432',
label: process.env.PKCS11_LABEL || 'ForFabric',
};
```
which is specific to using SoftHSM which has been initialised with a token labelled `ForFabric`
and a user pin of `98765432`, however you can override these values to use your own HSM by either
editting the application or use these environment variables to pass in the values:
* PKCS11_LIB - path to the your specific HSM Library
* PKCS11_PIN - your HSM pin
* PKCS11_LABEL - your HSM label
Alternatively you could install SoftHSM to try out the application as described in the next sections
### Install SoftHSM
In order to run the application in the absence of a real HSM, a software
emulator of the PKCS#11 interface is required.
For more information please refer to [SoftHSM](https://www.opendnssec.org/softhsm/).
SoftHSM can either be installed using the package manager for your host system:
* Ubuntu: `sudo apt install softhsm2`
* macOS: `brew install softhsm`
* Windows: **unsupported**
Or compiled and installed from source:
1. install openssl 1.0.0+ or botan 1.10.0+
2. download the source code from <https://dist.opendnssec.org/source/softhsm-2.5.0.tar.gz>
3. `tar -xvf softhsm-2.5.0.tar.gz`
4. `cd softhsm-2.5.0`
5. `./configure --disable-gost` (would require additional libraries, turn it off unless you need 'gost' algorithm support for the Russian market)
6. `make`
7. `sudo make install`
### Specify the SoftHSM configuration file
A configuration file for SoftHSM is provided in this sample directory. This file
uses /tmp as the location for SoftHSM to store it's data which means (depending on
your operating system configuration) the data could be deleted at some point, for example
when you reboot your system. If this data is lost then you will have to delete the wallet
created. An alternative is to change this file to store SoftHSM data in a permanent location
on your file system.
To use this configuration file you need to export an environment variable to point to it
for example, if you are in the application directory then you can use the following command
```bash
export SOFTHSM2_CONF=$PWD/softhsm2.conf
```
Ensure you have this set when initializing the token as well as running the application
### Initialize a token to store keys in SoftHSM
If you have not initialized a token previously (or it has been deleted) then you will need to perform this one time operation
```bash
softhsm2-util --init-token --slot 0 --label "ForFabric" --pin 98765432 --so-pin 1234
```
The Security Officer PIN, specified with the `--so-pin` flag, can be used to re-initialize the token,
and the user PIN (see below), specified with the `--pin` flag, is used by applications to access the token for
generating and retrieving keys.
## Running the sample
Use the Fabric test network utility (`network.sh`) to start a Fabric network and deploy one
one of the sample chaincodes.
Follow these step in order.
- Start the test network with a Certificate Authority and create a channel, so assuming you are in the ensuring you are in the `application-typescript-hsm` directory
```
cd ../../test-network
./network.sh down
./network.sh up createChannel -c mychannel -ca
```
- Deploy the chaincode (smart contract)
```
# to deploy the javascript version
./network.sh deployCC -ccs 1 -ccv 1 -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -ccl javascript -ccp ./../asset-transfer-basic/chaincode-javascript/ -ccn basic
```
- Run the application
```
cd ../asset-transfer-basic/application-typescript-hsm
npm install
npm run build
node dist/app.js
```
### Expected successful execution
If the sample runs successfully then it will output several messages showing the various actions and finally display the message
```
*** The sample ran successfully ***
```
One the first run of the sample, a CA admin id from Org1 will be enrolled from the CA. The certificate for this admin will be stored in the application wallet but the private key will have been stored in the HSM, it will not be in the application wallet. A User in Org1 will be registered in the the Org1 CA and then enrolled. Again only it's certificate will be stored in the application wallet.
All signing of transactions done by the application (driven by the node sdk) will actually be done by the HSM rather than within the node sdk as the private key will never be directly available outside of the HSM.
This sample can be run multiple times even while the same network remains up. As the certificates are already in the application wallet it will not have to enroll a CA admin or register and enroll a user.
### Possible issues you could encounter running the sample
If you see this error:
```
******** FAILED to run the application: Pkcs11Error: CKR_GENERAL_ERROR
```
Make sure you have exported SOFTHSM2_CONF correctly and it points to a valid SoftHSM configuration file that references
a directory containing a initialised SoftHSM token
If you see this error:
```
2020-08-07T20:23:17.590Z - error: [DiscoveryService]: send[mychannel] - Channel:mychannel received discovery error:access denied
******** FAILED to run the application: Error: DiscoveryService: mychannel error: access denied
```
Then the current certificates in your wallet are not valid for the network you are trying to interact with. This would happen if you had
shutdown the fabric network using `network.sh down` and created a new network because this causes all the root certificates to be recreated
To address this problem, you can delete the `wallet` directory in the `dist` folder (`fabric-samples/asset-transfer-basic/application-typescript-hsm/dist/wallet`) of this sample to create new certificates. Because new keypairs are generated these will be stored in SoftHSM and the existing old ones will not be referenced
If you see this error
```
Failed to register user : Error: fabric-ca request register failed with errors [[ { code: 20, message: 'Authentication failure' } ]]
******** FAILED to run the application: Error: Identity not found in wallet: appUser
```
Then the most likely cause is you have deleted your wallet. You would need to either
- stop and create a new fabric network using the `network.sh down` and then following the above instructions to start a new fabric network (but you should not re-initialize the softhsm token)
- or change the application such that it registers a new user instead of `appUser`. This is because be default a registered user can only be enrolled once (using the userid and it's secret)
If you see this error
```
******** FAILED to run the application: Error: _pkcs11OpenSession[336]: PKCS11 label ForFabric cannot be found in the slot list
```
Then the SoftHSM token directory has been deleted (could be due to the /tmp file being cleaned up if you use the sample softhsm2.conf file provided).
You will either need to
- delete your existing wallet, bring down the network as described in `Clean up` section and recreate the network including re-initializing the softhsm token
- or you could just re-initialise the softhsm token but you will need to change the application so that it registers a new user instead of `appUser`
If you see this error (note the number following `SKI` will not be the same)
```
******** FAILED to run the application: Error: _pkcs11SkiToHandle[572]: no key with SKI 27f3557183cd5f26384ab69968ba74944c94c0e24f681c4fadd6502886891da0 found
```
Then the certificates in your wallet do not have corresponding keys in SoftHSM. You can should bring down the network and delete your current wallet (as described in `Clean up` section) and create the network again
If you see either of these errors when the application ends
```
free(): double free detected in tcache 2
Aborted
```
or
```
node[61480]: ../src/node_http2.cc:521:void node::http2::Http2Session::CheckAllocatedSize(size_t) const: Assertion `(current_nghttp2_memory_) >= (previous_size)' failed.
1: 0xa1a640 node::Abort() [node]
2: 0xa1a6be [node]
3: 0xa55e2a node::mem::NgLibMemoryManager<node::http2::Http2Session, nghttp2_mem>::ReallocImpl(void*, unsigned long, void*) [node]
4: 0xa55ed3 node::mem::NgLibMemoryManager<node::http2::Http2Session, nghttp2_mem>::FreeImpl(void*, void*) [node]
5: 0x18b0388 nghttp2_session_close_stream [node]
6: 0x18b76ea nghttp2_session_mem_recv [node]
7: 0xa54937 node::http2::Http2Session::ConsumeHTTP2Data() [node]
8: 0xa54d5e node::http2::Http2Session::OnStreamRead(long, uv_buf_t const&) [node]
9: 0xb6a651 node::TLSWrap::ClearOut() [node]
10: 0xb6bcdb node::TLSWrap::OnStreamRead(long, uv_buf_t const&) [node]
11: 0xaf54b1 [node]
12: 0x137fed9 [node]
13: 0x1380500 [node]
14: 0x1386de5 [node]
15: 0x137458f uv_run [node]
16: 0xa5d7a6 node::NodeMainInstance::Run() [node]
17: 0x9eab6c node::Start(int, char**) [node]
18: 0x7fd7612180b3 __libc_start_main [/lib/x86_64-linux-gnu/libc.so.6]
19: 0x981fe5 [node]
Aborted (core dumped)
```
then this is due to a bug in `node`. May sure you are using the latest supported version of node, however at the time of writing (node 14.17.1 & node 12.22.1) a fix had not been released by node.js
### Enabling Node SDK logging
To see the SDK workings, try setting the logging to show on the console before running
```
export HFC_LOGGING='{"debug":"console"}'
```
or log to a file
```
export HFC_LOGGING='{"debug":"./debug.log"}'
```
## Clean up
When you are finished, you can bring down the test network.
The command will remove all the nodes of the test network, and delete any
ledger data that you created:
```bash
cd ../../test-network
./network.sh down
```
Be sure to delete the wallet directory create by the application.
The stored identities will no longer be valid when restarting the network.
For example if you are in the application-typescript-hsm directory
```bash
rm -fr dist/wallet
```
## Suggestions
When typescript node applications log problems or terminate with a stack trace you normally would have to look at the compiled .js code to find the code that was executed in the stack trace. It would be easier if you could find the corresponding lines in the typescript source file. One solution to this problem can be found here https://github.com/evanw/node-source-map-support which will convert stack trace output to corresponding typescript file lines using the generated source maps.

View file

@ -0,0 +1,50 @@
{
"name": "asset-transfer-basic",
"version": "1.0.0",
"description": "Asset Transfer Basic contract implemented in TypeScript",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"engines": {
"node": ">=12",
"npm": ">=5"
},
"scripts": {
"lint": "tslint -c tslint.json 'src/**/*.ts'",
"pretest": "npm run lint",
"start": "npm run build && node dist/app.js",
"build": "tsc",
"build:watch": "tsc -w",
"prepublishOnly": "npm run build"
},
"engineStrict": true,
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-ca-client": "^2.2.8",
"fabric-network": "^2.2.8"
},
"devDependencies": {
"tslint": "^5.11.0",
"typescript": "^3.1.6"
},
"nyc": {
"extension": [
".ts",
".tsx"
],
"exclude": [
"coverage/**",
"dist/**"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}

View file

@ -0,0 +1,5 @@
directories.tokendir = /tmp/
objectstore.backend = file
# ERROR, WARNING, INFO, DEBUG
log.level = INFO

View file

@ -0,0 +1,278 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
import * as FabricCAServices from 'fabric-ca-client';
import { Contract, Gateway, GatewayOptions, HsmOptions, HsmX509Provider, Wallets } from 'fabric-network';
import * as fs from 'fs';
import * as path from 'path';
import { buildCCPOrg1, prettyJSONString } from './utils//AppUtil';
import { enrollUserToWallet, registerUser, UserToEnroll, UserToRegister } from './utils/CAUtil';
const walletPath = path.join(__dirname, 'wallet');
// define information about the channel and chaincode id that will be driven by this application
const channelName = 'mychannel';
const chaincodeId = 'basic';
// define the CA Registrar
const mspOrg1 = 'Org1MSP';
const org1CAAdminUserId = 'admin';
const org1CAAdminSecret = 'adminpw';
// define the user in org1 to use
const org1UserId = 'appUser';
const org1Secret = 'appUserSecret';
const org1Affiliation = 'org1.department1';
type Request = 'submit' | 'evaluate';
interface TransactionToSendFormat {
request: Request;
txName: string;
txArgs: string[];
description?: string;
}
// The set of transactions to be invoked
const transactionsToSend: TransactionToSendFormat[] = [
{
request: 'submit',
txName: 'InitLedger',
txArgs: [],
description: '\n--> Submit Transaction: InitLedger, function creates the initial set of assets on the ledger',
},
{
request: 'evaluate',
txName: 'GetAllAssets',
txArgs: [],
description: '\n--> Evaluate Transaction: GetAllAssets, function returns all the current assets on the ledger',
},
{
request: 'submit',
txName: 'CreateAsset',
txArgs: ['asset13', 'yellow', '5', 'Tom', '1300'],
description: '\n--> Submit Transaction: CreateAsset, creates new asset with ID, color, owner, size, and appraisedValue arguments',
},
{
request: 'evaluate',
txName: 'ReadAsset',
txArgs: ['asset13'],
description: '\n--> Evaluate Transaction: ReadAsset, function returns an asset with a given assetID',
},
{
request: 'evaluate',
txName: 'AssetExists',
txArgs: ['asset1'],
description: '\n--> Evaluate Transaction: AssetExists, function returns "true" if an asset with given assetID exist',
},
{
request: 'submit',
txName: 'UpdateAsset',
txArgs: ['asset1', 'blue', '5', 'Tomoko', '350'],
description: '\n--> Submit Transaction: UpdateAsset asset1, change the appraisedValue to 350',
},
{
request: 'evaluate',
txName: 'ReadAsset',
txArgs: ['asset1'],
description: '\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes',
},
{
request: 'submit',
txName: 'UpdateAsset',
txArgs: ['asset70', 'blue', '5', 'Tomoko', '300'],
description: '\n--> Submit Transaction: UpdateAsset asset70, asset70 does not exist and should return an error',
},
{
request: 'submit',
txName: 'TransferAsset',
txArgs: ['asset1', 'Tom'],
description: '\n--> Submit Transaction: TransferAsset asset1, transfer to new owner of Tom',
},
{
request: 'evaluate',
txName: 'ReadAsset',
txArgs: ['asset1'],
description: '\n--> Evaluate Transaction: ReadAsset, function returns "asset1" attributes',
},
];
/**
* A test application to show basic queries operations with any of the asset-transfer-basic chaincodes
* -- How to submit a transaction
* -- How to query and check the results
*
* To see the SDK workings, try setting the logging to show on the console before running
* export HFC_LOGGING='{"debug":"console"}'
*/
async function main() {
try {
// build an in memory object with the network configuration (also known as a connection profile)
const ccp = buildCCPOrg1();
// softhsm pkcs11 options to use
const softHSMOptions: HsmOptions = {
lib: await findSoftHSMPKCS11Lib(),
pin: process.env.PKCS11_PIN || '98765432',
label: process.env.PKCS11_LABEL || 'ForFabric',
};
// setup the wallet to hold the credentials used by this application
// Here we add the HSM provider to the provider registry of the wallet
const wallet = await Wallets.newFileSystemWallet(walletPath);
const hsmProvider = new HsmX509Provider(softHSMOptions);
wallet.getProviderRegistry().addProvider(hsmProvider);
// build an instance of the fabric ca services client based on
// the information in the network configuration
const caInfo = ccp.certificateAuthorities['ca.org1.example.com']; // lookup CA details from config
const caTLSCACerts = caInfo.tlsCACerts.pem;
// Here we make sure we pass in an HSM enabled cryptosuite to this CA instance
const hsmCAClient = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName, hsmProvider.getCryptoSuite());
console.log(`Built a CA Client named ${caInfo.caName}`);
// enroll the CA admin into the wallet if it doesn't already exist in the wallet
if (!await wallet.get(org1CAAdminUserId)) {
await enrollUserToWallet({
caClient: hsmCAClient,
wallet,
orgMspId: mspOrg1,
userId: org1CAAdminUserId,
userIdSecret: org1CAAdminSecret,
} as UserToEnroll);
}
// if we don't have the required user in the wallet then
// register this user to the CA (if it's not already registered)
// then enroll that user into the wallet
if (!await wallet.get(org1UserId)) {
await registerUser({
caClient: hsmCAClient,
adminId: org1CAAdminUserId,
wallet,
orgMspId: mspOrg1,
userId: org1UserId,
userIdSecret: org1Secret,
affiliation: org1Affiliation,
} as UserToRegister);
// By default you can only enroll a user once, after that you would have to re-enroll using the current
// certificate rather than using the secret.
await enrollUserToWallet({
caClient: hsmCAClient,
wallet,
orgMspId: mspOrg1,
userId: org1UserId,
userIdSecret: org1Secret,
} as UserToEnroll);
}
// Create a new gateway instance for interacting with the fabric network bound to our user
// This sample expects a locally deployed fabric network (ie running on the same machine in docker containers)
// therefore we set asLocalhost to true
const gateway = new Gateway();
const gatewayOpts: GatewayOptions = {
wallet,
identity: org1UserId,
discovery: { enabled: true, asLocalhost: true }, // using asLocalhost as this gateway is using a fabric network deployed locally
};
try {
// setup the gateway instance
// The user will now be able to create connections to the fabric network and be able to
// submit transactions and query. All transactions submitted by this gateway will be
// signed by this user using the credentials stored in the wallet.
await gateway.connect(ccp, gatewayOpts);
// Build a network instance based on the channel where the smart contract is deployed
const network = await gateway.getNetwork(channelName);
// Get the contract from the network.
const contract = network.getContract(chaincodeId);
// loop around all transactions to send, each one will be sent sequentially
// through the same gateway/network/contract as subsequent transations expect the
// previous submits to have been committed
// Note however that a gateway/network/contract can support concurrent submitted
// transactions.
for (const transactionToSend of transactionsToSend) {
await interactWithFabric(contract, transactionToSend);
}
console.log('*** The sample ran successfully ***');
} finally {
// Disconnect from the gateway when the application is closing
// This will close all connections to the network
gateway.disconnect();
}
} catch (error) {
console.error(`******** FAILED to run the application: ${error}`);
}
}
/**
* Determine the location of the SoftHSM PKCS11 Library
* @returns the location of the SoftHSM PKCS11 Library or 'NOT FOUND' if not found
*/
async function findSoftHSMPKCS11Lib() {
const commonSoftHSMPathNames = [
'/usr/lib/softhsm/libsofthsm2.so',
'/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so',
'/usr/local/lib/softhsm/libsofthsm2.so',
'/usr/lib/libacsp-pkcs11.so',
];
let pkcsLibPath = 'NOT FOUND';
if (typeof process.env.PKCS11_LIB === 'string' && process.env.PKCS11_LIB !== '') {
pkcsLibPath = process.env.PKCS11_LIB;
} else {
//
// Check common locations for PKCS library
//
for (const pathnameToTry of commonSoftHSMPathNames) {
if (fs.existsSync(pathnameToTry)) {
pkcsLibPath = pathnameToTry;
break;
}
}
}
return pkcsLibPath;
}
/**
* Interact with the Fabric Network via the Contact with the required transaction to perform.
* @param contract The contract to send the transaction to
* @param transactionToPerform the transaction to perform
*/
async function interactWithFabric(contract: Contract, transactionToPerform: TransactionToSendFormat): Promise<void> {
console.log(transactionToPerform.description);
try {
switch (transactionToPerform.request) {
case 'submit': {
await contract.submitTransaction(transactionToPerform.txName, ...transactionToPerform.txArgs);
console.log('*** Result: committed');
break;
}
case 'evaluate': {
const result = await contract.evaluateTransaction(transactionToPerform.txName, ...transactionToPerform.txArgs);
console.log(`*** Result: ${prettyJSONString(result.toString())}`);
}
}
} catch (error) {
console.log(`*** Successfully caught the error: \n ${error}`);
// In reality applications should check the returned error to decide whether the transaction needs to be retried (ie go through
// endorsement again) for example an MVCC_READ_CONFLICT error, resubmitted to the orderer for example a timeout because it was
// never committed (for example due to networking issues the transaction never gets included in a block), or whether it should
// be reported back, for example they tried to perform an invalid application action.
}
}
// execute the main function
main();

View file

@ -0,0 +1,56 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
import * as fs from 'fs';
import * as path from 'path';
const buildCCPOrg1 = (): Record<string, any> => {
// load the common connection configuration file
const ccpPath = path.resolve(__dirname, '..', '..', '..', '..', 'test-network',
'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
const fileExists = fs.existsSync(ccpPath);
if (!fileExists) {
throw new Error(`no such file or directory: ${ccpPath}`);
}
const contents = fs.readFileSync(ccpPath, 'utf8');
// build a JSON object from the file contents
const ccp = JSON.parse(contents);
console.log(`Loaded the network configuration located at ${ccpPath}`);
return ccp;
};
const buildCCPOrg2 = (): Record<string, any> => {
// load the common connection configuration file
const ccpPath = path.resolve(__dirname, '..', '..', '..', '..', 'test-network',
'organizations', 'peerOrganizations', 'org2.example.com', 'connection-org2.json');
const fileExists = fs.existsSync(ccpPath);
if (!fileExists) {
throw new Error(`no such file or directory: ${ccpPath}`);
}
const contents = fs.readFileSync(ccpPath, 'utf8');
// build a JSON object from the file contents
const ccp = JSON.parse(contents);
console.log(`Loaded the network configuration located at ${ccpPath}`);
return ccp;
};
const prettyJSONString = (inputString: string): string => {
if (inputString) {
return JSON.stringify(JSON.parse(inputString), null, 2);
} else {
return inputString;
}
};
export {
buildCCPOrg1,
buildCCPOrg2,
prettyJSONString,
};

View file

@ -0,0 +1,94 @@
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
import * as FabricCAServices from 'fabric-ca-client';
import { Wallet } from 'fabric-network';
export interface UserToEnroll {
caClient: FabricCAServices;
wallet: Wallet;
orgMspId: string;
userId: string;
userIdSecret: string;
}
/**
* enroll a registered CA user and store the credentials in the wallet
* @param userToEnroll details about the user and the wallet to use
*/
export const enrollUserToWallet = async (userToEnroll: UserToEnroll): Promise<void> => {
try {
// check that the identity isn't already in the wallet
const identity = await userToEnroll.wallet.get(userToEnroll.userId);
if (identity) {
console.log(`Identity ${userToEnroll.userId} already exists in the wallet`);
return;
}
// Enroll the user
const enrollment = await userToEnroll.caClient.enroll({ enrollmentID: userToEnroll.userId, enrollmentSecret: userToEnroll.userIdSecret });
// store the user
const hsmIdentity = {
credentials: {
certificate: enrollment.certificate,
},
mspId: userToEnroll.orgMspId,
type: 'HSM-X.509',
};
await userToEnroll.wallet.put(userToEnroll.userId, hsmIdentity);
console.log(`Successfully enrolled user ${userToEnroll.userId} and imported it into the wallet`);
} catch (error) {
console.error(`Failed to enroll user ${userToEnroll.userId}: ${error}`);
}
};
export interface UserToRegister {
caClient: FabricCAServices;
wallet: Wallet;
orgMspId: string;
adminId: string;
userId: string;
userIdSecret: string;
affiliation: string;
}
export const registerUser = async (userToRegister: UserToRegister): Promise<void> => {
try {
// Must use a CA admin (registrar) to register a new user
const adminIdentity = await userToRegister.wallet.get(userToRegister.adminId);
if (!adminIdentity) {
console.log('An identity for the admin user does not exist in the wallet');
console.log('Enroll the admin user before retrying');
return;
}
// build a user object for authenticating with the CA
const provider = userToRegister.wallet.getProviderRegistry().getProvider(adminIdentity.type);
const adminUser = await provider.getUserContext(adminIdentity, userToRegister.adminId);
// Register the user
// if affiliation is specified by client, the affiliation value must be configured in CA
await userToRegister.caClient.register({
affiliation: userToRegister.affiliation,
enrollmentID: userToRegister.userId,
enrollmentSecret: userToRegister.userIdSecret,
role: 'client',
}, adminUser);
console.log(`Successfully registered ${userToRegister.userId}.`);
return;
} catch (error) {
// check to see if it's an already registered error, if it is, then we can ignore it
// otherwise we rethrow the error
if (error.errors[0].code !== 74) {
console.error(`Failed to register user : ${error}`);
throw error;
}
}
};

View file

@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "dist",
"target": "es2017",
"moduleResolution": "node",
"module": "commonjs",
"declaration": true,
"sourceMap": true,
"noImplicitAny": true,
"strict": true
},
"include": [
"./src/**/*"
],
"exclude": [
"./src/**/*.spec.ts"
]
}

View file

@ -0,0 +1,24 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {},
"rules": {
"indent": [true, "spaces", 4],
"linebreak-style": [true, "LF"],
"quotemark": [true, "single"],
"semicolon": [true, "always"],
"no-console": false,
"curly": true,
"triple-equals": true,
"no-string-throw": true,
"no-var-keyword": true,
"no-trailing-whitespace": true,
"object-literal-key-quotes": [true, "as-needed"],
"object-literal-sort-keys": false,
"max-line-length": false,
"interface-name":false
},
"rulesDirectory": []
}

View file

@ -4,8 +4,8 @@ go 1.14
require (
github.com/golang/protobuf v1.3.2
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212
github.com/hyperledger/fabric-contract-api-go v1.1.0
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e
github.com/hyperledger/fabric-chaincode-go v0.0.0-20210718160520-38d29fabecb9
github.com/hyperledger/fabric-contract-api-go v1.1.1
github.com/hyperledger/fabric-protos-go v0.0.0-20201028172056-a3136dde2354
github.com/stretchr/testify v1.5.1
)

View file

@ -45,11 +45,19 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212 h1:1i4lnpV8BDgKOLi1hgElfBqdHXjXieSuj8629mwBZ8o=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20210718160520-38d29fabecb9 h1:1cAZHHrBYFrX3bwQGhOZtOB4sCM9QWVppd81O8vsPXs=
github.com/hyperledger/fabric-chaincode-go v0.0.0-20210718160520-38d29fabecb9/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc=
github.com/hyperledger/fabric-contract-api-go v1.1.0 h1:K9uucl/6eX3NF0/b+CGIiO1IPm1VYQxBkpnVGJur2S4=
github.com/hyperledger/fabric-contract-api-go v1.1.0/go.mod h1:nHWt0B45fK53owcFpLtAe8DH0Q5P068mnzkNXMPSL7E=
github.com/hyperledger/fabric-contract-api-go v1.1.1 h1:gDhOC18gjgElNZ85kFWsbCQq95hyUP/21n++m0Sv6B0=
github.com/hyperledger/fabric-contract-api-go v1.1.1/go.mod h1:+39cWxbh5py3NtXpRA63rAH7NzXyED+QJx1EZr0tJPo=
github.com/hyperledger/fabric-protos-go v0.0.0-20190919234611-2a87503ac7c9/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e h1:9PS5iezHk/j7XriSlNuSQILyCOfcZ9wZ3/PiucmSE8E=
github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20201028172056-a3136dde2354 h1:6vLLEpvDbSlmUJFjg1hB5YMBpI+WgKguztlONcAFBoY=
github.com/hyperledger/fabric-protos-go v0.0.0-20201028172056-a3136dde2354/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/hyperledger/fabric-protos-go v0.0.0-20210722212527-1ed7094bb8fe h1:1ef+SKRVYiQCAMhZ5W6HZhStEcNNAm27V8YcptzSWnM=
github.com/hyperledger/fabric-protos-go v0.0.0-20210722212527-1ed7094bb8fe/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=

View file

@ -12,10 +12,11 @@ group 'org.hyperledger.fabric.samples'
version '1.0-SNAPSHOT'
dependencies {
compileOnly 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.2.+'
implementation 'org.json:json:+'
implementation 'com.owlike:genson:1.5'
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.2.+'
testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2'
testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation 'org.mockito:mockito-core:2.+'

View file

@ -12,8 +12,9 @@ group 'org.hyperledger.fabric.samples'
version '1.0-SNAPSHOT'
dependencies {
compileOnly 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.2.+'
implementation 'org.json:json:+'
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.2.+'
}
repositories {
@ -48,4 +49,4 @@ jacocoTestReport {
dependsOn test
}
installDist.dependsOn check
installDist.dependsOn check

View file

@ -12,10 +12,11 @@ group 'org.hyperledger.fabric.samples'
version '1.0-SNAPSHOT'
dependencies {
compileOnly 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.2.+'
implementation 'org.json:json:+'
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.2.+'
testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2'
testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation 'org.mockito:mockito-core:2.+'
@ -59,4 +60,4 @@ test {
}
}
installDist.dependsOn check
installDist.dependsOn check

View file

@ -12,10 +12,14 @@ group 'org.hyperledger.fabric.samples'
version '1.0-SNAPSHOT'
dependencies {
compileOnly 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.2.+'
implementation 'org.json:json:+'
implementation 'com.google.protobuf:protobuf-java:3.+'
implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-protos:2.2.+'
implementation 'com.owlike:genson:1.5'
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.+'
testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.2.+'
testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2'
testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation 'org.mockito:mockito-core:2.+'

View file

@ -169,6 +169,8 @@ jobs:
CHAINCODE_LANGUAGE: typescript
steps:
- template: templates/install-deps.yml
- script: sudo apt-get install softhsm2
displayName: Install SoftHSM
- script: ../ci/scripts/run-test-network-basic.sh
workingDirectory: test-network
displayName: Run Test Network Basic Chaincode

View file

@ -63,3 +63,19 @@ print "Running the output app"
node dist/app.js
popd
stopNetwork
# Run typescript HSM application
createNetwork
print "Initializing Typescript HSM application"
pushd ../asset-transfer-basic/application-typescript-hsm
print "Setup SoftHSM"
export SOFTHSM2_CONF=$PWD/softhsm2.conf
softhsm2-util --init-token --slot 0 --label "ForFabric" --pin 98765432 --so-pin 1234
print "install dependencies"
npm install
print "Building app.ts"
npm run build
print "Running the output app"
node dist/app.js
popd
stopNetwork

View file

@ -1,3 +0,0 @@
COMPOSE_PROJECT_NAME=net
IMAGE_TAG=latest
SYS_CHANNEL=system-channel

View file

@ -1,2 +0,0 @@
COMPOSE_PROJECT_NAME=net
IMAGE_TAG=latest

View file

@ -5,10 +5,14 @@
version: '2'
networks:
test:
name: fabric_test
services:
ca_org3:
image: hyperledger/fabric-ca:$IMAGE_TAG
image: hyperledger/fabric-ca:latest
environment:
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_CA_NAME=ca-org3

View file

@ -7,6 +7,7 @@ version: '2'
networks:
test:
name: fabric_test
services:
couchdb4:

View file

@ -10,19 +10,17 @@ volumes:
networks:
test:
name: fabric_test
services:
peer0.org3.example.com:
container_name: peer0.org3.example.com
image: hyperledger/fabric-peer:$IMAGE_TAG
image: hyperledger/fabric-peer:latest
environment:
#Generic peer variables
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_test
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_test
- FABRIC_LOGGING_SPEC=INFO
#- FABRIC_LOGGING_SPEC=DEBUG
- CORE_PEER_TLS_ENABLED=true

View file

@ -7,18 +7,21 @@ version: '2'
networks:
test:
name: fabric_test
services:
ca_org1:
image: hyperledger/fabric-ca:$IMAGE_TAG
image: hyperledger/fabric-ca:latest
environment:
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_CA_NAME=ca-org1
- FABRIC_CA_SERVER_TLS_ENABLED=true
- FABRIC_CA_SERVER_PORT=7054
- FABRIC_CA_SERVER_OPERATIONS_LISTENADDRESS=0.0.0.0:17054
ports:
- "7054:7054"
- "17054:17054"
command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
volumes:
- ../organizations/fabric-ca/org1:/etc/hyperledger/fabric-ca-server
@ -27,14 +30,16 @@ services:
- test
ca_org2:
image: hyperledger/fabric-ca:$IMAGE_TAG
image: hyperledger/fabric-ca:latest
environment:
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_CA_NAME=ca-org2
- FABRIC_CA_SERVER_TLS_ENABLED=true
- FABRIC_CA_SERVER_PORT=8054
- FABRIC_CA_SERVER_OPERATIONS_LISTENADDRESS=0.0.0.0:18054
ports:
- "8054:8054"
- "18054:18054"
command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
volumes:
- ../organizations/fabric-ca/org2:/etc/hyperledger/fabric-ca-server
@ -43,14 +48,16 @@ services:
- test
ca_orderer:
image: hyperledger/fabric-ca:$IMAGE_TAG
image: hyperledger/fabric-ca:latest
environment:
- FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
- FABRIC_CA_SERVER_CA_NAME=ca-orderer
- FABRIC_CA_SERVER_TLS_ENABLED=true
- FABRIC_CA_SERVER_PORT=9054
- FABRIC_CA_SERVER_OPERATIONS_LISTENADDRESS=0.0.0.0:19054
ports:
- "9054:9054"
- "19054:19054"
command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
volumes:
- ../organizations/fabric-ca/ordererOrg:/etc/hyperledger/fabric-ca-server

View file

@ -7,6 +7,7 @@ version: '2'
networks:
test:
name: fabric_test
services:
couchdb0:

View file

@ -12,12 +12,13 @@ volumes:
networks:
test:
name: fabric_test
services:
orderer.example.com:
container_name: orderer.example.com
image: hyperledger/fabric-orderer:$IMAGE_TAG
image: hyperledger/fabric-orderer:latest
environment:
- FABRIC_LOGGING_SPEC=INFO
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
@ -26,6 +27,7 @@ services:
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
- ORDERER_OPERATIONS_LISTENADDRESS=0.0.0.0:17050
# enabled TLS
- ORDERER_GENERAL_TLS_ENABLED=true
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
@ -45,19 +47,17 @@ services:
- orderer.example.com:/var/hyperledger/production/orderer
ports:
- 7050:7050
- 17050:17050
networks:
- test
peer0.org1.example.com:
container_name: peer0.org1.example.com
image: hyperledger/fabric-peer:$IMAGE_TAG
image: hyperledger/fabric-peer:latest
environment:
#Generic peer variables
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_test
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_test
- FABRIC_LOGGING_SPEC=INFO
#- FABRIC_LOGGING_SPEC=DEBUG
- CORE_PEER_TLS_ENABLED=true
@ -74,6 +74,7 @@ services:
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:17051
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- ../organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
@ -83,19 +84,17 @@ services:
command: peer node start
ports:
- 7051:7051
- 17051:17051
networks:
- test
peer0.org2.example.com:
container_name: peer0.org2.example.com
image: hyperledger/fabric-peer:$IMAGE_TAG
image: hyperledger/fabric-peer:latest
environment:
#Generic peer variables
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
# the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_test
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric_test
- FABRIC_LOGGING_SPEC=INFO
#- FABRIC_LOGGING_SPEC=DEBUG
- CORE_PEER_TLS_ENABLED=true
@ -112,6 +111,7 @@ services:
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:9051
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:9051
- CORE_PEER_LOCALMSPID=Org2MSP
- CORE_OPERATIONS_LISTENADDRESS=0.0.0.0:19051
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- ../organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
@ -121,12 +121,13 @@ services:
command: peer node start
ports:
- 9051:9051
- 19051:19051
networks:
- test
cli:
container_name: cli
image: hyperledger/fabric-tools:$IMAGE_TAG
image: hyperledger/fabric-tools:latest
tty: true
stdin_open: true
environment:

View file

@ -61,8 +61,8 @@ function checkPrereqs() {
fi
# use the fabric tools container to see if the samples and binaries match your
# docker images
LOCAL_VERSION=$(peer version | sed -ne 's/ Version: //p')
DOCKER_IMAGE_VERSION=$(docker run --rm hyperledger/fabric-tools:$IMAGETAG peer version | sed -ne 's/ Version: //p' | head -1)
LOCAL_VERSION=$(peer version | sed -ne 's/^ Version: //p')
DOCKER_IMAGE_VERSION=$(docker run --rm hyperledger/fabric-tools:$IMAGETAG peer version | sed -ne 's/^ Version: //p')
infoln "LOCAL_VERSION=$LOCAL_VERSION"
infoln "DOCKER_IMAGE_VERSION=$DOCKER_IMAGE_VERSION"