Hello World
Welcome to the step-by-step guide of creating the Hello World application with the Lisk SDK. The Hello World application is a simple blockchain app that showcases a minimal setup of a blockchain application with one custom transaction: the "Hello" transaction.
The purpose of the 'Hello World' application is to explain both how to implement and use custom transactions with the Lisk SDK. This custom transaction will extract the "hello" key value from the transaction asset property, and save it to the sender’s account.
The 'Hello World' implementation steps are listed below:
-
Steps 1-5 describes the implementation requirements on the node side of the blockchain application.
-
Step 6 explains how to interact with the network from the client side.
-
Step 7 explains how to override specific config values.
For the full code example please see the Hello World App on Github. |
1. Installation & setup
Firstly, create the root folder for the 'Hello World' app and initialize the project:
mkdir hello_world (1)
cd hello_world (2)
npm init --yes (3)
1 | Create the root folder for the blockchain application. |
2 | Navigate into the root folder. |
3 | Initialize the manifest file of the project. |
The next step is to install the lisk-sdk
package and add it to the project’s dependencies.
Please ensure that the Lisk SDK pre-installation steps steps have been completed. |
Supported platforms
-
Ubuntu 16.04 (LTS) x86_64
-
Ubuntu 18.04 (LTS) x86_64
-
MacOS 10.14 (Mojave)
-
macOS 10.15 (Catalina)
Dependencies
Dependencies | Version |
---|---|
Node.js |
v12 |
PostgreSQL |
10+ |
Redis (optional) |
5+ |
Python |
2 |
npm install lisk-sdk@4.0.0 (1)
1 | Install the Lisk SDK as a dependency for the node application. |
The default database name is lisk_dev
.
Create the database lisk_dev
with the lisk
user as the owner.
createdb lisk_dev --owner lisk
The default database user and password are |
2. Initialize and configure the application
Create the file index.js
.
This will hold the logic to initialize and start the blockchain application as shown below:
touch index.js
Now open the newly created file index.js
that was created with the previous step, and insert the following code shown below:
const { Application, genesisBlockDevnet, configDevnet } = require('lisk-sdk'); (1)
configDevnet.label = 'hello-world-blockchain-app'; (2)
//configDevnet.components.storage.user = '<username>'; (3)
//configDevnet.components.storage.password = 'password'; (4)
const app = new Application(genesisBlockDevnet, configDevnet); (5)
app (6)
.run()
.then(() => app.logger.info('App started...'))
.catch(error => {
console.error('Faced error in application', error);
process.exit(0);
});
See the file on GitHub: hello_world/index.js. |
1 | Require Application class, the devnet genesis block and the devnet config for the application.
The dependencies are required from the lisk-sdk package.
The most important dependency is the Application class, which is used in <5> to create the Application instance.
The Application instance will start the whole application at the bottom of index.js . |
2 | Set the name of the blockchain application. |
3 | In the case whereby a different user other than lisk was provided to gain access to the database lisk_dev , it will be necessary to update the username in the config. |
4 | Uncomment this and replace password with the password for your database user. |
5 | Create the application instance. By sending the parameters for the genesis block and the Devnet configuration file, the application is now configured with basic configurations to start the network. |
6 | The code block below starts the application and does not need to be changed. |
To change any of the values for configDevnet , please see the full list of configurations for Lisk SDK and overwrite them as described in configuration guide.
|
After the code block above has been added, save and close index.js
.
At this point, the node and the network can now be started in order to verify that the setup was successful:
node index.js
If everything is functioning correctly, the following logs will be displayed:
$ node index.js 10:51:10 INFO lisk-framework: If you experience any type of error, please open an issue on Lisk GitHub: https://github.com/LiskHQ/lisk-sdk/issues (module=lisk:app) 10:51:10 INFO lisk-framework: Contribution guidelines can be found at Lisk-docs: https://github.com/LiskHQ/lisk-docs/blob/build/CONTRIBUTING.adoc (module=lisk:app) 10:51:10 INFO lisk-framework: Booting the application with Lisk Framework(0.1.0) (module=lisk:app) 10:51:10 INFO lisk-framework: Starting the app - HelloWorld-blockchain-app (module=lisk:app) 10:51:10 INFO lisk-framework: Initializing controller (module=lisk:app) 10:51:11 INFO lisk-framework: Loading controller (module=lisk:app) 10:51:11 INFO lisk-framework-http-api: Loading in-memory module (module=lisk:app) { "version": "0.1.0", "moduleAlias": "http_api" } 10:51:11 INFO lisk-framework-http-api: Loaded in-memory module (module=lisk:app) { "version": "0.1.0", "moduleAlias": "http_api" } 10:51:11 INFO lisk-framework: Modules ready and launched (module=lisk:app) 10:51:12 INFO lisk-framework: New block added to the chain (module=lisk:app) { "id": "1349213844499460766", "height": 1, "numberOfTransactions": 310 } 10:51:12 INFO lisk-framework: Blockchain ready (module=lisk:app) 10:51:12 INFO lisk-framework: App started... (module=lisk:app) 10:51:12 INFO lisk-framework: Loading 103 delegates using encrypted passphrases from config (module=lisk:app) 10:51:12 INFO lisk-framework: Forging enabled on account: 8531579280410192796L (module=lisk:app) 10:51:12 INFO lisk-framework: Forging enabled on account: 7700165370820050502L (module=lisk:app) 10:51:12 INFO lisk-framework: Started Lisk (module=http_api) { "address": "0.0.0.0", "httpPort": 4000 } 10:51:12 INFO lisk-framework: Event app:loader:sync was subscribed but not registered to the bus yet. (module=lisk:app) 10:51:12 INFO lisk-framework: Forging enabled on account: 18070013346623491378L (module=lisk:app) 10:51:12 INFO lisk-framework: Forging enabled on account: 13803933794686825569L (module=lisk:app) 10:51:12 INFO lisk-framework: Forging enabled on account: 13782190884886479261L (module=lisk:app) 10:51:12 INFO lisk-framework: Forging enabled on account: 3426690280983981237L (module=lisk:app) 10:51:12 INFO lisk-framework: Forging enabled on account: 2239791898636671159L (module=lisk:app) [...]
To stop the blockchain process, press CTRL+C.
3. Create a new transaction type
For the 'Hello World' App, it is necessary to create a custom transaction HelloTransaction
:
If the account contains an adequate enough balance to process the HelloTransaction
transaction, the new "hello" property will appear into the account’s asset field as shown below:
The next step is to define the new transaction type, HelloTransaction
as described below.
First, create a new folder transactions
, which will store the custom transactions, in this case the HelloTransaction
.
mkdir transactions
cd transactions
npm init --yes
npm i @liskhq/lisk-transactions
Next, create and open the file hello_transaction.js
and insert the following code shown below:
const {
BaseTransaction,
TransactionError
} = require('@liskhq/lisk-transactions');
class HelloTransaction extends BaseTransaction {
static get TYPE () {
return 20;
};
static get FEE () {
return `${10 ** 8}`;
};
async prepare(store) {
await store.account.cache([
{
address: this.senderId,
},
]);
}
validateAsset() {
const errors = [];
if (!this.asset.hello || typeof this.asset.hello !== 'string' || this.asset.hello.length > 64) {
errors.push(
new TransactionError(
'Invalid "asset.hello" defined on transaction',
this.id,
'.asset.hello',
this.asset.hello,
'A string value no longer than 64 characters',
)
);
}
return errors;
}
async applyAsset(store) {
const errors = [];
const sender = await store.account.get(this.senderId);
if (sender.asset && sender.asset.hello) {
errors.push(
new TransactionError(
'You cannot send a hello transaction multiple times',
sender.asset.hello,
'.asset.hello',
this.asset.hello
)
);
} else {
sender.asset = { hello: this.asset.hello };
store.account.set(sender.address, sender);
}
return errors; // array of TransactionErrors, returns empty array if no errors are thrown
}
async undoAsset(store) {
const sender = await store.account.get(this.senderId);
sender.asset = null;
store.account.set(sender.address, sender);
return [];
}
}
module.exports = HelloTransaction;
See the file on GitHub: hello_world/transactions/hello_transaction.js |
After adding the code block above, save and close hello_transaction.js
.
4. Register the new transaction type
At this point the project should have the following file structure as shown below:
hello_world ├── transactions │ ├── hello_transaction.js │ ├── node_modules │ └── package.json ├── index.js ├── node_modules └── package.json
Add the new transaction type to your application, by registering it to the application instance inside of index.js
.
How to create this file is shown below:
touch index.js
It is only required to add 2 new lines to the existing index.js , to register the new transaction type.
|
HelloTransaction
in index.js
const { Application, genesisBlockDevnet, configDevnet} = require('lisk-sdk');
const HelloTransaction = require('./hello_transaction'); (1)
configDevnet.label = 'hello-world-blockchain-app';
//configDevnet.components.storage.user = '<username>'; (4)
//configDevnet.components.storage.password = 'password'; (5)
const app = new Application(genesisBlockDevnet, configDevnet);
app.registerTransaction(HelloTransaction); (2)
app (8)
.run()
.then(() => app.logger.info('App started...'))
.catch(error => {
console.error('Faced error in application', error);
process.exit(0);
});
Please see the file on Github: hello_world/index.js. |
1 | New line: Require the newly created transaction type 'HelloTransaction'. |
2 | New line: Register the 'HelloTransaction'. |
After the 2 new lines shown above are added to your index.js
file, save and close it.
5. Start the network
It should now be possible to start the customized blockchain network for the first time.
The parameter configDevnet
, which is passed to the Application
instance in step 3, is preconfigured to start the node with a set of genesis delegates, that have enabled forging by default in the Devnet.
These genesis delegates stabilize the new network, and ensure it is possible to test out the basic functionality of the network immediately with only one node, which in turn is beneficial during development of the blockchain application.
The genesis delegates can be replaced with real delegates later. To facilitate this, the users need to create new accounts and register themselves as delegates on the network. More information about this can be found in the guide which covers how to launch an application. |
To start the network again, run the command shown below:
node index.js
Please check the logs in order to to verify that the network has started successfully.
If any problems occur, then the process should stop and an error with debug information will be displayed.
6. Interact with the network
Now with the network running, try to send a HelloTransaction
to the node to see if it will be accepted.
As your blockchain process is running in your current console window, it is necessary to open a new window to proceed with the tutorial. Make sure to navigate into the root folder of your blockchain application in the new console window. |
How to create sendable transaction objects
Once inside the root folder of the 'Hello World' application, create the file that will hold a code snippet to create the transaction object:
npm i @liskhq/lisk-client@4.0.0
touch print_sendable_hello-world.js
Now open the newly created file and paste the following code:
const HelloTransaction = require('../transactions/hello_transaction');
const { cryptography } = require('@liskhq/lisk-client');
const networkIdentifier = cryptography.getNetworkIdentifier(
"19074b69c97e6f6b86969bb62d4f15b888898b499777bda56a3a2ee642a7f20a",
"Lisk",
);
const tx = new HelloTransaction({ (1)
asset: {
hello: 'world',
},
nonce: "103",
fee: "1000000"
});
tx.sign(networkIdentifier,'peanut hundred pen hawk invite exclude brain chunk gadget wait wrong ready'); (2)
console.log(tx.stringify()); (3)
process.exit(0);
1 | The desired transaction object is created. |
2 | The transaction is signed by the genesis account. |
3 | The transaction is displayed as a JSON object in the console. |
To get the nonce of an account, view the respective account details. This can be achieved via an API call as described in the Broadcast a transaction guide. |
The following script will print the transaction in the console. (When it is executed the Python’s json.tool is used to prettify the output):
node print_sendable_hello-world.js | python -m json.tool
The generated transaction object will be logged in the console:
{
"asset": {
"hello": "world"
},
"fee": "1000000",
"id": "16496489785787724389",
"nonce": "103",
"senderId": "5059876081639179984L",
"senderPublicKey": "0fe9a3f1a21b5530f27f87a414b549e79a940bf24fdf2b2f05e7f22aeeecc86a",
"signatures": [
"db6cf96756fe537eebe427f40f8832d14a408e38ab2b0a40a8e584bf22642c59556dcf9452b9021205338ffc6db6e29dd3fc34795e66be26c6e88376382e6c02"
],
"type": 20
}
This transaction object can be posted to a node.
More information about how to interact with the blockchain application can be found in the Interact with the API guide.
A simple react frontend
Now that we know how to create sendable transaction objects, let’s discover the application through a simple react frontend.
Please download the react-client folder and add it to the root of the 'Hello World' application.
cd ..
git clone git@github.com:LiskHQ/lisk-sdk-examples.git
cd hello_world
git checkout v4
cp -r ../lisk-sdk-examples/hello_world/react-client react-client
cd react-client
npm i
npm start
The 'Hello World' frontend is now available under localhost:8080
To test the frontend, always ensure your node application is still running in the other terminal window. |
The react client offers a collection of simple scripts for the most common interactions for a blockchain application. In addition, it provides you with a good start to extend and adjust the application further to fit your particular use case.
Please see the Connect a frontend guide for a detailed description of the react client and its contents. |
Optional: Run the app in the background
For further interaction with the network, it is possible to run the node in the background by executing the following commands:
cd hello_world (1)
pm2 start --name hello index.js (2)
pm2 stop hello (3)
pm2 start hello (4)
1 | Navigate into the root folder of the 'Hello World' application. |
2 | Add the application to pm2 under the name 'hello'. |
3 | Stop the hello app. |
4 | Start the hello app. |
PM2 must be installed on the system in order to run these commands. Please see the SDK pre-installation section. |
7. Customize the default configuration
Your project should now contain the following file structure:
hello_world ├── react-client/ ├── transactions/ │ ├── node_modules/ │ ├── package.json │ └── hello_transaction.js ├── print_sendable_hello-world.js ├── hello_transaction.js ├── index.js ├── node_modules/ └── package.json
To run the script remotely, change the configuration before creating the Application
instance, in order to make the API accessible as shown below:
For more configuration options, please see the full list of configurations for the Lisk SDK. |
const { Application, genesisBlockDevnet, configDevnet} = require('lisk-sdk'); (1)
const HelloTransaction = require('./hello_transaction'); (2)
configDevnet.label = 'hello-world-blockchain-app'; (3)
//configDevnet.components.storage.user = '<username>'; (4)
//configDevnet.components.storage.password = 'password'; (5)
configDevnet.modules.http_api.access.public = true; (6)
//configDevnet.modules.http_api.access.whitelist.push('1.2.3.4'); (7)
const app = new Application(genesisBlockDevnet, configDevnet); (8)
app.registerTransaction(HelloTransaction); (9)
app (10)
.run()
.then(() => app.logger.info('App started...'))
.catch(error => {
console.error('Faced error in application', error);
process.exit(0);
});
1 | Require Application class, the default genesis block and the default config for the application. |
2 | Require the newly created transaction type HelloTransaction . |
3 | Set the name of your blockchain application. |
4 | In the case whereby a different user than lisk was provided, to gain access to the database lisk_dev , it is necessary to update the username in the config. |
5 | Uncomment this and replace password with the password for your database user. |
6 | Make the API accessible from everywhere. |
7 | Example how to make the API accessible for specific IP addresses: add 1.2.3.4 IP address as whitelisted. |
8 | Creates the application instance. |
9 | Registers the 'HelloTransaction'. |
10 | The code block below starts the application and does not need to be changed. |
Optional: After the first successful verification, the possibility exists to reduce the default console log level (info), and file log level (debug).
This can be achieved by sending a copy of the config object,
|