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
node
andnpm
on your system if you don't have them.- This code was developed and run with
node
version9.8.0
andnpm
version5.7.1
respectively. - 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 install
to 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>]
orgName
can 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
password
MUST be specified if and only if theusername
isadmin
. - In our back-end, the
admin
password 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
admin
users, so you will need to login as anadmin
and 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
secret
andtoken
will be present only ifsuccess
istrue
. - The
secret
is 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
tradechannel
on the peer network of 4 organizations- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token>
- Body: None
- Access Control: Only
admin
user - 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
admin
user - 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
exportingentityorg
organization and its peer totradechannel
- Method: POST
- URL Parameters: None
- Header:
authorization: Bearer <JSON Web Token>
- Body: None
- Access Control: Only
admin
user - 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
admin
user - 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> }
args
refers to the arguments list expected by the chaincode'sInit
function- A chaincode function name is not needed here as the
init
vale us hardcoded in the middleware, and is anyway irrelevant to the chaincode
- Access Control: Only
admin
user - 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> }
args
refers to the arguments list expected by the chaincode'sInit
function- A chaincode function name is not needed here as the
init
vale us hardcoded in the middleware, and is anyway irrelevant to the chaincode
- Access Control: Only
admin
user - 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> }
args
refers to the arguments list expected by the chaincode's<function>
function
- Access Control: Only
admin
user - 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> }
args
refers to the arguments list expected by the chaincode's<function>
function
- Access Control: Only
admin
user - 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,
message
will contain the result
Pre-requisites:
- Make sure you have
curl
installed on your system. - Make sure you have the initial 4-org network up and running.
In a terminal window:
-
Register or log in an
admin
user 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
token
value 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
Jim
toimporterorg
(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
Bob
toimporterorg
:
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
admin
user 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
admin
user 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
Tom
inexportingentityorg
(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
Jim
inimporterorg
(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
jq
installed 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
requestTrade
operation: invoke_requestTrade.sh - Query
getTradeStatus
operation: query_getTradeStatus.sh