-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7a5c47a
commit 5f925de
Showing
6 changed files
with
284 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#!/usr/bin/env node | ||
const yargs = require('yargs') | ||
const index = require('./index.js') | ||
|
||
yargs | ||
.usage('$0 <cmd> [args]') | ||
.command('submit <organization> <channel> <chaincode> <transactionName> [transactionParams..]', 'Submit a transaction', (yargs) => { | ||
yargs | ||
.positional('organization', { | ||
type: 'string', | ||
describe: 'name of the organization', | ||
example: 'agency.quotation.com' | ||
}) | ||
.positional('channel', { | ||
type: 'string', | ||
describe: 'name of the channel', | ||
example: 'q1channel' | ||
}) | ||
.positional('chaincode', { | ||
type: 'string', | ||
describe: 'name of the chaincode', | ||
example: 'assetTransfer' | ||
}) | ||
.positional('transactionName', { | ||
type: 'string', | ||
describe: 'name of the transaction', | ||
example: 'createAsset' | ||
}) | ||
.positional('transactionParams', { | ||
type: 'string', | ||
describe: 'list of transaction parameters', | ||
example: 'shoes white 39 morena 70' | ||
}) | ||
}, (argv) => { | ||
index.submit( | ||
argv.organization, | ||
argv.channel, | ||
argv.chaincode, | ||
argv.transactionName, | ||
argv.transactionParams); | ||
}) | ||
.help() | ||
.alias('h', 'help') | ||
.example('$0 submit agency.quotation.com q1channel assetTransfer createAsset shoes white 39 morena 70') | ||
.demandCommand(1, 'You must specify a command.') | ||
.strict() | ||
.fail((msg, err, yargs) => { | ||
if (msg) console.error(msg); | ||
if (err) console.error(err); | ||
yargs.showHelp(); | ||
process.exit(1); | ||
}) | ||
.argv; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
/* | ||
* Copyright IBM Corp. All Rights Reserved. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
const grpc = require('@grpc/grpc-js') | ||
const { connect, signers } = require('@hyperledger/fabric-gateway') | ||
const crypto = require('crypto') | ||
const fs = require('fs') | ||
const path = require('path') | ||
const { TextDecoder } = require('util') | ||
|
||
// Path to crypto materials | ||
const cryptoPath = '/workspaces/Fabric2.5_school_material/test-network/organizations/peerOrganizations/'; | ||
|
||
// Gateway peer endpoint | ||
const peerEndpoints = { | ||
'suppliera.quotation.com': 'localhost:7051', | ||
'supplierb.quotation.com': 'localhost:9051', | ||
'agency.quotation.com': 'localhost:11051' | ||
} | ||
|
||
// mspIDs | ||
const orgMspIds = { | ||
'suppliera.quotation.com': 'SupplierAMSP', | ||
'supplierb.quotation.com': 'SupplierBMSP', | ||
'agency.quotation.com': 'AgencyMSP' | ||
} | ||
|
||
const utf8Decoder = new TextDecoder(); | ||
|
||
/** | ||
* Establish client-gateway gRPC connection | ||
* @param {String} organization | organization domain | ||
* @returns gRPC client | ||
*/ | ||
async function newGrpcConnection(organization) { | ||
// Gateway peer SSL host name override. | ||
const peerHostAlias = `peer0.${organization}` | ||
// Path to peer tls certificate. | ||
const tlsCertPath = path.join(cryptoPath, `${organization}/peers/${peerHostAlias}/tls/ca.crt`) | ||
|
||
const tlsRootCert = fs.readFileSync(tlsCertPath); | ||
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); | ||
|
||
//Complete the gRCP Client connection here | ||
return new grpc.Client(... | ||
{ 'grpc.ssl_target_name_override': peerHostAlias } | ||
); | ||
} | ||
|
||
/** | ||
* Create a new user identity | ||
* @param {String} organization | organization domain | ||
* @returns the user credentials | ||
*/ | ||
function newIdentity(organization) { | ||
// Path to user certificate | ||
const certPath = path.join(cryptoPath, `${organization}/users/User1@${organization}/msp/signcerts/User1@${organization}-cert.pem`) | ||
const mspId = orgMspIds[organization]; | ||
//Retrieve and return credentials here ... | ||
// const credentials ... | ||
// return {...} | ||
} | ||
|
||
/** | ||
* Create a signing implementation | ||
* @param {String} organization | organization domain | ||
* @returns a new signing implementation for the user | ||
*/ | ||
function newSigner(organization) { | ||
// Path to user private key directory. | ||
const keyDirectoryPath = path.join(cryptoPath, `${organization}/users/User1@${organization}/msp/keystore`) | ||
|
||
const files = fs.readdirSync(keyDirectoryPath) | ||
const keyPath = path.resolve(keyDirectoryPath, files[0]) | ||
const privateKeyPem = fs.readFileSync(keyPath) | ||
const privateKey = crypto.createPrivateKey(privateKeyPem) | ||
//Create and return the signing implementation here | ||
// ... | ||
} | ||
|
||
/** | ||
* Submit a transaction synchronously, blocking until it has been committed to the ledger. | ||
* @param {String} organization | organization domain | ||
* @param {String} channel | channel name | ||
* @param {String} chaincode | chaincode name | ||
* @param {String} transactionName | transaction method | ||
* @param {Array} transactionParams | transaction parameters | ||
* @returns a new signing implementation for the user | ||
*/ | ||
async function submitT(organization, channel, chaincode, transactionName, transactionParams) { | ||
|
||
organization = organization.toLowerCase() | ||
|
||
console.log("\nCreating gRPC connection...") | ||
//Establish gRPC connection here | ||
// const client = ... | ||
|
||
console.log(`Retrieving identity for User1 of ${organization} ...`) | ||
//Retrieve User1's identity here | ||
// const id = ... | ||
|
||
//Retrieve signing implementation here | ||
// const signer = ... | ||
|
||
//Complete the gateway connection here ... | ||
const gateway = connect({ | ||
//..., | ||
//..., | ||
//..., | ||
|
||
// Default timeouts for different gRPC calls | ||
evaluateOptions: () => { | ||
return { deadline: Date.now() + 5000 }; // 5 seconds | ||
}, | ||
endorseOptions: () => { | ||
return { deadline: Date.now() + 15000 }; // 15 seconds | ||
}, | ||
submitOptions: () => { | ||
return { deadline: Date.now() + 5000 }; // 5 seconds | ||
}, | ||
commitStatusOptions: () => { | ||
return { deadline: Date.now() + 60000 }; // 1 minute | ||
}, | ||
}) | ||
|
||
try { | ||
console.log(`Connecting to ${channel} ...`) | ||
//Retrieve the channel here | ||
//const network = ... | ||
|
||
console.log(`Getting the ${chaincode} contract ...`) | ||
//Retrieve the contract here | ||
//const contract = ... | ||
|
||
console.log(`Submitting ${transactionName} transaction ...\n`) | ||
|
||
//Submit transaction here | ||
let resp = null | ||
if (!transactionParams || transactionParams === '') { | ||
//resp = ... | ||
} else { | ||
//resp = ... | ||
} | ||
const resultJson = utf8Decoder.decode(resp); | ||
|
||
if (resultJson && resultJson !== null) { | ||
const result = JSON.parse(resultJson); | ||
console.log('*** Result:', result); | ||
} | ||
console.log('*** Transaction committed successfully'); | ||
|
||
|
||
//Retrieve chaincode events here ... | ||
//const events = ... | ||
try { | ||
for await (const event of events) { | ||
const asset = new TextDecoder().decode(event.payload); | ||
|
||
console.log(`*** Contract Event Received: ${event.eventName}`) | ||
console.log(`-- asset: ${asset}`) | ||
console.log(`-- chaincodeName: ${event.chaincodeName}`) | ||
console.log(`-- transactionId: ${event.transactionId}`) | ||
console.log(`-- blockNumber: ${event.blockNumber}\n`) | ||
} | ||
} finally { | ||
events.close(); | ||
} | ||
} catch (err) { | ||
console.error(err) | ||
} finally { | ||
gateway.close() | ||
client.close() | ||
} | ||
|
||
} | ||
|
||
function submit(organization, channel, chaincode, transactionName, transactionParams) { | ||
if (!organization) { | ||
console.log("organization argument missing!") | ||
} | ||
else if (!channel) { | ||
console.log("channel argument missing!") | ||
} | ||
else if (!chaincode) { | ||
console.log("chaincode argument missing!") | ||
} | ||
else if (!transactionName) { | ||
console.log("transactionName argument missing!") | ||
} else { | ||
submitT(organization, channel, chaincode, transactionName, transactionParams) | ||
} | ||
} | ||
|
||
module.exports = { submitT, submit } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.