Skip to content

Commit

Permalink
Quotation application template
Browse files Browse the repository at this point in the history
  • Loading branch information
MorenaBarboni committed Jan 15, 2024
1 parent 69c85da commit 7462637
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 61 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,5 @@ package-lock.json
# Chaincode solutions
lib/

# Application solutions
assetTransferApplication/index.js
application/index.js

# override the ignore of all config/ folders
!full-stack-asset-transfer-guide/infrastructure/sample-network/config
179 changes: 179 additions & 0 deletions application/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* 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()
}

}

module.exports = { submitT }
34 changes: 17 additions & 17 deletions application/package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"name": "quotation_app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node server.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Alessandro Marcelletti",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"fabric-ca-client": "^2.2.0",
"fabric-network": "^2.2.0",
"js-yaml": "^3.14.0"
}
}
"name": "quotation_app",
"version": "1.0.0",
"description": "quotation app",
"main": "index.js",
"scripts": {
"start": "node server.js",
},
"author": "Alessandro Marcelletti",
"license": "ISC",
"dependencies": {
"@grpc/grpc-js": "^1.9.13",
"@hyperledger/fabric-gateway": "^1.4.0",
"crypto": "^1.0.1",
"express": "^4.17.1",
"js-yaml": "^3.14.0"
}
}
61 changes: 30 additions & 31 deletions application/public/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,49 @@
<body>
<div class="container">
<form action="" class="m-auto" style="max-width:600px">
<h3 class="my-4">Asset Transfer App</h3>
<h3 class="my-4">Quotation 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="quotation" 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="requestQuotation"
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="quotation1,laptop,500">
</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
14 changes: 5 additions & 9 deletions application/server.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
const express = require('express')
const app = express()
const port = 3000
const FabNetwork = require('./index.js')
const FabNetwork = require('./index')

app.use(express.static('public'))
app.use(express.urlencoded({extended: true}))
app.use(express.urlencoded({ extended: true }))
app.use(express.json())

app.post('/submitTX', async (req, res) => {
const data = req.body
const identity = data.identity
const organization = data.organization
const msp = data.msp
const channel = data.channel
const chaincode = data.chaincode
const txName = data.txName
const txParams = data.txParams

await FabNetwork.createIdentity(identity, organization, msp)
await FabNetwork.createConnection(identity, organization)
const resultTx = await FabNetwork.submitT(channel, txName, txParams)

const resultTx = await FabNetwork.submitT(organization, channel, chaincode, txName, txParams)
res.send(resultTx)
})

app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`)
console.log(`Server listening at ${port}`)
})

0 comments on commit 7462637

Please sign in to comment.