The smart contract code is sensitive and is therefore wrapped and guarded by the middleware.
The middleware also exposes some sensitive operations involving channel configuration and chaincode installation.
Therefore, the safe and proper way to expose application capabilities to the end user is through a web application.
The code in this folder is for starting a NodeJS web server and exposing a REST API to the user.
Note: In a production scenario, you should run different applications (servers) for different organizations and user roles (trading parties, banks, carrier, regulator)
- Install
nodeandnpmon your system if you don't have them.- This code was developed and run with
nodeversion9.8.0andnpmversion5.7.1respectively. - Note: Older and newer versions may also work, but they are not guaranteed to do so.
- This code was developed and run with
- Run
npm installto install the dependencies.
In a terminal window:
- Run
node app.js - The web server will listen for incoming HTTP requests on port 4000.
- Note: In a production scenario, you should run the server only in HTTPS mode.
-
/login: Login an existing user or register a new one
- Method: POST
- URL Parameters: None
- Header:
content-type: application/x-www-form-urlencoded(FORM DATA) - Body:
username=<string>&orgName=<string>[&password=<string>]orgNamecan be one of the following: {exporterorg,importerorg,carrierorg,regulatororg} in the initial version of the application- After you add a new organization to the channel, you can also use
exportingentityorg - The
passwordMUST be specified if and only if theusernameisadmin. - In our back-end, the
adminpassword is hardcoded toadminpw, so this feature is only for demonstration (and not production) purposes. - The purpose of exercising this API is to obtain a JWT token for subsequent session authentication for other operations.
- Certain API functions are restricted to
adminusers, so you will need to login as anadminand use the returned JWT token.
- Access Control: None
- Return Value: 200 status code upon success or miscellaneous error
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string>, "secret": <intermediate registration password>, "token": <JSON Web Token for Session Authentication> }- The
secretandtokenwill be present only ifsuccessistrue. - The
secretis just for your information. It's for temporary use during registration to get the enrollment certificate. It will also be present in the above JSON ony if this is a registration and not a login of an existing user.
-
/channel/create: Create a channel named
tradechannelon the peer network of 4 organizations- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token> - Body: None
- Access Control: Only
adminuser - Return Value: 200 status code upon success or 403 upon authentication failure
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string> }
-
/channel/join: Join the peers of the 4 organizations to
tradechannel- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token> - Body: None
- Access Control: Only
adminuser - Return Value: 200 status code upon success or 403 upon authentication failure
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string> }
-
/channel/addorg: Add
exportingentityorgorganization and its peer totradechannel- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token> - Body: None
- Access Control: Only
adminuser - Return Value: 200 status code upon success or 403 upon authentication failure
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string> }
-
/chaincode/install: Install the chaincode on the peers joined to
tradechannel- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token> - Header:
content-type: application/json(JSON) - Body:
{ "ccpath": <relative path of chaincode folder>, "ccversion": <string> } - Access Control: Only
adminuser - Return Value: 200 status code upon success or 403 upon authentication failure
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string> }
-
/chaincode/instantiate: Instantiate the chaincode on
tradechannel- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token> - Header:
content-type: application/json(JSON) - Body:
{ "ccpath": <relative path of chaincode folder>, "ccversion": <string>, "args": <array-of-strings> }argsrefers to the arguments list expected by the chaincode'sInitfunction- A chaincode function name is not needed here as the
initvale us hardcoded in the middleware, and is anyway irrelevant to the chaincode
- Access Control: Only
adminuser - Return Value: 200 status code upon success or 403 upon authentication failure
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string> }
-
/chaincode/upgrade: Install and upgrade the chaincode to a new version on
tradechannel- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token> - Header:
content-type: application/json(JSON) - Body:
{ "ccpath": <relative path of chaincode folder>, "ccversion": <string>, "args": <array-of-strings> }argsrefers to the arguments list expected by the chaincode'sInitfunction- A chaincode function name is not needed here as the
initvale us hardcoded in the middleware, and is anyway irrelevant to the chaincode
- Access Control: Only
adminuser - Return Value: 200 status code upon success or 403 upon authentication failure
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string> }
-
/chaincode/: Invoke
<function>on the chaincode- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token> - Header:
content-type: application/json(JSON) - Body:
{ "ccversion": <string>, "args": <array-of-strings> }argsrefers to the arguments list expected by the chaincode's<function>function
- Access Control: Only
adminuser - Return Value: 200 status code upon success or miscellaneous error
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string> }
-
/chaincode/: Query
<function>on the chaincode- Method: GET
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token> - Header:
content-type: application/json(JSON) - Body:
{ "ccversion": <string>, "args": <array-of-strings> }argsrefers to the arguments list expected by the chaincode's<function>function
- Access Control: Only
adminuser - Return Value: 200 status code upon success or miscellaneous error
- If 200: return value is a JSON:
{ "success": <boolean>, "message": <string> }- If the query is successful,
messagewill contain the result
Pre-requisites:
- Make sure you have
curlinstalled on your system. - Make sure you have the initial 4-org network up and running.
In a terminal window:
-
Register or log in an
adminuser toimporterorg(IMPORTER organization)curl -s -X POST http://localhost:4000/login -H "content-type: application/x-www-form-urlencoded" -d 'username=admin&orgName=importerorg&password=adminpw'- If the user is already registered, you should see something like the following:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzQzMTgsInVzZXJuYW1lIjoiYWRtaW4iLCJvcmdOYW1lIjoiaW1wb3J0ZXJvcmciLCJpYXQiOjE1MjcyMzAxNzh9.nHTxkdFb1NlGaAunECtak25yn9hXxiuX686KoF9A8AM","success":true,"message":"Login successful"}- Otherwise, you should see something like the following:
`{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzQzMTgsInVzZXJuYW1lIjoiYWRtaW4iLCJvcmdOYW1lIjoiaW1wb3J0ZXJvcmciLCJpYXQiOjE1MjcyMzAxNzh9.nHTxkdFb1NlGaAunECtak25yn9hXxiuX686KoF9A8AM","success":true,"secret":"JXjhiYyMomkS","message":"Registration successful"}`- Let's assume the latter was the result. Save the
tokenvalue for use in the commands below.
-
Create the trade channel
curl -s -X POST http://localhost:4000/channel/create -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzQzMTgsInVzZXJuYW1lIjoiYWRtaW4iLCJvcmdOYW1lIjoiaW1wb3J0ZXJvcmciLCJpYXQiOjE1MjcyMzAxNzh9.nHTxkdFb1NlGaAunECtak25yn9hXxiuX686KoF9A8AM"- If this is successful, you should see something like:
{"success":true,"message":"Channel created"} -
Join peers of the first 4 organizations to the trade channel
curl -s -X POST http://localhost:4000/channel/join -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzQzMTgsInVzZXJuYW1lIjoiYWRtaW4iLCJvcmdOYW1lIjoiaW1wb3J0ZXJvcmciLCJpYXQiOjE1MjcyMzAxNzh9.nHTxkdFb1NlGaAunECtak25yn9hXxiuX686KoF9A8AM"- If this is successful, you should see something like:
{"success":true,"message":"Channel joined"} -
Install the initial version of the trade chaincode on the peers
curl -s -X POST http://localhost:4000/chaincode/install -H "content-type: application/json" -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzQzMTgsInVzZXJuYW1lIjoiYWRtaW4iLCJvcmdOYW1lIjoiaW1wb3J0ZXJvcmciLCJpYXQiOjE1MjcyMzAxNzh9.nHTxkdFb1NlGaAunECtak25yn9hXxiuX686KoF9A8AM" -d '{ "ccpath": "github.com/trade_workflow", "ccversion": "v0" }'- If this is successful, you should see something like:
{"success":true,"message":"Chaincode installed"} -
Instantiate the initial version of the trade chaincode on the trade channel
curl -s -X POST http://localhost:4000/chaincode/instantiate -H "content-type: application/json" -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzQzMTgsInVzZXJuYW1lIjoiYWRtaW4iLCJvcmdOYW1lIjoiaW1wb3J0ZXJvcmciLCJpYXQiOjE1MjcyMzAxNzh9.nHTxkdFb1NlGaAunECtak25yn9hXxiuX686KoF9A8AM" -d '{ "ccpath": "github.com/trade_workflow", "ccversion": "v0", "args": ["LumberInc", "LumberBank", "100000", "WoodenToys", "ToyBank", "200000", "UniversalFrieght", "ForestryDepartment"] }'- If this is successful, you should see something like:
{"success":true,"message":"Chaincode instantiated"} -
Log in an existing user
Jimtoimporterorg(IMPORTER organization)curl -s -X POST http://localhost:4000/login -H "content-type: application/x-www-form-urlencoded" -d 'username=Jim&orgName=importerorg'- If this is successful, you should see something like:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzUzODQsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6ImltcG9ydGVyb3JnIiwiaWF0IjoxNTI3MjMxMjQ0fQ.CfV7BCr-bKzP-hqpdvSjHnXqnms6f36lXhyUsTK8yTQ","success":true,"message":"Login successful"}- Just for testing, you can register a new user
Bobtoimporterorg:
curl -s -X POST http://localhost:4000/login -H "content-type: application/x-www-form-urlencoded" -d 'username=Bob&orgName=importerorg'- If this is successful, you should see something like:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzU0NTEsInVzZXJuYW1lIjoiQm9iIiwib3JnTmFtZSI6ImltcG9ydGVyb3JnIiwiaWF0IjoxNTI3MjMxMzExfQ.7cEzCSdldiEuYjueLIfHb9PhJHm75MP-qpdQ77e_9Ts","success":true,"secret":"WaUGtKDwGfgC","message":"Registration successful"}- We will use user
Jim's handle to run chaincode transactions below
-
Invoke a trade request by an importer
curl -s -X POST http://localhost:4000/chaincode/requestTrade -H "content-type: application/json" -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzUzODQsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6ImltcG9ydGVyb3JnIiwiaWF0IjoxNTI3MjMxMjQ0fQ.CfV7BCr-bKzP-hqpdvSjHnXqnms6f36lXhyUsTK8yTQ" -d '{ "ccversion": "v0", "args": ["2ks89j9", "50000","Wood for Toys"] }'- If this is successful, you should see something like:
{"success":true,"message":"Chaincode invoked"} -
Query the status of the trade request by an importer
curl -s -X GET http://localhost:4000/chaincode/getTradeStatus -H "content-type: application/json" -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzUzODQsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6ImltcG9ydGVyb3JnIiwiaWF0IjoxNTI3MjMxMjQ0fQ.CfV7BCr-bKzP-hqpdvSjHnXqnms6f36lXhyUsTK8yTQ" -d '{ "ccversion": "v0", "args": ["2ks89j9"] }'- If this is successful, you should see something like:
{"success":true,"message":"{\"Status\":\"REQUESTED\"}"} -
Add a new organization (exporting entity) and its peer to the channel
-
Make sure you have the network peer and MSP for the new organization up and running.
-
Update the channel configuration and join a new peer to the network
- Perform this operation as the
adminuser ofimporterorg, whose JWT token we already possess.
curl -s -X POST http://localhost:4000/channel/addorg -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzQzMTgsInVzZXJuYW1lIjoiYWRtaW4iLCJvcmdOYW1lIjoiaW1wb3J0ZXJvcmciLCJpYXQiOjE1MjcyMzAxNzh9.nHTxkdFb1NlGaAunECtak25yn9hXxiuX686KoF9A8AM"- If this is successful, you should see something like:
{"success":true,"message":"New Organization and Peer Added to Channel"} - Perform this operation as the
-
Upgrade chaincode to accommodate the new organization
- Perform this operation as the
adminuser ofimporterorg, whose JWT token we already possess.
curl -s -X POST http://localhost:4000/chaincode/upgrade -H "content-type: application/json" -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzQzMTgsInVzZXJuYW1lIjoiYWRtaW4iLCJvcmdOYW1lIjoiaW1wb3J0ZXJvcmciLCJpYXQiOjE1MjcyMzAxNzh9.nHTxkdFb1NlGaAunECtak25yn9hXxiuX686KoF9A8AM" -d '{ "ccpath": "github.com/trade_workflow_v1", "ccversion": "v1", "args": [] }'- If this is successful, you should see something like:
{"success":true,"message":"New version of Chaincode installed and upgraded"} - Perform this operation as the
-
Invoke a trade request acceptance by an exporting entity
- Register user
Tominexportingentityorg(EXPORTING ENTITY organization)
curl -s -X POST http://localhost:4000/login -H "content-type: application/x-www-form-urlencoded" -d 'username=Tom&orgName=exportingentityorg'- If this is successful, you should see something like:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyNTE3MzMsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6ImV4cG9ydGluZ2VudGl0eW9yZyIsImlhdCI6MTUyNzI0NzU5M30.HxuL744Mw77MxIlBIwfmgia4_y1YiqDNtIMJQhJFY84","success":true,"secret":"BQNqVfPYVfzu","message":"Registration successful"}- Run the invocation
curl -s -X POST http://localhost:4000/chaincode/acceptTrade -H "content-type: application/json" -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyNTE3MzMsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6ImV4cG9ydGluZ2VudGl0eW9yZyIsImlhdCI6MTUyNzI0NzU5M30.HxuL744Mw77MxIlBIwfmgia4_y1YiqDNtIMJQhJFY84" -d '{ "ccversion": "v1", "args": ["2ks89j9"] }'- If this is successful, you should see something like:
{"success":true,"message":"Chaincode invoked"} - Register user
-
Query the status of the trade request by an importer
- We will query as user
Jiminimporterorg(whose JWT token we already possess)
curl -s -X GET http://localhost:4000/chaincode/getTradeStatus -H "content-type: application/json" -H "authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjcyMzUzODQsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6ImltcG9ydGVyb3JnIiwiaWF0IjoxNTI3MjMxMjQ0fQ.CfV7BCr-bKzP-hqpdvSjHnXqnms6f36lXhyUsTK8yTQ" -d '{ "ccversion": "v0", "args": ["2ks89j9"] }'- If this is successful, you should see something like:
{"success":true,"message":"{\"Status\":\"ACCEPTED\"}"} - We will query as user
-
As a shortcut, you can also use (and adapt) shell scripts in the client_scripts folder to run the above commands
- Pre-requisite: make sure you have
jqinstalled on your system for JSON parsing. (On an Ubuntu/Debian system, runsudo apt-get install jq.) - The scripts to run are as follows (make sure you run the channel and chaincode operation scripts from the same folder you ran the login script in):
- Admin registration/login: adminLogin.sh
- User Jim registration/login: userLogin.sh
- Create channel: createChannel.sh
- Join channel: joinChannel.sh
- Install chaincode: installChaincode.sh
- Instantiate chaincode: instantiateChaincode.sh
- Upgrade channel: upgradeChannel.sh
- Upgrade chaincode: upgradeChaincode.sh
- Invoke
requestTradeoperation: invoke_requestTrade.sh - Query
getTradeStatusoperation: query_getTradeStatus.sh