Tutorial A5: Invoking A Smart Contract From An External Application
Tutorial A5: Invoking A Smart Contract From An External Application
Tutorial A5: Invoking A Smart Contract From An External Application
In the last tutorial we learned how an identity, wallet and gateway are used to access a Hyperledger Fabric
network. We also used the IBM Blockchain Platform VS Code extension to connect to a sample network and
call a smart contract to query the ledger and submit new transactions. In this tutorial we will:
In order to successfully complete this tutorial, you must have first completed tutorial A4: Invoking a smart
contract from VS Code in the active workspace.
a connection profile
a wallet containing one or more identities
Our sample application will use the same identity and connection profile used by VS Code to interact with the
sample network.
A5.2: With the gateway connected, move the mouse over the Fabric Gateways view, click the
ellipsis that appears and select "Export Connection Profile".
A5.3: Create a new folder called 'demo-application' as a peer of the demo-contract project we
created earlier. Give the connection profile a convenient name ('connection.json') and export it into the new
folder.
We will now export our wallet.
A5.4: In the Fabric Wallets view, expand '1 Org Local Fabric', right click 'Org1' and select 'Export
Wallet'.
A5.5: Navigate into the 'demo-application' folder, change the name to 'Org1Wallet' and click Export
to save the wallet.
A5.6: Expand the next section of the tutorial to continue.
A5.7: From the VS Code menu bar click "File" -> "Add Folder to Workspace..."
The demo-application folder should contain a subfolder called 'Org1Wallet' (the wallet) and a connection
profile called 'connection.json'.
In order to build a working Typescript application we will now create three files in addition to the wallet and
connection profile:
create.ts: The TypeScript application containing the logic required to connect to the Hyperledger Fabric
sample network and submit a new transaction.
tsconfig.json: TypeScript compiler options, including source and destination locations
package.json: Application metadata, including the Hyperledger Fabric client SDK dependencies, and
commands to build and test the application.
A5.13: In the editor view for the new create.ts file, copy and paste the following text. (The contents
are also available here).
} catch (error) {
console.error('Failed to submit transaction:',error);
process.exit(1);
}
}
void main();
Your file should be 38 lines long. We will look through what the application is doing later on in this tutorial.
Saving the file will change the tab for the editor to show a cross; a solid circle here means that you have
unsaved changes:
When you save, you will see various errors reported by VS Code. This is because we have not yet configured
the set of external dependencies.
We will next create the tsconfig.json file.
A5.17: In the editor view for the new tsconfig.json file, copy and paste the following text. (The
contents are also available here).
{
"compilerOptions": {
"target": "ES2017",
"module": "commonjs",
"allowJs": true,
"sourceMap": true,
"outDir": "./dist/",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"./src/**/*"
],
"exclude": [
"node_modules"
]
}
Importantly, the tsconfig.json file specifies the source and output folders ('src' and 'dist' respectively), and
enables compiler options for strict syntax checking of our Typescript.
A5.21: In the editor view for the new package.json file, copy and paste the following text. (The
contents are also available here).
{
"name": "demo-application",
"version": "1.0.0",
"description": "Demo Application implemented in TypeScript",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"scripts": {
"lint": "tslint -c tslint.json 'src/**/*.ts'",
"pretest": "npm run lint",
"test": "nyc mocha -r ts-node/register src/**/*.spec.ts",
"resolve": "npx npm-force-resolutions",
"build": "tsc",
"build:watch": "tsc -w",
"prepublishOnly": "npm run build",
"start": "node ./dist/create.js",
"create": "node ./dist/create.js",
"query": "node ./dist/query.js",
"listener": "node ./dist/listener.js"
},
"engineStrict": true,
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-network": "~2.1.0"
},
"devDependencies": {
"@types/chai": "^4.2.0",
"@types/mocha": "^5.2.7",
"@types/node": "^10.12.10",
"@types/sinon": "^7.0.13",
"@types/sinon-chai": "^3.2.3",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"jsrsasign": "^8.0.13",
"minimist": "^1.2.5",
"mocha": "^6.2.0",
"nyc": "^14.1.1",
"sinon": "^7.4.1",
"sinon-chai": "^3.3.0",
"ts-node": "^8.3.0",
"tslint": "^5.19.0",
"typescript": "^3.6.2"
},
"nyc": {
"extension": [
".ts",
".tsx"
],
"exclude": [
"coverage/**",
"dist/**"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
},
"resolutions": {
"minimist": "^1.2.5",
"mkdirp": "^1.0.4",
"jsrsasign": "^8.0.13"
}
}
Your file should be 73 lines long. It describes the module dependencies of our application, including any
required versions. It also configures a few scripts that we will run during the course of these tutorials.
At this stage, your application structure should contain a wallet folder ('Org1Wallet'), a source folder ('src')
which contains a single file ('create.ts'), a connection profile ('connection.json'), package.json and
tsconfig.json. If this is not the case, check the instructions and move and edit files as necessary.
Even though we've specified our application's dependencies inside package.json, we haven't yet loaded the
required modules into our workspace and so errors remain. The next step is to install these modules so that
the errors disappear and allow our application to be built and run.
A5.25: In the terminal window type npm install and press Enter.
This will download the module dependencies into our project folder and may take a minute or so to complete.
When it has finished, the prompt will return.
The errors that were previously reported will now all vanish, and the demo-application folder will now contain
a new 'node_modules' folder that contains the imported dependencies.
Resolving vulnerabilities
Depending on the versions of your installed components, you might see software vulnerabilities
reported in the terminal after installation and it is good practice to fix these. We recommend running
the `npm run resolve` command in the same terminal window. This runs the `resolve` script described
in our package.json.
A5.26: In the main VS Code menu, click 'Terminal' -> 'Run Build Task...'.
A5.27: In the command palette, find and click 'tsc: watch - tsconfig.json demo-application'.
Take care to select the correct option as there will be similar looking alternatives (build options for our smart
contract project, for example). You might need to scroll the list to find the correct task.
After a few seconds, the application will have been built and the compiler will enter 'watch' mode, which
means that any changes to the source will cause an automatic recompilation. Using watch mode is useful as
it means you do not have to force a rebuild each time you make a change.
You will also see a new 'dist' folder underneath the demo-application project. This contains the built version of
the application, which is what we will run in the next section.
We can run our application wherever we choose - it is just a standard Node.js application. However, VS Code
additionally provides an integrated terminal facility whereby different tasks can be run in different terminals.
We'll use that now to make all our outputs easily accessible within VS Code.
A5.29: In the main VS Code menu, click 'Terminal' -> 'Run Task...'.
A5.30: Find and select the task 'npm: start demo-application'.
Again, take care to select the correct task as there might be alternatives that look very similar. You might need
to scroll the list to find the correct task. You may also need to click Show All Tasks.
VS Code will offer to automatically scan the task output for us, but we will not do that here.
The task will now run. What it will do is run the start script that is defined in demo-application's package.json,
which is the command node ./dist/create.js. You could run the same node command in any
appropriately configured environment and achieve the same output.
(Note that the start script is identical to create; while convention is to name our default script start, having
create also allows us to be more explicit about the application we are running.)
The task will be run inside a VS Code terminal and, after a brief pause, you will see it complete successfully.
A5.32: Press any key in the terminal window to free it up for other tasks.
The Terminal window will switch back to what was there previously.
A5.33: Click on the 'create.ts' tab in the VS Code editor (or load it from the Explorer view).
You can see the sequence of steps in the source file. The key elements are:
1. The wallet location on the local file system is specified using newFileSystemWallet()
2. A gateway is connected to using gateway.connect(). The gateway uses a set of connection options
that control how it interacts with the network channels accessed via the connection profile. A gateway
has a fixed set of options which include the identity, and whether or not it uses service discovery for
example.
3. The gateway provides access to a set of network channels using gateway.getNetwork().
4. The network channel provides access to a set of smart contracts using network.getContract().
5. A new transaction is submitted using contract.submitTransaction().
6. Control is returned to the application only when consensus is complete and the distributed ledger has
been updated.
We will now make a small change to the external application to call a different transaction.
Although submitting a transaction is the most important blockchain application operation, querying the ledger
is the most common.
We're now going to query the ledger to verify that the createMyAsset transaction was added to the ledger
correctly. To do this, we'll create a new query application based on our existing application.
A5.35: In the Explorer view, right click 'create.ts' and select 'Copy'.
A5.36: Select the 'src' folder, right click and select 'Paste'.
This will create a new file inside the 'src' folder called 'create copy.ts'.
A5.39: With query.ts loaded in the editor, find and select the lines that submit the transaction:
Our new application will attempt to evaluate the readMyAsset transaction and display the result.
A5.40: Use copy and paste to replace these lines with the following:
We can test the new application by running the correct task in npm. To save time, we created the query task
when we implemented the package.json file earlier:
A5.42: In the main VS Code menu, click 'Terminal' -> 'Run Task...'.
A5.43: Find and select the task 'npm: query demo-application'. You may also need to click Show All
Tasks.
A5.44: Click 'Continue without scanning the task output'.
The task will be run and again, after a brief pause, you will see it complete successfully.
Note that the output now shows the current value of the '002' key we entered earlier.
Congratulations! You've now written two applications: one that submits new transactions to the ledger and
another that queries the current value of the ledger.
Summary
In this tutorial we have built client applications that can submit and evaluate transactions on a Hyperledger
Fabric blockchain.
Although the Fabric instance we've been working with is part of our VS Code environment, these applications
can connect to any Hyperledger Fabric blockchain: you simply use the identity and connection profile for the
target network when you create a gateway object you instantiate in your application.
In the same way as applications can change, smart contracts can evolve too. In the next tutorial we will try
modifying our smart contract to see how the upgrade process works.