Skip to content

Commit

Permalink
asset transfer app template
Browse files Browse the repository at this point in the history
  • Loading branch information
MorenaBarboni committed Jan 18, 2024
1 parent 7a5c47a commit 5f925de
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 39 deletions.
2 changes: 1 addition & 1 deletion application/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "quotation app",
"main": "index.js",
"scripts": {
"start": "node server.js",
"start": "node server.js"
},
"author": "Alessandro Marcelletti",
"license": "ISC",
Expand Down
53 changes: 53 additions & 0 deletions assetTransferApplication/commands.js
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;
196 changes: 196 additions & 0 deletions assetTransferApplication/index.js
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 }
3 changes: 2 additions & 1 deletion assetTransferApplication/package.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"express": "^4.17.1",
"fabric-ca-client": "^2.2.0",
"fabric-network": "^2.2.0",
"js-yaml": "^3.14.0"
"js-yaml": "^3.14.0",
"yargs": "17.7.2"
}
}
59 changes: 29 additions & 30 deletions assetTransferApplication/public/home.html
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,47 @@
<form action="" class="m-auto" style="max-width:600px">
<h3 class="my-4">Asset Transfer App</h3>
<hr class="my-4" />
<div class="form-group mb-3 row">
<label for="identity" class="col-md-5 col-form-label">Identity</label>
<div class="col-md-7">
<input type="text" class="form-control form-control-lg" id="identity" value="Agency" required>
</div>
</div>
<div class="form-group mb-3 row"><label for="organization"
class="col-md-5 col-form-label">Organization</label>
<h5 class="my-4">Identity</h5>

<div class="form-group mb-3 row"><label for="organization" class="col-md-5 col-form-label">User1 of
Organization</label>
<div class="col-md-7">
<input type="text" class="form-control form-control-lg" id="organization"
value="agency.quotation.com" required>
</div>
</div>
<div class="form-group mb-3 row"><label for="msp" class="col-md-5 col-form-label">MSP ID</label>

<h5 class="my-4">Network</h5>

<div class="form-group mb-3 row"><label for="channel" class="col-md-5 col-form-label">Channel</label>
<div class="col-md-7">
<input type="text" class="form-control form-control-lg" id="msp" value="AgencyMSP" required>
<input type="text" class="form-control form-control-lg" id="channel" value="q1channel" required>
</div>
</div>
<div class="form-group mb-3 row"><label for="channel" class="col-md-5 col-form-label">Channel</label>


<div class="form-group mb-3 row">
<label for="identity" class="col-md-5 col-form-label">Chaincode</label>
<div class="col-md-7">
<input type="text" class="form-control form-control-lg" id="channel" value="q1channel"
required>
<input type="text" class="form-control form-control-lg" id="chaincode" value="assetTransfer" required>
</div>
</div>


<h5 class="my-4">Transaction</h5>

<hr class="bg-transparent border-0 py-1" />
<div class="form-group mb-3 row">
<label for="txName" class="col-md-5 col-form-label">Transaction Name</label>
<div class="col-md-7">
<input type="text" class="form-control form-control-lg" id="txName" value="createAsset" required>
<input type="text" class="form-control form-control-lg" id="txName" value="createAsset"
required>
</div>
</div>
<div class="form-group mb-3 row"><label for="txParams" class="col-md-5 col-form-label">Transaction
Parameters</label>
<div class="col-md-7">
<input type="text" class="form-control form-control-lg" id="txParams"
value="shoes,white,39,morena,70">
<input type="text" class="form-control form-control-lg" id="txParams" value="shoes,white,39,morena,70">
</div>
</div>
<hr class="my-4" />
Expand All @@ -61,30 +66,24 @@ <h3 class="my-4">Asset Transfer App</h3>

<script>
document.getElementById("sendTxBtn").addEventListener("click", (e) => {
var identity = document.getElementById("identity").value
if (!identity) {
alert("'Identity' field missing!")
return
}

var organization = document.getElementById("organization").value
if (!organization) {
alert("'Organization' field missing!")
return
}

var msp = document.getElementById("msp").value
if (!msp) {
alert("'MSP ID' field missing!")
return
}

var channel = document.getElementById("channel").value
if (!channel) {
alert("'Channel' field missing!")
return
}

var chaincode = document.getElementById("chaincode").value
if (!chaincode) {
alert("'chaincode' field missing!")
return
}

var txName = document.getElementById("txName").value
if (!txName) {
alert("'Transaction Name' field missing!")
Expand All @@ -106,12 +105,12 @@ <h3 class="my-4">Asset Transfer App</h3>
var xhr = new XMLHttpRequest()
// TODO change the url to your own domain
xhr.open("POST", "https://jubilant-space-happiness-rv5q5794v6wcxqp7-3000.app.github.dev/submitTX", true)

xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(JSON.stringify({
identity,
organization,
msp,
channel,
chaincode,
txName,
txParams: paramsArr
}))
Expand Down
Loading

0 comments on commit 5f925de

Please sign in to comment.