Development
Development environment
Local environment configuration

Local environment configuration

Clone the Logos development environment repository

$ cd ~/... # wsl /home of the user
$ git clone https://github.com/logoslabstech/logos-dev-environment # master branch
$ git checkout -b >new-branch-name< # create and change branch
$ mkdir ~/temp & mkdir ~/temp/acc & mkdir ~/temp/logos-dev-environment # create a temp directories for blochain states

Ensure the correctness of the default rust configuration

~/.rustup/settings.toml
default_toolchain = "stable-x86_64-unknown-linux-gnu" # nightly --> stable
profile = "default"
version = "12"
 
# If there [overrides] REMOVE them 
# Example
[overrides]
"/home/user/../../" = "stable-x86_64-unknown-linux-gnu"

Build the Logos development environment project

$ cd ~/.../logos-dev-environment # change to the root directory of the repository.
$ cargo build --release # The "--release" build optimizes the code for performance, which leads to longer compilation times.
# For the first build and when major changes have been made, it is not a bad idea to do the whole build again
💡

For day-to-day development, it's recommended to use cargo build (incremental build) without the --release flag. This compiles the project in debug mode, which is much faster because it performs fewer optimizations. The result is slower code at runtime, but this shouldn't be a major issue during development since the focus is on quickly testing changes.

How to start a local single node development chain or a local test network

💡

predefined accounts: Alice, Bob, Charlie
sp-core::keyring (sp-core pallet and keyring module)

Creating custom accounts with subkey and integrating them into the Genesis configuration offers a flexible and future-proof method of meeting specific requirements without having to intervene in the Substrate Core modules. For development and testing, the predefined accounts such as "Alice", "Bob" etc. are enough for our purposes.

There are two types of developer mode depending on what you want to develop or test:

  • Single node chain for development purposes (no blochain state)
Start the development single node chain
$ cd ~/.../logos-dev-environment
$ ./target/release/dev-node --base-path ~/temp/logos-dev-environment/ --dev
⚠️

Don't forget to purge the development chain's state after you done

$ cd ~/.../logos-dev-environment
$ rm -rf ~/temp/logos-dev-environment/chains
  • Local network for engineering purposes (network specific development)
Start the first node
$ cd ~/.../logos-dev-environment
$ ./target/release/dev-node \
--base-path ~/temp/acc/alice \
--chain local \
--alice \
--port 30333 \
--rpc-port 9945 \
--node-key 0000000000000000000000000000000000000000000000000000000000000001 \
#--telemetry-url "wss://telemetry.logoslabs.io/submit/ 0" \
--validator

Explanation

  • --base-path ~/temp/alice - Specifies the directory for storing all of the data related to this chain.
  • --chain local - Specifies the chain specification to use. Valid predefined chain specifications include local, development, and staging.
  • --alice - Adds the predefined keys for the alice account to the node's keystore. With this setting, the alice account is used for block production and finalization.
  • --port 30333 - Specifies the port to listen on for peer-to-peer (p2p) traffic. Two nodes will run on the same physical computer to simulate a network, it must be different port for at least one account.
  • --rpc-port 9945 - Specifies the port on which the server will listen for incoming JSON-RPC traffic via WebSocket and HTTP. The default port is 9944.
  • --node-key - Specifies the Ed25519 secret key to use for libp2p networking. Only use this option for development and testing.
  • --telemetry-url - Specifies where to send telemetry data. Currently not available.
  • --validator - Specifies that this node participates in block production and finalization for the network.
Start the second node
$ ./target/release/dev-node \
--base-path ~/temp/acc/bob \
--chain local \
--bob \
--port 30334 \
--rpc-port 9946 \
--validator \
--bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp 
# This command includes the --bootnodes option and specifies a single boot node, the node started by alice.

Explanation --bootnodes instruction:

  • ip4 - indicates that the IP address for the node uses the IPv4 format.
  • 127.0.0.1 - specifies the IP address for the running node.
  • tcp - specifies TCP as the protocol used for peer-to-peer communication.
  • 30333 - specifies the port number used for peer-to-peer communication. In this case, the port number for TCP traffic.
  • 12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp - identifies the running node to communicate with for this network. In this case, the identifier for the node started using the alice account.
⚠️

Don't forget to purge the chain's state after you done

$ cd ~/.../logos-dev-environment
$ rm -rf ~/temp/acc/alice/
$ rm -rf ~/temp/acc/bob/

Connect with Polkadot-JS Apps Front-End and bookmark it

Prepare for ink! smart contracts development

Our blockchain will be mainly used to execute ink! smart contracts.

Test your environment

Compile the hello_contract

$ cd ~/.../logos-dev-environment/contracts/hello_contract
$ cargo contract build --release
# output example
...
- hello.contract (code + metadata) 
- hello.wasm (the contracts code)
- hello.json (the contracts metadata)

Deploy the hello_contract via CLI

⚠️

Your development node must be started

$ cd ~/.../logos-dev-environment/contracts/hello_contract
$ cargo contract upload --suri //Alice --execute
$ cargo contract instantiate --suri //Alice --args true --execute

Deploy the hello_contract via the PolkadotJs UI

⚠️

Your development node must be started

Go to Polkadot.JS app (opens in a new tab) (Development -> Contracts)

polkadotjs

Deploy the hello_contract via the contract UI

⚠️

Your development node must be startet

Go to contracts-ui (opens in a new tab) app

contract-ui
⚠️

Although Polkadot-JS and Substrate's Contracts UI are designed to interact with the same blockchain, differences in the implementation of the front-ends or in the way transactions are formulated and sent can lead to different results.

Polkadot-JS allows detailed configuration of transaction parameters, including gasLimit and storageDepositLimit. If these parameters are not set correctly, this could cause transactions to fail or "hang", especially if the default gas limit is too low. Substrate's Contracts UI could internally use other default values or heuristics to set these parameters, resulting in a smoother experience.

⚠️

The preferred method is to deploy and test the contracts via the PolkadotJs UI. Since this is a development environment, it can sometimes happen that due to the chain development there are issues when deploying smart contracts because of block limitation, for example. In such a case, the contract can still be deployed and tested via the contracts UI, because the contracts UI uses internal values and heuristics and allows the contract to be deployed and instantiated.

This is currently a workaround.

💡

Uploaded code vs. contract instances

  • Uploaded code (code hash):
    When you upload the smart contract code, it is stored on the network and is identified by a unique code hash. At this point, there is no running instance of the contract, only the code itself, which can potentially be used to create instances.

  • Contracts (instances): A contract instance (or simply a "contract") is created when you "instantiate" or "deploy" the uploaded code. This initializes a specific execution of the code on the blockchain, often with specific design parameters. This instance has its own state and can be interacted with using transactions.

Don't worry about the newly created files in the git-repo directory

.gitignore
# Generated by Cargo
# will have compiled files and executables
**/target/
# These are backup files generated by rustfmt
**/*.rs.bk

.DS_Store

# direnv files
.envrc
.direnv

Optimize your development cycles (if you want)

Additionally, following practices can be applyed to optimize the development cycles:

  • cargo check: If you just want to check if the code compiles without producing an executable program, use cargo check.
$ cd ~/.../logos-dev-environment
$ cargo check
  • cargo run: For applications that can be run, such as a Substrate node, cargo run can be used to combine the build process and launching of the program in one step. In development, you can do this without the --release flag to save time.
$ cd ~/.../logos-dev-environment
$ cargo run 
⚠️

In this case, the network (requires 2 nodes) will be started and not the logos template node. An additional node must then be started manually.

  • Testing with cargo test: Running tests don't always have to be done in release mode. Use cargo test during development to quickly go through your unit and integration tests. If you have any.
$ cd ~/.../logos-dev-environment
$ cargo test 

Purge the environment

💡

When for some reason a complete rebuild of the project is required, the cargo clean command can be used. The cargo clean command removes the previous compilation results, which means that the entire project will be recompiled from scratch during the next cargo build.

cd ~/.../logos-dev-environment
$ cargo clean 
Removed 20470 files, 17.0GiB total # output example
 
$ rm -rf ~/temp/logos-dev-environment/* & rm -rf ~/temp/acc/*

GIT is your Nakama

⚠️

Don't forget to push your changes if you have some, you don't want to write the code again

You are good to go!