Welcome to the Aergo Developers Guide!

Aergo is an open blockchain platform that allows businesses to build innovative applications and services by sharing data on a trustless and distributed IT ecosystem. Aergo combines the best of public and private blockchains to be scalable, enterprise-ready, and easy to develop with.

This website contains guides for developers to get started developing with Aergo and detailed references.

Introduction

Aergo is developing a practical blockchain platform, frameworks, libraries, and tools.

Design goals

There are four main ideologies regarding this project.

  • Developer-friendly
  • Guaranteed performance
  • Scalable architecture
  • Open, extensible, inter-connectable network

Current features

  • BFT-dPOS with voting

  • Name system

  • Aergo Lua smart contract

  • Ship (development framework, package management)

  • Simple client API

  • Client SDKs

  • Sub projects

    • Litetree
    • Sparse Merkle Tree
  • Hub Enterprise (management and monitoring)

  • Merkle bridge verification

  • Testnet deployment

Roadmap

These features are under active development or planned.

  • Aergo SQL
  • Parallelism (inter-contract)
  • Simple branching (2WP or simple Plasma)
  • Orchestration with Aergo Horde
  • Service with Aergo Hub
  • Advanced performance features

Dapp Development

This article gives an introduction into the high level approach to developing dapps on the AERGO blockchain.

Development cycle

These are components of today’s blockchain application development cycle that Aergo offers new solutions for.

  1. Design (UX patterns, economic models)
  2. Clients (interacting with the blockchain)
  3. Smart contracts (new programming patterns, debugging and testing)
  4. Infrastructure (deployment cost, security, privacy, monitoring)

Design

The possibilities of designing applications for Aergo are endless: social networks, distributed organizations, games, monetary systems, asset management, trading, databases, public deliberation, crowdsourcing, …

Aergo tries to not limit designers’ and developers’ creativity to create novel applications. However, the platform aims to offer reasonable guidelines, standard protocols, and well-tested models to make designing dapps easier than ever.

Clients

Using the Hera SDK family, client applications can easily interact with the blockchain.

Smart contracts

Smart contracts are the main backend component of distributed applications. As other blockchain platforms had a serious limitation in terms of cost and scalability, it used to be not feasible to develop large scale, complex systems. With Aergo and the use of embedded sidechains and proof systems, smart contracts can really shine.

Aergo also offers a development toolchain that includes package management, Aergo Ship.

Infrastructure

Aergo is currently available as a public testnet and separate private installations. In the future, a network of blockchains can be orchestrated using Aergo Horde. Aergo Hub will offer an easy configuration and monitoring interface. With these features, developers will not have to worry about the deployment of their applications.

Running a Node

This section includes general instructions for running Aergo nodes.

If you want to connect to an existing Aergo network (such as the public mainnet and testnet), please also refer to this section for more details.

Quickstart

The easiest way to run a local Aergo server is using Docker.

docker run -p 7845:7845 aergo/node

You can pass arguments to the server like this:

docker run -p 7845:7845 aergo/node aergosvr --testmode

To supply your own config file, use:

docker run -p 7845:7845 -v $(pwd)/config.toml:/aergo/config.toml aergo/node aergosvr --config /aergo/config.toml

Building from source: You can also build the binaries yourself from source. See here for details.

Syncing with public networks: Please refer to the syncing guide for more instructions.

Configuration

This page explains the possible ways to configure an Aergo node.

There are three common modes of operation for aergo server:

  • BP Node - Block provider node, which mines and propagates blocks
  • Full Node - Node to get and validate all blocks
  • Single Node - BP Node without peer, which uses to something like test.

We describe only single node configuration in this. More will updated for the BP Node and full node.

Single Aergo Server

We will show default configuration file next. You can check the each fields’ meaning in here

# aergo TOML Configuration File (https://github.com/toml-lang/toml)
# base configurations
datadir = ".aergo/data"
enableprofile = false
profileport = 6060
enablerest = false
enabletestmode = false
authdir = ".aergo/auth"

[rpc]
netserviceaddr = "127.0.0.1"
netserviceport = 7845
nstls = false
nscert = ""
nskey = ""
nsallowcors = false

[rest]
restport = "8080"

[p2p]
# Set address and port to which the inbound peers connect, and don't set loopback address or private network unless used in local network 
netprotocoladdr = "" 
netprotocolport = 7846
npbindaddr = ""
npbindport = -1 
# Set file path of key file
npkey = ""
npaddpeers = [
]
nphiddenpeers = [
]
npmaxpeers = 100
nppeerpool = 100
npexposeself = true
npusepolaris = true
npaddpolarises = [
]

[blockchain]
# blockchain configurations
maxblocksize = 1048576

[mempool]
showmetrics = false
dumpfilepath = ".aergo/mempool.dump"

[consensus]
enablebp = true

Testmode

To enable testmode, either pass the command line option --testmode to aergosvr or set enabletestmode = true in the configuration.

In testmode, all new accounts are assigned a high number of Aergo tokens by default, basically circumventing balance checks. This means you can send any transaction without first pre-funding hard-coded accounts using a genesis block.

Testmode MUST NOT be used in production.

Reference

Module Property name Meaning
(default) datadir data files' base path
enableprofile whether use profie
profileport profile port
enablerest whether use REST API
enabletestmode whether test mode
personal enable personal account API
rpc netserviceaddr rpc hostname or address
netserviceport rpc port number
nstls whether applying tls to rpc
nscert certificate file path for rpc tls
nskey key file path for rpc tls
nsallowcors whether allows CORS
rest restport port number for REST API
p2p netprotocoladdr ip address or domain name to which other peers connect
netprotocolport port number for connect
npbindaddr listener binding address
npbindport listener binding port
npkey key file path for p2p tls
npaddpeers initial peer list on start-up
nphiddenpeers peerid list which will not inform to other peers
npexposeself whether to advertise node to Polaris <../tools/polaris.html>__ or other peers.
npusepolaris whether to connect Polaris for finding other peers
npaddpolarises list of addresses of custom polaris
blockchain maxblocksize maximum block size
coinbaseaccount address where is send rewards for mining
mempool showmetrics whether if turn periodic log on
dumpfilepath file path for recording mempool at process termination
verifiers number of concurrency for sign verifying
consensus enablebp whether this node is BP

Logging options

It is possible to customize the log output format of all Aergo CLI tools using a file called arglog.toml placed in the current working directory.

This file is specified here.

level = "info"  # default log level
formatter = "json"  # format: console, console_no_color, json
caller = true  # enabling source file and line printer
timefieldformat = "RFC3339"

[chain]
level = "info"  # optional, log level for 'chain' module

[dpos]
level = "info"

[p2p]
level = "info"

[consensus]
level = "info"

[mempool]
level = "info"

[contract]
level = "info"

[syncer]
level = "info"

[bp]
level = "info"

Monitoring

Aergo server has 5 major subcomponents: Account, Chain, MemPool, RPC, and P2P.

We can get status of component using aergocli node command (see here for detail).

$ aergocli node 
{
        "AccountsSvc": {
                "status": "started",
                "acc_processed_msg": 3,
                "msg_queue_len": 0,
                "msg_latency": "69.851µs",
                "error": "",
                "actor": null
        },
        "ChainSvc": {
                "status": "started",
                "acc_processed_msg": 238,
                "msg_queue_len": 0,
                "msg_latency": "68.849µs",
                "error": "",
                "actor": {
                        "orphan": 0
                }
        },
        "MemPoolSvc": {
                "status": "started",
                "acc_processed_msg": 237,
                "msg_queue_len": 0,
                "msg_latency": "59.462µs",
                "error": "",
                "actor": {
                        "cache_len": 0,
                        "dead": 0,
                        "orphan": 0
                }
        },
        "RPCSvc": {
                "status": "started",
                "acc_processed_msg": 120,
                "msg_queue_len": 0,
                "msg_latency": "71.785µs",
                "error": "",
                "actor": null
        },
        "p2pSvc": {
                "status": "started",
                "acc_processed_msg": 120,
                "msg_queue_len": 0,
                "msg_latency": "54.783µs",
                "error": "",
                "actor": null
        }
}

As it shown above, each component has 6 values, which are

  • status *
  • acc_processed_msg
    • number of message processed by the component
    • message is basic unit for communicate with other components
  • msg_queue_len
    • number of pending messages for the component
  • msg_latency
    • average latency for processing a message
  • error *
  • actor
    • component specific statistics are shown
    • for example, ChainSvc “actor”: { “orphan”: 0 } orphan represents number of orphan block the component has

Configuring a Network

This article explains the steps needed to configure a network of multiple block producers. You can follow this guide to setup a private Aergo blockchain network.

This guide specifically requires no prior setup, so it should be easy to follow along with new bare machines running Ubuntu. It has been tested with AWS EC2 instances. We will setup three block producers, but you can adjust the procedure to any number of BPs.

Per-machine setup

Install Docker

You will need Docker for this setup, so let’s install that now.

sudo apt-get update && sudo apt-get install docker.io
sudo usermod -aG docker ubuntu

NTP

Timing is critical in a blockchain, so it’s better to configure the machines’ time setup manually:

sudo bash
apt-get install chrony
vi /etc/chrony/chrony.conf
server time1.google.com iburst
server time2.google.com iburst
server time3.google.com iburst
server time4.google.com iburst
systemctl restart chronyd
chronyc makestep

Generate BP accounts and keys

You can use any machine (e.g. your own local machine) for this.

Start by installing aergocli if you haven’t already.

Generate accounts

aergocli account new --password yourpassword --path genesis
(displays generated address)

aergocli account new --password yourpassword --path bp01
(displays generated address)

aergocli account new --password yourpassword --path bp02
(displays generated address)

aergocli account new --password yourpassword --path bp03
(displays generated address)

Export accounts

aergocli account export --address [insert address from genesis]  --password yourpassword --path genesis
(displays exported private key)

aergocli account export --address [insert address from bp01]  --password yourpassword --path bp01
(displays exported private key)

aergocli account export --address [insert address from bp02]  --password yourpassword --path bp02
(displays exported private key)

aergocli account export --address [insert address from bp03]  --password yourpassword --path bp03
(displays exported private key)

Generate peer keys

aergocli keygen bp01
Wrote files bp01.{key,pub,id}.

aergocli keygen bp02
Wrote files bp02.{key,pub,id}.

aergocli keygen bp03
Wrote files bp03.{key,pub,id}.

Write configuration files

genesis.json (same for all machines)

{
    "chain_id":{
        "magic": "[insert an identifier string for your network]",
        "public": false,
        "mainnet": false,
        "consensus": "dpos"
    },
    "timestamp": 1548918000000000000,
    "balance": {
        "[insert address from genesis]": "470000000000000000000000000",
        "[insert address from bp01]": "10000000000000000000000000",
        "[insert address from bp02]": "10000000000000000000000000",
        "[insert address from bp03]": "10000000000000000000000000"
    },
    "bps": [
        "[insert text from bp01.id]",
        "[insert text from bp02.id]",
        "[insert text from bp03.id]"
    ]
}

config.toml (one per machine)

# aergo TOML Configration File (https://github.com/toml-lang/toml)
# base configurations
datadir = "./data"
enableprofile = true
profileport = 6060
enablerest = true
personal = false

[rpc]
netserviceaddr = "0.0.0.0"
netserviceport = 7845
nstls = false
nscert = ""
nskey = ""
nsallowcors = false

[p2p]
netprotocoladdr = "{LOCAL_IP}"  # Insert IP address from this machine
netprotocolport = 7846
npbindaddr = "0.0.0.0"
npbindport = 7846
nptls = false
npcert = ""
npkey = "bp{01,02,03}.key"  # Name of key file of node
npaddpeers = [
    "/ip4/[IP ADDRESS FROM BP 01]/tcp/7846/p2p/[PEER ID FROM BP 01]",
    "/ip4/[IP ADDRESS FROM BP 02]/tcp/7846/p2p/[PEER ID FROM BP 02]",
    "/ip4/[IP ADDRESS FROM BP 03]/tcp/7846/p2p/[PEER ID FROM BP 03]"
]

npexposeself = false
npusepolaris = false
nphiddenpeers= [
    "[PEER ID FROM BP 01]",
    "[PEER ID FROM BP 02]",
    "[PEER ID FROM BP 03]"
]

[blockchain]
usefastsyncer = true
blockchainplaceholder = false
coinbaseaccount = "[ADDRESS FROM THIS PEER]"

[mempool]
showmetrics = true
dumpfilepath = "./data/mempool.dump"

[consensus]
enablebp = true

Running

We are going to use the Docker image aergo/node to run the server. Please refer to the Docker documentation for learn about the available run options.

Check the directory contents

After following the above steps, you should now have these files in one directory for each machine. In this example we use the path /blockchain, but you can use any directory as long as you substitute its local path in the Docker run commands below.

/blockchain/
    bp{01,02,03}.key
    genesis.json
    config.toml

Create genesis block

docker run --rm \
    -v /blockchain:/aergo \
    aergo/node \
    aergosvr init --genesis /aergo/genesis.json --home /aergo --config /aergo/config.toml

Start the node

docker run -d --log-driver json-file --log-opt max-size=1000m --log-opt max-file=7 \
    -v /blockchain:/aergo \
    -p 7845:7845 -p 7846:7846 -p 6060:6060 \
    --restart="always" --name aergo-node \
    aergo/node \
    aergosvr --home /aergo --config /aergo/config.toml

Further reading

You may now want to setup further full nodes as well as Polaris for automatic node discovery.

Advanced Topics

Genesis block configuration

The genesis block is the first block created on a new chain according to a predefined specification. If you want to bootstrap your own Aergo blockchain, you will need to configure and create the genesis block. All nodes producing blocks and syncing with the network need to use the same genesis block.

You can find an example genesis configuration json file here. It is the one used for the public testnet.

Key Type Explanation
chain_id obj  
– magic string A name identifier used to distinguish different chains. Example: testnet.aergo.io
– public bool If this chain is for a public (true) or private network. This may affect certain features.
– mainnet bool If this is the main network (true) or a sidechain for another network.
– consensus string This blockchain’s consensus type (dpos)
– coinbasefee string The default transaction fee amount
timestamp number The genesis block’s creation timestamp in nanoseconds
balance obj A mapping of addresses and allocated balances
bps list A list of fallback block producer peer ids.

Manually creating peer identification

Every peer (i.e. instance of aergosvr) is identified by a peer id, derived from its public key. If unspecified, aergosvr creates these automatically, but you may want to do it manually to control the generation of keys and make backups. You can use the CLI to do that:

aergocli keygen your-keyname

# Using Docker:
docker run --rm -v $(pwd):/tools/ aergo/tools aergocli keygen your-keyname

You then need to specify the path to the generated your-keyname.key file in the Aergo configuration:

...
[p2p]
npkey = "/aergo/your-keyname.key"
...

Troubleshooting

Storage errors

DB initilaize failure

Aergo uses Badger DB as its internal storage. If the DB creation fails for Badger at initial boot, boot process will fail.

In this case, you can see the following error when checking the server’s log.

failed to initialize chaindb
failed to initialize statedb

You need to make sure that you have write access to the path you want to create the data directory on the config file If the database server was rebooted while it was running, it is possible that the DB datafile has been crashed. In this case, a reinstallation is required.

check previously running processes

The DB initialize problem is most likely to occur when a new aergosvr is run without shutting down the existing aergosvr completely. In this case, you can check with the following log.

panic: Fail to Create New DB: Cannot acquire directory lock on "config data directory". 
Another process is using this Badger database.: resource temporarily unavailable`

In this case, terminate the existing aergosvr completely and restart it.

Miscellaneous DB errors

If an error occurs in DB, the following log is output.

Database Error: description...

In this case, it’s a good idea to first check to see if there is a problem with the filesystem .If there is no problem with the filesystem, the DB datafile can be seen as corrupt. In this case, reinstallation is required.

Disk performance problem

The BP node generates a block every 1 second. When a block is created, it is stored in the DB and Disk I / O occurs at this time.

If the disk I / O is too slow, the block created by the BP will not be added to the chain. This is because the block generated by the node is propagated to another node but the block of the corresponding height is already generated in the next BP. Therefore, the block arriving late comes to be discarded.

Check the disk I / O execution time through dd. This allows you to check for disk errors.

Network trouble

peer connection failure

If there is a problem with the network configuration, the peer connections may not be normal. you can check peer connections as follows.

  1. You need to make sure that the entire peer set in the config is connected. If there is an unconnected peer, check the network configuration with the peer.

    You can check the connection status of peers with the following command:

    aergocli -p $ServerPort getpeers
    [
            {
                    "Address": "127.0.0.1",
                    "PeerID": "16Uiu2HAkxUPj8zUnSkBzP8f4mw9WvJ4s5DeMVarzsqBuyrDy6dmD",
                    "Port": "11002",
                    "State": "RUNNING"
            }
    ]
    
network performance problem

aergo uses DPOS as a consensus algorithm. Blocks generated by one node must be transmitted to other nodes at a high speed. If the block transmission is too slow due to the network problem, the block created by the BP will not be included in the chain.

You can track the block creation time and the time passed to other nodes.

Oct 30 15:50:57.009 |INFO| block produced BP=16Uiu2HAmF5fpuk9ZWQbzHUuu9C1jwtqKnZdtkQYYDapA7AyoibWP caller=/Users/everjs/go/src/github.com/aergoio/aergo/consensus/impl/dpos/blockfactory.go:213 confirms=2 id=6mdjTYFEKXJ4UQ3xdKEu5RybnVWh3Hio6VG8a5SAXPbp lpb=1356 module=dpos no=1358 sroot=9hbmSFxzGj58YQuM2642zyo8jDAuu5qTWNG8JCMb78iZO`
Oct 30 15:50:57.012 |INFO| added block successfully. best=1358
Oct 30 15:50:57.013 |DEBUG| add block chainservice blockNo=1358 caller=/Users/ev
erjs/go/src/github.com/aergoio/aergo/chain/chainservice.go:252 hash=6mdjTYFEKXJ4UQ3xdKEu5RybnVWh3Hio6VG8a5SAXPbp module=chain

Server Process Hang

The aergo server was developed using the proto actor framework. Each module in the server receives a request using a message, performs an action on it, and returns a response.

At this time, if a specific module does not operate normally and hangs, it can be checked with the following command.

aergocli -p 10001 node
{
        "AccountsSvc": {
                "status": "started",
                "acc_processed_msg": 202,
                "msg_queue_len": 0,
                "msg_latency": "55.623µs",
                "error": "",
                "actor": null
        },

...

}

If a particular module hangs, the value of msg_queue_len field is high.

The details can be analyzed through the log by increasing the log level of the module.

Tracking status of Transaction

A transaction is added to a mempool and then executed when it is included in a block. Transactions are not included in block if validation fails due to nonce, balance, etc.. All transactions in the block will have a receipt. If the VM fails to execute contract, the error is recorded in the receipt. Therefore, the state of transaction may be as follows.

  • State of transaction
    • pending in mempool
    • included in block
      • sucess
      • fail if contract
check status of transaction

Use the following command to track the status of the transaction.

aergocli -p $PORT gettx $TXHASH

If the transaction stays in the pending state in the mempool, the following status is output.

aergocli -p $PORT gettx $TXHASH
Pending:  {
 "Hash": "BTY3zrsBkVHTqFbpqKtwbXwgfpGwRoiAmKRrdFKfZRna",
 "Body": {
  "Nonce": 101,
  "Account": "AmM5wCL3XhDngGAyYk6pbd2AYKSomVAKRqLBhnP8QsBMRRoA62fv",
  "Recipient": "AmNeY5fDqvGAfpYYLxhy7AhSsFzCSL96iYBApR2aHvRzMY5D34Ky",
  "Amount": 2560000,
  "Payload": "",
  "Limit": 0,
  "Price": 0,
  "Type": 0,
  "Sign": "381yXZRAPSGAFbGYndN5xU3s9RXHddFbCxyutNtUYvyT4DbDt7jWyia4oM6CLGtXYeQqtQBvqTaNU2gwpdrCm5FjwFP6fZCQ"
 }
}
check account

First, check the nonce and balance of the corresponding account. The status of the current account can be seen by the command below.

aergocli -p $PORT  getstate --address $ADDRESS

Ensure that the nonce and balance of transaction are consistent with the account status.

check status of mempool

There are too many transactions in mempool, which can take a long time to be included in the block. To see the current status of mempool, try the following command.

aergocli -p $PORT  node

In the cache_len field, you can see the total number of tx’s in mempool.

check receipt

If the transaction is contained in a block, you can use the receipt to check the execution result. Receipt can be seen using transaction hash

aergocli -p $PORT receipt get $TXHASH
{
 "contractAddress": "AmNeY5fDqvGAfpYYLxhy7AhSsFzCSL96iYBApR2aHvRzMY5D34Ky",
 "status": "CREATED",
 "ret": ""
}

Using Public Networks

These pages explain how you can connect to and sync with public Aergo networks.

Connecting to Well-known Nodes

Testnet

Use testnet-api.aergo.io and the default port 7845 to connect to a public GRPC server for the testnet.

docker run --rm aergo/tools aergocli -H testnet-api.aergo.io blockchain

Mainnet

Use mainnet-api.aergo.io and the default port 7845 to connect to a public GRPC server for the mainnet.

docker run --rm aergo/tools aergocli -H mainnet-api.aergo.io blockchain

Syncing

This setup assumes some basic knowledge about using Docker. Using Docker is the recommended way to run an Aergo node as it requires minimal configuration and enables you to use Docker features such as logging and restart policies.

Note

When you run the Docker image named aergo/node for the first time, Docker downloads the latest image automatically. To update the image to the latest version, run docker pull aergo/node. You can also specify a specific version by replacing aergo/node with, for example, aergo/node:1.0. Refer to Docker Hub to see a list of available tags.

Running

This is the main command to run a node syncing with the main Aergo network:

docker run -v $(pwd)/data:/aergo/data -p 7845:7845 -p 7846:7846 aergo/node

The -p argument maps ports from the aergo server inside the container to your host machine. 7846 is for the peer to peer protocol. 7845 is for the RPC API for connecting clients to the server; you can remove this port binding to disallow access to the API.

When running this command for the first time, it will create the default genesis block (block number 0). Afterwards it automatically starts synchronizing.

Note

If your machine is behind a NAT (such as a router), you need to setup manual forwarding of the port 7846 to allow other peers to sync with your node.

Testnet

To sync with the testnet instead, use the testnet flag:

docker run -v $(pwd)/data:/aergo/data -p 7845:7845 -p 7846:7846 aergo/node aergosvr --home /aergo --testnet

Configuration

The above commands use default configuration files suitable to connect to officially supported networks. If you want to override configuration parameters, you can supply a custom config file using a Docker volume, for example:

docker run -v $(pwd)/data:/aergo/data -v $(pwd)/config.toml:/aergo/config.toml -p 7846:7846 aergo/node aergosvr --home /aergo --config /aergo/config.toml

Please refer to Configuration for a detailed explanation of the available settings.

Note

To customize the log format, place an arglog.toml file in the container’s working directory: -v $(pwd)/arglog.toml:/aergo/arglog.toml.

Server key file

Every node is identified by a key and peer id. In the default configuration, a key is generated every time you launch the docker container. This may not be what you want. You can persist the generated key by adding a volume -v $(pwd)/auth:/aergo/auth. You can also supply the key manually by placing aergo-peer.key and aergo-peer.id files in that volume.

Refer to Configuration for details about server keys.

Tip

Instead of binding several volumes, you can use one combined volume, e.g. -v $(pwd)/aergo:/aergo.

Node discovery

Without any specific settings, the server connects to Polaris, registers itself, obtains addresses of other nodes, and automatically attempts to connect to those nodes. If the server is in a NAT environment or has multiple NICs, additional settings are required for external nodes to access the server. You have to setup the external address in the external network connection and set the internal address for binding address.

netprotocoladdr = "211.12.34.56" # external address to which other peer can connect
netprotocolport = 7846
npbindaddr = "192.168.0.2" # no config element or empty string means using same address as external
npbindport = 17846 # negative number means it is same as external port, in this case 7846

Creating Accounts

Accounts are identified by addresses that belong to private keys. To own an account, all you need is access to its private key. Always make sure that nobody except you gains access to your keys!

There are several methods to create accounts.

  1. If you are running your own node on your machine, you can create a local account:

    aergocli account new
    
    # Or using Docker:
    docker run --rm --net=host aergo/tools aergocli account new
    
  2. To create an account without a node (aka offline):

    aergocli account new --password your_password --path ./wallet
    
    # Or using Docker:
    docker run --rm -v $(pwd):/wallet aergo/tools aergocli account new --password your_password --path /wallet
    

    The output shows the address of your new account. It is saved in account/data.db in the given path.

    You can export this new account:

    aergocli account export --address your_address --password your_password --path ./wallet
    
    # Or using Docker:
    docker run --rm -v $(pwd):/wallet aergo/tools aergocli account export --address your_address --password your_password --path /wallet
    

    The output shows the encrypted private key belonging to your address which can be imported in other wallets.

Funding Accounts

Note

The method described here only applies to the testnet.

To create transactions on the public testnet, you need an account with a positive balance. After creating an account, this is how can fund your account for testing.

  1. Go to faucet.aergoscan.io, enter your account address, and click Request Tokens.
  2. Depending on demand, you need to wait for a moment. If the queue is full, try again a bit later.
  3. Check your account on Aergoscan. You should have received some AERGO tokens for your testing purposes.

These AERGO tokens are only valid on the testnet and cannot be sold or bought. They are only useful for developing and testing applications. Please only request as many tokens as you actually need.

If you have any trouble creating an account or receiving testnet tokens, please ask for help on our Discord channel.

Monitoring

Aergoscan is an explorer for the officially supported networks.

You can monitor blocks as they get produced and check transactions and accounts.

Snapshots

To quickly bootstrap a new full node, you can sart from a snapshot.

  1. Download the latest snapshot from snapshot.aergo.io.
  2. Extract the archive, e.g. tar zxvf 672571_20190423.tar.gz.
  3. Start the node, pointing it to the extracted data directory: docker run -v $(pwd)/data:/aergo/data -p 7845:7845 -p 7846:7846 aergo/node

Using Raft consensus

These pages explain how you can configure and manage nodes using raft consensus

Note

RAFT consensus can only be used for private networks.

Configuration

This page describes the configuration and logging options related to Raft consensus.

See also

See Config Reference for a detailed explanation of common config reference.

Config Reference

Module Property name Meaning
consensus.raft name raft node name. name should be unique in cluster
  newcluster initialize a new raft cluster if it doesn’t already exist
  skipempty skip producing block if there is no transactions in block
  heartbeattick heartbeat time(millisec) of raft node
  electiontickcount number of heartbeattick to wait before becomeing a candidate without heartbeat
  blockfactorytickms interval(millisec) to check if block factory should run new task
  blockintervalms block generation interval(millisec).It overrides BlockInterval of consensus
  usebackup use backup datafiles for initializing a new cluster or joining an existing cluster
  snapfrequency frequency which raft make snapshot with log
  recoverbp bp info for initializing a new cluster from backup data files
  slownodegap Max difference of chain height for determining if a node is a slow node

Logging options

To see the log related to Raft consensus, add a raft section to arglog.toml.

[raft]
level = "info"

Configuring a Network Using RAFT

This article describes the process for setting up a network of multiple block producers using RAFT Consensus.

Note

RAFT consensus can only be used for private networks.

A block chain network using RAFT consensus is called a RAFT Cluster. All the settings below assume a case where a blockchain network consisting of 3 nodes using RAFT consensus.

To create a blockchain network using RAFT consensus, you need to configure the genesis block and config file. Other settings are the same as the private network configuration using DPoS.

Common Configuration (per machines)

To configure aergo node as a block producer, it requires common configuration as descriped on Configuring a Network page.

However, additional configuration requires in genesis block and config file.

Write configuration files for RAFT

The initial nodes of a new RAFT cluster should be added to the genesis block. Every node in the cluster is a candidate to be a block producer. Only one of these nodes becomes a leader to create a block. The remaining nodes become followers who receive instructions from the leader. If a leader crashes, one of the follower nodes becomes the new leader.

Nodes that cannot be block producers can be used by adding them as fullnodes. These nodes communicate via the P2P protocol but are not included in the RAFT cluster.

genesis.json (same for all machines)

  • RAFT is not supported in the public network, so chain_id should be set to public and maninet should be set to false.
  • Add the nodes to be included in the RAFT cluster to the enterprise_bps entry. Add the name, address, and peerid of the desired nodes to the enterprise_bps. The address field uses the p2p peer format of the config file.
  • set consensus field to "raft".
  • set the bps entry to an empty list.
{
    "chain_id":{
        "magic": "[insert an identifier string for your network]",
        "public": false,
        "mainnet": false,
        "consensus": "raft"
    },
    "timestamp": 1548918000000000000,
    "balance": {
        "[insert address from genesis]": "470000000000000000000000000",
        "[insert address from bp01]": "10000000000000000000000000",
        "[insert address from bp02]": "10000000000000000000000000",
        "[insert address from bp03]": "10000000000000000000000000"        },
    "bps": [
    ],
    "enterprise_bps": [
      {
        "name": "[NICKNAME OF BP 01]",
        "address": "/ip4/[IP ADDRESS FROM BP 01]/tcp/7846",
        "peerid": "[PEER ID FROM BP 01]",
      },
      {
        "name": "[NICKNAME OF BP 02]",
        "address": "/ip4/[IP ADDRESS FROM BP 02]/tcp/7846",
        "peerid": "[PEER ID FROM BP 02]",

      },
      {
        "name": "[NICKNAME OF BP 03]",
        "address": "/ip4/[IP ADDRESS FROM BP 03]/tcp/7846",
        "peerid": "[PEER ID FROM BP 03]",
      }
    ]
}

config.toml (one per machine)

# aergo TOML Configration File (https://github.com/toml-lang/toml)
...  insert common configuration for block producer ...

[p2p]
npaddpeers = [
]
...
...
# configuration for block producer using RAFT
[consensus.raft]
newcluster=true
name="[NICKNAME OF THIS BP]"

Basically, the settings when using DPoS should be applied to the config in the same way. But you don’t need to set npaddpeers of [p2p]. Nodes use the address value of enterprise_bps to connect to others.

To use RAFT, [consensus.raft] section should be added. name is the current node’s nickname. The name must be included in the enterprise_bps of the genesis block. When you create a new RAFT cluster, you must set newcluster to true.

Other settings

To change block creation cycle

[consensus]
blockinterval=[insert value in seconds]

To change heartbeat cycle

[consensus.raft]
heartbeattick=[insert value in milliseconds ]

To skip creating empty block

[consensus.raft]
skipempty=true

Dynamic Membership Changement

Blockchain that uses the RAFT consensus can add or remove members dynamically through enterprise transactions. You do not have to restart running nodes or change the config file at this time. For a description of enterprise transactions, see transacion-types.

This article assumes the Aergo blockchain using raft consensus consisting of 3 nodes.

Abstaction

Note

Membership changes must be made after the completion of one. When adding a new node, do not add another node again until blockchain synchronization is over, since the new node becomes unavailable until the chain is synchronized and up to date. If more than half of the nodes are out of sync, the cluster stops.

Validation

When executing a membership change transaction, leader node checks if the current cluster status is changeable.

  • When adding a new node

    If any node is not properly synchronized in the whole network, it will fail. The node is either in a shutdown state or a state where synchronization is slowed down due to a failure.

  • When removing a node

    If the cluster can be stopped when the node is excluded, the delete request will fail. Deletion to a failed node always succeeds.

Prework

You need set up and unlock ENTERPRISE ADMIN ACCOUNT to execute commands with Enterprise Transaction. See the page transacion-types.

Add Member

Execute Add Node command

Send an enterprise transaction to one of the cluster nodes.

aergocli -p [RPC PORT] contract call --governance [ADMIN ACCOUNT] aergo.enterprise changeCluster [ { "command": "add", "name": "[NODE NAME]", "address": "[PEER ADDRESS]", "peerid":"[PEER ID]" } ]

example> aergocli -p 10001 contract call --governance AmQJ6HTxMzq5eios54xubENE2wAe4puF3GDuaFxBzXkWa4KpfnWr aergo.enterprise changeCluster [ { "command": "add", "name": "raft4", "address": "/ip4/127.0.0.1/tcp/11004", "peerid":"16Uiu2HAmQti7HLHC9rXqkeABtauv2YsCPG3Uo1WLqbXmbuxpbjmF" } ]
Check the command result

Query enterprise transaction results on one of the cluster nodes. The hash of enterprise transaction must be given as an argument.

aergocli -p [RPC PORT] enterprise tx "[ENTERPRISE TX HASH]" --timeout=[VALUE IN SECONDS]

The changed cluster status can be checked using getconsensusinfo RPC. "Total" represents the total number of nodes and "Bps" contains the block producer list.

aergocli -p 10001 getconsensusinfo
Write configuration for a new node (new node only)

In the config file of the node to add, set the peer addresses of the block producers to the [p2p] npaddpeers. If possible, register the peer address of all members currently registered in the raft cluster. However if necessary, only one connectable node can be set.

[p2p]
...
npaddpeers = [
"/ip4/[IP ADDRESS FROM BP 01]/tcp/7846/p2p/[PEER ID FROM BP 01]",
"/ip4/[IP ADDRESS FROM BP 02]/tcp/7846/p2p/[PEER ID FROM BP 02]",
"/ip4/[IP ADDRESS FROM BP 03]/tcp/7846/p2p/[PEER ID FROM BP 03]"
]
...

[consensus.raft]
newcluster=false
name="[NICKNAME OF NEW BP]"
Running

See the page Configuring a Network to start a new node.

Note

You should wait for the added node to finish synchronizing with the existing blockchain.

  • Check if the new node recognized the raft leader node

    If the leader node is recognized, ConsensusInfo.Status.Leader is set to one of the node names.

    aergocli -p 10004 blockchain
    > {"Hash":"3ivEw2o97WkpEvarBkVEYWCAQXhQ7BpHwmzs2L4WXUzJ","Height":7302,"ConsensusInfo":{"Type":"raft","Status":{"Leader":"raft1","Total":3,"Name":"raft4","RaftId":"dd44cf1a06727dc5","Status":null}},"ChainIdHash":"A9gpZUsFS9BVEfpUy6gbJ7YtGuHsYAmzamWkhDo54cak"}
    
  • Make sure the BlockChain Height of the new node matches the Leader

    aergocli -p [RPC PORT OF LEADER] blockchain
    aergocli -p [RPC PORT OF NEW NODE] blockchain
    

Remove Member

Get RAFT ID to remove

To delete a node, you should get RAFT ID of the node. RAFT ID is a value assigned after a node is added to RAFT. It is a value to idenity each node in RAFT Consensus.

You can get it in the result of blockchain RPC. In the example above, dd44cf1a06727dc5 is the Raft ID of the “raft4” node.

aergocli -p 10004 blockchain
> {"Hash":"...","Height":7302,"ConsensusInfo":{"Type":"raft","Status":{"Leader":"raft1","Total":4,"Name":"raft4","RaftId":"dd44cf1a06727dc5","Status":null}},"ChainIdHash":"..."}

Run enterprise transaction

aergocli -p [RPC PORT] contract call --governance [ADMIN ACCOUNT] aergo.enterprise changeCluster [ { "command": "remove", "id": "[RAFT ID]" } ]

example> aergocli -p 10001 contract call --governance AmQJ6HTxMzq5eios54xubENE2wAe4puF3GDuaFxBzXkWa4KpfnWr aergo.enterprise changeCluster '[ { "command": "remove", "id": "dd44cf1a06727dc5" } ]'

Check result of enterprise transaction

As with adding a node case, you should check “Total” and “Bps” in the results of the getconsensusinfo RPC.

aergocli -p 10001 getconsensusinfo

Wait shutdown removed node

If Enterprise Transaction is executed on the node to be deleted, the node terminates itself.

Add Member with Backup

After adding a new node, it takes a long time to synchronize the existing blockchain. To reduce this time, you can add a new node by using backup data files obtained from existing member nodes. There is no conflict because the new node resets all the cluster-related information from the given backup data files at the first startup.

Prepare backup datafiles

The bakcup datafiles can be obtained by shutting down an existing node and copying the data directory.

Note

Since the blockchain is already created in the data file, there is no need to create the genesis block.

Write Configuration file

When using backup data files, usebackup must be set to true. Set the backup data directory to datadir field.

datadir="[copied data directory]"

[p2p]
...
npaddpeers = [
"/ip4/[IP ADDRESS FROM BP 01]/tcp/7846/p2p/[PEER ID FROM BP 01]",
"/ip4/[IP ADDRESS FROM BP 02]/tcp/7846/p2p/[PEER ID FROM BP 02]",
"/ip4/[IP ADDRESS FROM BP 03]/tcp/7846/p2p/[PEER ID FROM BP 03]"
]
...

[consensus.raft]
newcluster=false
    usebackup=true
name="[NICKNAME OF NEW BP]"

The rest of the process is the same as adding members without using backup.

Recovery

If more than half of the cluster’s nodes become unrecoverable, the raft cluster can no longer delete or add any node. This is because more than half of nodes cannot agree to the change.

In this case, if you want to keep the data of BlockChain as it is, you can create a new cluster by using backup of existing node data. However, RAFT cluster information cannot be recycled.

This is called recovery.

There are some differences between recovery and general cluster creation.

  1. When creating a cluster using the recovery function, there must be one initial member node.
  2. Since genesis block is already created in blockchain, you should set initial node in config file instead of genesis block.
  3. If you want to configure N-node clusters, you need to add members dynamically from the second member.

The cluster related information is deleted in the backup files. The newly created cluster creates a block following blockchain that has already created.

Prepare backup datafiles

Copy backup datafiles from the old node to storage on the new node.

Write Configuration file(only initial node)

datadir="[copied data directory]"

[p2p]
...
npaddpeers = [
]
...

[consensus.raft]
newcluster=true
usebackup=true
name="[NICKNAME OF NEW BP]"
recoverbp={name="[NICKNAME OF NEW BP]",address="/ip4/[IP ADDRESS FROM BP 01]/tcp/7846",peerid="[PEER ID FROM NEW BP 01]"}
  • To create a new cluster, you need to set newcluster to true.
  • Set usebackup to true to use backup data files.
  • Set recoverbp to the member of the new cluster. At this time, member must only be one node.

Running a node

Start the node. After that, add nodes one by one using Dynamic membership change.

Smart Contracts

Aergo provides its own smart contract platform for implementing various business logic on the blockchain.

Currently, you can create smart contracts using the Lua programming language.

Lua

To create smart contracts for Aergo, you can use the Lua scripting language.

Lua is a powerful, efficient, lightweight, embeddable scripting language. It has a simple procedural syntax with a powerful data description structure. Lua supports a variety of programming methods: procedural programming, object-oriented programming, functional programming.

We use LuaJIT 2.1.0 as the VM. LuaJIT is a Just-In-Time Compiler (JIT) for the Lua programming language.

You can learn the Lua programming language through the following documents:

Table of contents

Hello World

This is the most basic lua smart contract to store and retrieve states in aergo. You can save a name on the blockchain with the contract call function. And you can print ‘hello …’ with the query function.

-- Define global variables.
state.var {
  Name = state.value(),
  My_map = state.map()

}

-- Initialize a name in this contract.
function constructor()
  -- a constructor is called at a deployment, only one times
  -- set initial name
  Name:set("world")
  My_map["key"] = "value"
end

-- Update a name.
-- @call
-- @param name          string: new name.
function set_name(name)
  Name:set(name)
end

-- Say hello.
-- @query
-- @return              string: 'hello ' + name
function hello()
  return "hello " .. Name:get()
end

-- register functions to expose
abi.register(set_name, hello)
Tutorial

This is explained based on using cli. Variables used in this example are

  • Account to deploy and execute a contract: AmPbWrQbtQrCaJqLWdMtfk2KiN83m2HFpBbQQSTxqqchVv58o82i
Check Account and Balance

First, you need an account with enough balances to deploy and execute smart contracts. (If you don’t) Import or Unlock Account to aergo server.

Compile Contract

Copy above code and save it to a file (e.g. helloword.lua). And Compile using the aergoluac compiler

./aergoluac --payload helloworld.lua
37mGLDoCPNDQw7HbCG5WPfcM3E3cLhqhgE2V2UJKwQp9QZ5nJhT14nkCdGFcmN91fewB2ZuMZ5NWJUPyD4G4G2beaTeE1cigLzyNdGuuU4Y7cY2A6MUMq5weoAGGJdyf6PUfzgQ7k1cwjjDRe7P8bN5tNR8xxiibYk1hoeV2fuG4ZGVUwosutqFYePonLAtvK57N2MphJWVkTVxkySkXBnKywCiKB2pqv93VVQbBepYrUwURAeaj5aGhuFa8sxbSjuZfrvdy3i7dAEesf1jPHyeoN6CHWEB3teQJHUUh5K89p8vZ7nXKYPSa7MbzEg3YCUx8uLYmkJPjqA5YT1dxcKWCmHV4M2nYxmv3h9v3viPFkkFuMdpJboCTV2iqkMr3robxT6okSJtDdVUk2PprZKuiipS6tbKmDmxuicJqFvtP653qdWpu4tvWQDBb5k3UJcMTcEDdrjqqtNcE8dujFxr4TWfDu9Nwb4FedLrb5z7CoRWvXi5eZBkujJdDBm5MowamWLy9Pu6UmjAmBHfkDpQiagocrFzZrDPvNbaon8r5Rph8gFHAzwaUdM3dpt3dghePsiH1jbz8j93aMhMxgE6Lgap
Deploy Contract

With the payload generated above, Deploy contract

./aergocli contract deploy AmPbWrQbtQrCaJqLWdMtfk2KiN83m2HFpBbQQSTxqqchVv58o82i --payload 37mGLDoCPNDQw7HbCG5WPfcM3E3cLhqhgE2V2UJK
wQp9QZ5nJhT14nkCdGFcmN91fewB2ZuMZ5NWJUPyD4G4G2beaTeE1cigLzyNdGuuU4Y7cY2A6MUMq5weoAGGJdyf6PUfzgQ7k1cwjjDRe7P8bN5tNR8xxiibYk1hoeV2fuG4ZGVUwosutqFYePonLAtvK57N2MphJWVkTVxkySkXBnKywCiKB2pqv93VVQbBepYrUwURAeaj5aGhuFa8sxbSjuZfrvdy3i7dAEesf1jPHyeoN6CHWEB3teQJHUUh5K89p8vZ7nXKYPSa7MbzEg3YCUx8uLYmkJPjqA5YT1dxcKWCmHV4M2nYxmv3h9v3viPFkkFuMdpJboCTV2iqkMr3robxT6okSJtDdVUk2PprZKuiipS6tbKmDmxuicJqFvtP653qdWpu4tvWQDBb5k3UJcMTcEDdrjqqtNcE8dujFxr4TWfDu9Nwb4FedLrb5z7CoRWvXi5eZBkujJdDBm5MowamWLy9Pu6UmjAmBHfkDpQiagocrFzZrDPvNbaon8r5Rph8gFHAzwaUdM3dpt3dghePsiH1jbz8j93aMhMxgE6Lgap
1 : FPqA3kNQHoVXqKJv8JNpUSsh8F8id87yvRr5UzQFoCcH TX_OK
Get receipt of contract

Look up the actual contract address with the transaction ID above.

./aergocli receipt get FPqA3kNQHoVXqKJv8JNpUSsh8F8id87yvRr5UzQFoCcH
{
 "BlokNo": 317,
 "BlockHash": "48zceVwBZt5dpzuEFMtJB9icPXUu7YG1Xkxvw5N92yFW",
 "contractAddress": "AmfzX3SHXVTBU9NSEWXaLxxjN11KsUpm1Gb3YjF7kmsHrgmL41WU",
 "status": "CREATED",
 "ret": {},
 "txHash": "AWeaoCTpohuQpBMTFaW3qFpZqWwuTehXA8ZkAX59UjMV",
 "txIndex": 0,
 "from": "AmPbWrQbtQrCaJqLWdMtfk2KiN83m2HFpBbQQSTxqqchVv58o82i",
 "to": "",
 "usedFee": 10,
 "events": []
}

If the status is not ‘CREATED’, it may not be included in the block yet, or there may be an error. Wait a while until the transaction is included in the block. Or check the server’s error log.

Get ABI of contract

Look up ABI of contract with the contract address above.

./aergocli contract abi AmfzX3SHXVTBU9NSEWXaLxxjN11KsUpm1Gb3YjF7kmsHrgmL41WU
{
 "version": "0.2",
 "language": "lua",
 "functions": [
  {
   "name": "hello"
  },
  {
   "name": "set_name",
   "arguments": [
    {
     "name": "name"
    }
   ]
  },
  {
   "name": "constructor"
  }
 ],
 "state_variables": [
  {
   "name": "Name",
   "type": "value"
  },
  {
   "name": "My_map",
   "type": "map"
  }
 ]
}
Query Initial State

You can query the generated contract in the following way.

./aergocli contract query AmfzX3SHXVTBU9NSEWXaLxxjN11KsUpm1Gb3YjF7kmsHrgmL41WU hello
value:"\"hello world\""

You can see that the name ‘world’ assigned by the constructor is output.

Call Contract

You can change the name recorded in the block chain as follows:

./aergocli contract call AmPbWrQbtQrCaJqLWdMtfk2KiN83m2HFpBbQQSTxqqchVv58o82i AmfzX3SHXVTBU9NSEWXaLxxjN11KsUpm1Gb3YjF7kmsHrgmL41WU
 set_name '["aergo"]'
1 : 8mcuEFNxNCF6h4Q3FJk3mGN356R1AmWgGptAgJHNfaKs TX_OK
Query Changed State

If you look at the results again, it has changed.

./aergocli contract query AmfzX3SHXVTBU9NSEWXaLxxjN11KsUpm1Gb3YjF7kmsHrgmL41WU hello
value:"\"hello aergo\""
Query contract variable with merkle proof

Value

./aergocli contract statequery AmfzX3SHXVTBU9NSEWXaLxxjN11KsUpm1Gb3YjF7kmsHrgmL41WU Name --compressed

Map

./aergocli contract statequery AmfzX3SHXVTBU9NSEWXaLxxjN11KsUpm1Gb3YjF7kmsHrgmL41WU My_map key --compressed

Array

./aergocli contract statequery AmfzX3SHXVTBU9NSEWXaLxxjN11KsUpm1Gb3YjF7kmsHrgmL41WU array_name array_index --compressed

By default, the returned state is the one at the latest block, but you may specify any past block’s state root.

./aergocli contract statequery AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ var_name --root "9NBSjkcNTdE5ciBxfb52RmsVW7vgX5voRsv6KcosiNjE"

Programming Guide

Lua provides useful functions and libraries. So you can easily create smart contracts using these functions.

Please refer to the Lua Reference Manual for detailed syntax, explanation, basic built-in functions and libraries.

Restrictions

Because Lua smart contract is performed in the aergo, OS related functions including Input/Output are not provided for stability and security.

Here is a list of the base functions that are not available.

print, dofile, loadfile, module, and require

You can replace print with system.print.

And you can use import instead of require. import is not a Lua syntax.

Use SHIP to build and deploy smart contracts using multiple files.

Here is a list of the default libraries that are not available.

coroutine, io, os, debug, and jit

The string, math, bit, and table packages are available. However, you can not use the random, randomseed functions in the math package.

There are no restrictions on literals, expressions, and statements.

During the early period, the execution of a contract has some limitations.

  • The maximum number of instruction can be executed per contract is 5000000
  • The maximum size of the memory can be used per contract is 10 MB
  • The maximum size of the state DB that can be modified per contract is 200 KB

If the maximum is exceeded, the execution of a contract will fail.

Libraries

We provide libraries for smart contract as follows:

  • Blockchain API
    • system module
    • contract module
    • state module
    • db module
    • abi module
  • Utils
    • json module
    • crypto module
    • bignum module

You can find detailed descriptions for libraries on this page

Smart Contract
Layout
import "./path/to/library"

state.var {
  Value = state.value(),
  Map = state.map(),
  Array = state.array(10)
}

function constructor(init_value)
  Value:set(init_value)
end

function contract1(name, id)
  Map["name"] = name
  Map["ID"] = id
end

function contract2()
  local sum = 0
  for i, v in state.array_pairs(Array) do
    if v ~= nil then
      sum = sum + v
    end
  end
  return sum
end

abi.register(contract1, contract2) -- , contract3, ...
import

This replaces the require function.

It allows you to divide and develop one smart contract into multiple modules(files).

This is not a Lua feature. You should use SHIP to build and deploy smart contracts using multiple files.

state variable

The state.var function defines global state variables.

Three types of state variables can be defined.

value

This type store any Lua values.

You can define a state value with the syntax var_name = state.value(). It has get and set methods for reading and writing data.

Value:set("data")
local data = Value:get()
map

The type map implements associative arrays.

It can be indexed only with string, but the value of a map element can be of any type.

You can define a state map with the syntax var_name = state.map(). The index operator is used for reading and inserting elements.

You can delete a element of map by delete method with the syntax var_name:delete(key)

state.var {
  Map_var = state.map()
}

function contract_func()
  Map_var["name"] = "kslee"
  Map_var["age"] = 38
  -- ...
  local age = Map_var["age"]
end

function delete_elem(key)
  Map_var:delete(key)
end

state map support multi dimension(syntax var_name = state.map(dimension)) The multi index operator is used for reading and inserting elements.

state.var {
  Map_var = state.map(2)
}

function contract_func()
  Map_var["kslee"]["age"] = 38
  Map_var["kslee"]["birth"] = "1999/09/09"
  -- ...
  local kslee = Map_var["kslee"]
  local age = kslee["age"]
  local birth = kslee["birth"]
  
  kslee["birth"] = "1970/10/9"
end
Restrictions
  • max dimension : 5
  • not support setting intermediate dimension element

next is setting intermediate dimension element example

state.var {
  Map_var = state.map(2)
  person_var = state.map()
}

function contract_func()
  person_var["age"] = 38
  person_var["birth"] = "1999/09/09"
  Map_var["kslee"] = person_var
 -- ...
end
array

The type array is a fixed-length ordinary array.

It can be indexed only with integer, but the value of an array element can be of any type. The index starts at 1.

You can define a state array with the syntax var_name = state.array(size). The index operator is used for reading and inserting elements.

state.var {
  Arr_var = state.array(3)
}

function contract()
  Arr_var[1] = 1
  Arr_var[2] = 2
  Arr_var[3] = 3

  local sum1 = 0
  for i, v in Arr_var:ipairs() do
    if v ~= nil then
      sum1 = sum1 + v
    end
  end

  local sum2 = 0
  for i = 1, #Arr_var do
    if Arr_var[i] ~= nil then
      sum2 = sum2 + Arr_var[i]
    end
  end

  if sum1 == sum2 then
  -- ...
  end

end

state array support multi dimension (syntax var_name = state.array(1st_ncount, 2nd_ncount,....)) The multi index operator is used for reading and inserting elements.

state.var {
  -- declare 2 dimensional array 
  Arr_var = state.array(2, 3)
}

function contract_func()
  Arr_var[1][1] = 1
  Arr_var[1][2] = 2
  Arr_var[1][3] = 3
  
  -- ...
  local Arr2 = Arr_var[2]
  Arr2[1] = 4
  Arr2[2] = 5
  Arr2[3] = 6
  
  local sum1 = 0
  for i, v in Arr_var:ipairs() do
   for j, k in v:ipairs() do
    if k ~= nil then
      sum1 = sum1 + k
    end
   end
  end
  
  local sum2 = 0
  for i = 1, #Arr_var do
   for j = 1, #Arr_var[i] do
    if Arr_var[i][j] ~= nil then
      sum2 = sum2 + Arr_var[i][j]
    end
   end
  end

  if sum1 == sum2 then
  -- ...
  end
end
Restrictions
  • max dimension : 5
  • not support setting intermediate dimension element

next is setting intermediate dimension element example

state.var {
  Marr_var = state.map(2,3)
  Arr_var = state.map(3)
}

function contract_func()
  Arr_var[1] = 1
  Arr_var[2] = 2
  Arr_var[3] = 3

  Marr_var[1] = Arr_var
 -- ...
end

Note: The state variables are just syntax sugar that replace system.getItem(), system.setItem() functions.

The fields of state variables that are directly modified cannot update the state db.

See InvalidUpdateAge() and ValidUpdateAge() functions in the example.

state.var{
   Person = state.value()
}

function constructor()
  Person:set({ name = "kslee", age = 38, address = "blahblah..." })
end

function InvalidUpdateAge(age)
  Person:get().age = age
end

function ValidUpdateAge(age)
  local p = Person:get()
  p.age = age
  Person:set(p)
end

function GetPerson()
  return Person:get()
end

abi.register(InvalidUpdateAge, ValidUpdateAge, GetPerson)
constructor

The constructor is executed only once during deployment. It can has arguments. It does not need to register into the abi.register() function because it is handled automatically.

functions

Write business logic and help functions.

export contract function(s)

You should add global functions that must be called from contract call/query commands to the abi.register().

special functions
default

default is a special function. It is called when the function name can not be found or when the transaction has no a call information. It does not need to export through abi.register(). default is the name of this function. default is used internally by the VM. You should not use default for any other purpose.

You can define a default function as follows:

...
function default()
  ...
end
...

You can call this default function. There is no call information for the contract function.

./aergocli contract call <sender> <contract>
payable

The payable is a property of a function. Only payable function can receives Aergo(s) sent from a sender. We can make a payable function using abi.payable(). payable functions are automatically exported. Therefore, you do not have to register using the abi.register function. constructor and default are not payable functions by default. They can be payable functions using abi.payable().

You can call the ReceiveAergo with aergo, But you can not call the NotReceiveAergo:

...
function ReceiveAergo()
  ...
end

function NotReceiveAergo()
  ...
end

abi.register(NotReceiveAergo)
abi.payable(RecieveAergo)
./aergocli contract call --amount=10 <sender> <contract> ReceiveAergo     # success
./aergocli contract call --amount=10 <sender> <contract> NotReceiveAergo  # fail
view

The view is a property of a function. Functions can be declared view in which case they promise not to modify the state(send aergo, emit event, set state, etc…). We can make a view function using abi.register_view(). register_view functions are automatically exported. Therefore, you do not have to register using the abi.register.

you can not call the sendAergo:

...
function sendAergo()
  contract.send(addr, "1 aergo")
end

abi.register_view(sendAergo)
./aergocli contract call <sender> <contract> sendAergo  # fail
SQL

Aergo smart contract has db library that supports SQL features.

Note: The db package is only available on private networks(SQL TestNet).

The below code is a example of creating table and insert a row using db.exec()

-- creates a customer table
function createTable()
  db.exec([[create table if not exists customer(
        id text,
        passwd text,
        name text,
        birth text,
        mobile text
    )]])
end

-- insert a row to the customer table
function insert(id, passwd, name, birth, mobile)
  db.exec("insert into customer values (?, ?, ?, ?, ?)",
          id, passwd, name, birth, mobile)
end

The db.query() function returns a result set. You can fetch rows from the result set.

function query(name)
  local rt = {}
  local rs = db.query("select * from customer where name like '%' || ? || '%'", name)
  while rs:next() do 
    local col1, col2, col3, col4, col5 = rs:get()
    local item = {
        id = col1,
        passwd = col2,
        name = col3,
        birth = col4,
        mobile = col5
    }
    table.insert(rt, item)
  end
  return rt
end

You can also use prepared statements:

function insert(id , passwd, name, birth, mobile)
  stmt = db.prepare("insert into customer values (?, ?, ?, ?, ?)")
  stmt.exec(id, passwd, name, birth, mobile)
end

function insert_contacts(contacts)
  local stmt = db.prepare("insert into contacts (name, email) values (?, ?)")
  for _,contact in ipairs(contacts) do
    stmt.exec(contact.name, contact.email)
  end
end

function query_names(ids)
  local names = {}
  local stmt = db.query("select name from customer where id=?")
  for _,id in ipairs(ids) do
    local rs = stmt:query(id)
    if rs:next() then
      table.insert(names, rs:get())
    else
      table.insert(names, "")
    end
  end
  return names
end
Security

:warning: Do not concatenate values when building SQL commands!

This would make your smart contract vulnerable to SQL injection attacks.

These are bad examples that should NOT be used: :no_entry_sign:

  db.exec("insert into customer values ('" .. id .. "', '"
      .. passwd .. "', '"
      .. name .. "', '"
      .. birth .. "', '"
      .. mobile .. "')")

  local rs = db.query("select * from customer where id like '%'" .. id .. "'%'")
Restrictions

Litetree is used as the SQL processing engine for the aergo smart contract. Litetree is implemented based on SQLite.

Detailed SQL usage can be found at https://sqlite.org/lang.html and https://sqlite.org/lang_corefunc.html

However, we do not provide full SQL functionality. There are some limitations due to stability and security.

Data types

Allow only SQL datatypes corresponding to Lua strings and numbers(int, float).

  • text
  • integer
  • real
  • null
  • date, datetime

SQL statements

You can execute the following SQL statements. However, DDL and DML can not be run on smart contract queries.

  • DDL
    • TABLE: ALTER, CREATE, DROP
    • VIEW: CREATE, DROP
    • INDEX: CREATE, DROP
  • DML
    • INSERT, UPDATE, DELETE, REPLACE
  • Query
    • SELECT

functions

Here is a list of functions that are not available:

  • load_XXX functions
  • random function
  • sqlite_XXX functions
  • data and time related functions can be used, except now timestring and localtime modifier.

A list of other functions and descriptions is available via the links below.

  • basic : https://www.sqlite.org/lang_corefunc.html
  • data and time : https://www.sqlite.org/lang_datefunc.html
  • aggregation : https://www.sqlite.org/lang_aggfunc.html

contraints

You can use the following contraints:

  • NOT NULL
  • DEFAULT
  • UNIQUE
  • PRIMARY KEY (FOREIGN KEY)
  • CHECK
Tools
aergoluac

aergoluac is a compiler for Lua smart contracts.

aergocli

aergocli is a command line tool that interfaces with the GRPC exposed by aergosvr.

It provides smart contract-related commands as follows:

  • contract deploy/call/query/abi/statequery
  • receipt get
  • event list/stream
  • Reference
brick

Toy for Contract Developers. You can use it to test smart contracts.

https://github.com/aergoio/aergo/tree/master/cmd/brick

Style conventions

It is good adopt a consistent coding style for readability. We recommend the Lua style guide.

Reference

Overview

aergo smart contract uses Lua, a lightweight scripting language, as a smart contract language. The following is an example of a simple coin stack smart contract written in Lua that stores key-value values ​​in a block-chain state store and reads the values.

-- Storing key-values ​​in the state store
function set(key, value)
    system.setItem(key, value);
end

-- Returns the value corresponding to the key in the state store
function get(key)
    return system.getItem(key);
end
​
-- Output the hash value of the previous block. The output is printed on the server log.
function printPrevBlock()
    system.print(system.getPrevBlockHash());
end

-- Functions to be called for contract declare as abi
abi.register(set, get, printBlock)

To read and write data on a block chain within a contract, you must use a system package. In the above example, smart contract provides the function to access the key-value repository through the setItem and getItem functions of the system package and store the data permanently. In addition, a simple debug message can be output to the log file of the node via the print function.

system package

This packages provides blockchain information and store/get state

getSender()

This function returns caller address of current contract

getBlockheight()

This function returns the block number that contains the current contract transaction.

getTxhash()

This function returns the id of the current contract transaction.

getTimestamp()

This function returns the creation start time of the block that contains current contract transaction.

getContractID()

This function returns the current contract address.

setItem(key, value)

This function sets the value corresponding to key to the storage belonging to current contract

  • restriction
    • key type string only (number type is implicitly converted to string)
    • value type available : number, string, table
getItem(key)

This function returns the value corresponding to key in storage belonging to current contract

  • If there is no value corresponding to key, it returns nil.
getAmount()

This function returns number of AER sent with contract call. Return type is string.

getCreator()

This function returns creator address of current contract

getOrigin()

This function returns sender address of current transaction

getPrevBlockHash()

This function returns the hash of the previous block

isContract(address)

This function return if address is contract then true else false. when address is invalid then raise error

contract package

This packages provides contract operation

send(address, amount)

This function transfers the coins in this contract by address and amount(in AER units). Amount form can be string, number, bignum.

contract.send("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", 1)
contract.send("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "1 aergo 10 gaer")
contract.send("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", bignum.number("999999999999999"))
deploy(code, args…)

The deploy function creates a contract account using code and args, and returns the corresponding address and the return of the constructor function

  • If you use an existing address instead of code, deploy it with the code of the address.
  • In addition, can call the value function to send a coin. Value function can get string, number, bignum argument like send function.
    src = [[
        function hello(say)
            return "Hello " .. say .. system.getItem("made")
        end
        function constructor(check)
            system.setItem("made", check)
        end
        abi.register(hello)
        abi.payable(constructor)
    ]]
    addr = contract.deploy.value("1 aergo")(src, system.getContractID())
call(address, function_name, args…)

The call function returns the result of the function of the contract being executed in the state of the corresponding address.

  • In addition, can call the value function to send a coin. Value function can get string, number, bignum argument like send function.
contract.call("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "inc", 1)
contract.call.value(10)("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "inc", 2)
Restrictions

Before the fee system for smart contract is applied to mainnet, there are the following restrictions

  • limit the call depth of call or delegatecall in one transaction to 5
delegatecall(address, function_name, args…)

The delegatecall function returns the result of the function of the calling process, executed in the state in the current address.

contract.delegatecall("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "inc", 1)
Restrictions

Before the fee system for smart contract is applied to mainnet, there are the following restrictions

  • limit the call depth of call or delegatecall in one transaction to 5
pcall(fn, args…)

It is an error handling function that works just like pcall in lua. The difference is that when the error occurs, the modified state,table or balance of the function executed rollback

success = contract.pcall(contract.send, "Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "1 AERGO")
if success == false then
    return 0
end
return 1
balance(address)

This function return balance of the address(argument) in AER. return type is string. If address is nil then return balance of current address.

contract.balance() --get balance of current contract address 
contract.balance("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod")
event(eventName, args…)

This function causes eventName and args to remain in the contract result receipt. The user can search for event and receive notification the event with rpc when the receipt is added to the blockchain.

contract.event("send", 1, "toaddress") 
Restrictions

Before the fee system for smart contract is applied to mainnet, there are the following restrictions

  • limit length of event name to 64
  • limit size of event argument to 4k
  • limit the number of events in one transaction to 50
Search event and receive notification with aergocli

you can search for events with event name “send” in the contract address(AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ)

./aergocli event list --address AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ --event send

you can search for events with event argument 0 is 1 and argument 1 is “toaddress” in the contract address(AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ)

./aergocli event list --address AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ --argfilter '{"0":1, "1":"toaddress"}'

you can get notified for events with event name “send” for contract(AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ)

./aergocli event stream --address AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ --event send
stake(amount), unstake(amount), vote([bps,…])

you can do governance(stake, unstake, vote) in contract with contract address

contract.stake("1 aergo") 
contract.vote(["<bp1 address>", "<bp2 address>"....)
contract.unstake("1 aergo")
Built-in Functions

Lua provides the language itself as a useful function and basic package. It provides useful functions such as string management functions, so you can easily create smart contracts using these functions. Please refer to the Lua Reference Manual for detailed syntax, explanation, basic built-in functions and packages.

Since Lua Smart Contract is performed in Blockchain, OS related functions including input / output are not provided for stability and security.

Here is a list of the main functions that are not available.

print, loadstring, dofile, loadfile and module

Here is a list of the default packages that are not available.

coroutine, io, os and debug

The string, math, and table packages are available. However, you can not use the random, randomseed functions in the math package.

DB package

If the smart contract is handling simple types of data, it would not be difficult to implement using only the basic APIs (getItem (), setItem ()). However, complex data structures, data association, scope queries, filtering, sorting, and other features require the complexity and size of the data logic so developers can not focus on critical business logic. To solve this problem, Aergo supports SQL. This section details the types and usage of SQL APIs available in smart contracts

Note: The db package is only available on private networks(SQL TestNet).
exec(sql)

This function perform DDL or DML statements

query(sql)

This function perform SELECT statements and return result set object

prepare(sql)

This function create prepared statement and return statement object

-- create customer table 
function createTable()
  db.exec([[create table if not exists customer(
        id text,
        passwd text,
        name text,
        birth text,
        mobile text
    )]])
end

function insert(id, passwd, name, birth, mobile)
  db.exec("insert into customer values (?, ?, ?, ?, ?)",
      id, passwd, name, birth, mobile)
end
functions of result set object

Object functions must be called with the: operator

get

This function return result row

function query(id)
  local rt = {}
  local rs = db.query("select * from customer where id like '%' || ? || '%'", id)
  while rs:next() do 
    local col1, col2, col3, col4, col5 = rs:get()
    local item = {
        id = col1,
        passwd = col2,
        name = col3,
        birth = col4,
        mobile = col5
    }
    table.insert(rt, item)
  end
  return rt
end
functions of prepared statement object

equivalent to the prepareStatement object in JDBC. You can use the parameters in SELECT or DML to view, add, modify, or delete information.

query(bind1 , bind2, ….)

This function execute SELECT statement by specifying argument value corresponding to bind parameter and return result set object

exec(bind1, bind2, ….)

This function execute DML statement by specifying argument value corresponding to bind parameter

SQL Restrictions

Smart Contract’s SQL processing engine is built on SQLite. Therefore, detailed SQL usage grammar can be found at https://sqlite.org/lang.html and https://sqlite.org/lang_corefunc.html. However, because of the stability and security of the Aergo, not all SQL is allowed.

types

Allow only SQL datatypes corresponding to Lua strings and numbers (int, float).

  • text
  • integer
  • real
  • null
  • date, datetime
SQL statement

The allowed SQL statements are listed below. However, DDL and DML are only allowed in smart contract transactions.

  • DDL
    • TABLE: ALTER, CREATE, DROP
    • VIEW: CREATE, DROP
    • INDEX: CREATE, DROP
  • DML
    • INSERT, UPDATE, DELETE, REPLACE
  • Query
    • SELECT
Function

The following is an unavailable list

  • Data and time related functions can be used except ‘now’ timestring and ‘localtime’ modifier
  • load_XXX function
  • random function
  • sqlite_XXX function

For a list of other functions and descriptions, please refer to the links below.

Constraint

The following constraints can be used.

  • NOT NULL
  • DEFAULT
  • UNIQUE
  • PRIMARY KEY(FOREIGN KEY)
  • CHECK
function init_database()
    db.exec("drop table if exists customer")
    db.exec("create table if not exists customer (cid integer PRIMARY KEY ASC AUTOINCREMENT , passwd text , cname text, birthdate date, rgdate date)")
    db.exec("insert into customer (cid, passwd, cname, birthdate, rgdate) values (100 ,'passwd1','홍길동', date('1988-01-03'),date('2018-05-30'))")
    db.exec("insert into customer (passwd, cname, birthdate, rgdate) values ('passwd2','김철수', date('1978-11-03'),date('2018-05-30'))")
    db.exec("insert into customer (passwd, cname, birthdate, rgdate) values ('passwd3','이영미', date('1938-04-23'),date('2018-05-30'))")

    db.exec("drop table if exists product")
    db.exec("create table if not exists product (pid integer PRIMARY KEY ASC AUTOINCREMENT, pname text, price real, rgdate date)")
    db.exec("insert into product (pid, pname, price, rgdate) values (1000 ,'사과',1000, date('2018-05-30'))")
    db.exec("insert into product (pname, price, rgdate) values ('수박',10000, date('2018-05-30'))")
    db.exec("insert into product (pname, price, rgdate) values ('포도',3500, date('2018-05-30'))")

    db.exec("drop table if exists order_hist")
    db.exec("create table order_hist (oid integer PRIMARY KEY ASC AUTOINCREMENT, cid integer, pid integer, p_cnt integer, total_price real, rgtime datetime, FOREIGN KEY(cid) REFERENCES customer(cid), FOREIGN KEY(pid) REFERENCES product(pid) )")
    db.exec("insert into order_hist(oid, cid, pid,  p_cnt, total_price,rgtime) values(10000,100,1000,3,3000, datetime('2018-05-30 16:00:00'))")
    db.exec("insert into order_hist(cid, pid, p_cnt, total_price, rgtime) values(100,1000,3,3000, datetime('2018-05-30 17:00:00'))")
    db.exec("insert into order_hist(cid, pid, p_cnt, total_price, rgtime) values(100,1000,3,3000, datetime('2018-05-30 18:00:00'))")
end
json package

Json package is provided for user convenience in input and output. This package allows automatic conversion between Json format strings and Lua Table structures.

encode(arg)

This function returns a JSON-formatted string with the given lua value.

decode(string)

This function converts a string in JSON format to the corresponding Lua structure and returns it

crypto package
sha256(arg)

This function compute the SHA-256 hash of the argument.

ecverify(message, signature, address)

This function verify the address associated with the public key from elliptic curve signature.

function validate_sig(data, signature, address)
    msg = crypto.sha256(data)
    return crypto.ecverify(msg, signature, address)
end
bignum package

Since the lua number type has a limit on the range that can be represented by an integer (less than 2 ^ 53), the bignum module is used to provide an exact operation for larger numbers.

  • Notice
    • == Operations on bignum and other types always return false.
    • Bignum does not allow a decimal point.
    • Bignum value range : -(2^256 - 1) ~ (2^256 -1)
number(x)

This function make bignum object with argument x(string or number)

isneg(x)

Check bignum x if negative than return true else false

iszero(x)

Check bignum x if zero than return true else false

tonumber(x)

Convert bignum x to lua number

tostring(x) (bignum.tostring(x) same as tostring(x))

Convert bignum x to lua string

neg(x) (same as -x)

Negate bignum x and return as bignum

sqrt(x)

Returns the square root of a positive number as bignum. not permitted negative value to x

compare(x, y)

Compare two big numbers. Return value is 0 if equal, -1 if x is less than y and +1 if x is greater than y.

add(x, y) (same as x + y)

Add two big numbers and return bignum

sub(x, y) (same as x - y)

Subtract two big numbers and return bignum

mul(x, y) (same as x * y)

Multiply two big numbers and return bignum

mod(x, y) (same as x % y)

Returns the bignum remainder after bignum x is divided by bignum y

div(x, y) (same as x / y)

Divide two big numbers and return bignum

pow(x, y) (same as x ^ y)

Power of two big numbers and return bignum. not permitted negative value to y

divmod(x, y)

Returns a pair of big numbers consisting of their quotient and remainder

powmod(x, y, m)

Return the bignum remainder after pow(bignum x,bignum y) is divided by bignum m. not permitted negative value to y

isbignum(x)

Return true if x is bignum else false

tobyte(x)

Return byte string of bignum x. not permitted negative value to x

frombyte(x)

Return bignum from byte string x

function factorial(n,f)
 for i=2,n do f=f*i end
 return f
end
for i=1,30 do
  local b=factorial(i,bignum.number(1))
  return bignum.mod(b, 10)
end

Aergo SCL

Aergo Smart Contract Language (Aergo SCL, we pronounce it “askel”) is a language dedicated to smart contact for Aergo, designed to make it easier for developers to develop smart contracts. Although the specification is less than traditional languages, it aims to be faster and more powerful. Aergo SCL has the following characteristics.

  • Strongly typed language
  • Object-oriented language (except for inheritance and abstraction)
  • Support SQL extension for database access
  • Support extension for blockchain access
  • Compiled with WebAssembly

Aergo SCL is currently not supported on the testnet but under active development.

Technical Specifications

Addresses

Client-side

Account and contract addresses are Base58-check encoded strings that look like this:

AmQA7dHJFiA4mXXxTV5sAniLpxMrankdW4Cow3ykj1UM5G14QKL5

The prefix used for encoding Aergo addresses in base58-check is 0x42.

Internal

Internally (in the server and over the wire, i.e. in GRPC requests) addresses are byte arrays with a length of 33. They represent the compressed public key of an account.

In the case of smart contracts, the address is generated from a hash of the creator’s account and the creating transaction’s nonce, prefixed with the byte 0x0C to arrive at a compatible length of 33 bytes. As a developer, you don’t have to worry about this: smart contract addresses can be used just the same as account addresses.

Token Units

1 aergo = 1 * 10^18 aer = 1 * 10^9 gaer

The Aergo CLI and client libraries have support for these units, i.e. you can specify transaction amounts as 1 aergo instead of 1000000000000000000.

Note that amounts in the base unit aer exceed the range of 64-bit integers. You need some implemention of Big Integer to deal with these numbers. Aergo SDKs come bundled with a recommended way to do that. In most cases, you can just use strings instead of numbers. For example, when creating a JSON transaction, set

{
    "amount": "1000000000000000000"
}

Name System

Aergo contains a name service to translate addresses into easy to remember short names.

One name maps to exactly one address. Names are currently fixed to a length of 12 characters.

Names include an owner and a destination. The owner is used to determine who can change the name, the destination is the actual adress the name should resolve to. In case of normal accounts, these two values will be identical, but they differ in case of smart contracts.

Creating and updating names

The easiest way to create and update names is the aergocli.

Registering and updating names currently requires spending 1 aergo.

To register a new name:

aergocli name new --from my_unlocked_account_address --name my12charname

To change the destination of the name:

aergocli name update --from my_unlocked_account_address --to account_address_or_contract_address --name my12charname

Warning

The update command affects both the destination and the owner of a name. If the new destination is a regular account, both owner and destination are set to that address. If the new destination is a smart contract address, the owner is set to the address of that contract’s creator.

Lookups

To retrieve the owner and destination of a registered name:

aergocli name owner --name my12charname

The destination field contains the resolved address.

This method is also available over RPC and in the various SDKs.

Reverse lookups

Aergo server currently supports no way to do reverse lookups, i.e. finding all names associated with an address. On public networks, you can use block explorers like Aergoscan to find that information.

Technical details

Names are stored in the state of the special account aergo.name. They are created and updated using special governance transactions. Refer to transaction types for the technical specification of these actions. Governance transactions currently don’t require any fee, but the name system requires an amount of 1 aergo to be included in the transaction.

Transactions that create or update names are effective after they are included in a block. That means that you can only refer to new or updated names in the following block.

Consensus Algorithm

The objective of all blockchain protocols is to replicate a blockchain and its associated state across participating nodes. To achieve such an agreement, each blockchain protocol deploys a consensus algorithm.

The public Aergo network uses Delegated Proof of Stake (DPoS) for blockchain consensus.

BP Election

In DPoS, blocks are generated only by a limited number of nodes called Block Producers (BPs). BPs are elected via voting, where the voting power is weighted by staked tokens.

BPs are re-elected round by round (blocks per round = 100). In each round, time is split into slots and each slot is assigned to one of the elected BPs. Only the permitted BP can produce a block in a time slot.

Staking & Voting

Staking means locking up one’s tokens for a minimum period of time. Any user wanting to vote must stake their tokens since the voting power is weighted by the number of staked tokens, as remarked above.

All of these requests are performed via a transaction. Therefore, all proccesses are transparently recorded in the blockchain and can be verified by anyone.

After the voting transaction is included in the block, the results are caculated immediately. But there is a slight delay until it is applied. The current BPs are elected based on the voting result gathered at the block number: (<current block number> / 100 - 1) * <the total number of BPs>.

In other words, the voting results gathered in the past (approximately 1 round before) are used for stability (recent blocks may be roll-backed via a reorganization).

Votes are locked for a certain period of time to prevent users from spamming votes. On the public Aergo network, this is currently approx. 1 day (after 60 * 60 * 24 block number). That means, after casting a vote, a user can only change their vote after 1 day has passed.

Last Irreversible Block (LIB)

In some blockchain protocols, a blockchain may branch into two or more, which is called a fork. Later, only one of them is chosen as the main branch via a set of rules defined by the protocol. Such reorganizations limit each block’s finality and, in turn, transaction’s finality. For example, a transaction, included in a block at one time, might be rejected later.

DPoS also allows blockchain forks. However, a block becomes a last irreversible block (LIB) when it is (double time) confirmed by a majority (2/3+) of BPs. Once a block is determined as a LIB, it cannot be rolled back, i.e. it achieves finality.

Transactions

Tx

Field Type Description
Hash bytes Hash of body
Body Nonce uint64 Increasing number used only once per sender account
Account bytes Decoded sender account address
Recipient bytes Decoded receiver account address
Amount bytes Amount of transfer
Payload bytes Smart contract data
Limit uint64 Reserved
Price bytes Reserved
Type int 0 is normal type, 1 is governance type
ChainIDHash bytes Hash of chain ID
Sign bytes ECDSA signature with secp256k1

Payload

A payload can be any kind of binary data, but is most often used with JSON strings for smart contract calls.

Transaction types

There are two kinds of transactions.

Normal type

Normal transactions are used to transfer tokens and calling smart contracts.

Governance type

Governance transactions are used for calling system contracts, such as staking and voting. Transactions of this type have a special payload format and recipient.

The following table shows the specification for each field of the transaction body.

Action Recipient Amount Payload
staking aergo.system amount to stake {"Name":"v1stake"}
unstaking aergo.system amount to unstake {"Name":"v1unstake"}
voting aergo.system 0 {"Name":"v1voteBP","Args":[<peer IDs>]}
create name aergo.name 1 aergo {"Name":"v1createName","Args":[<a name string>]}
update name aergo.name 1 aergo {"Name":"v1updateName","Args":[<a name string>, <new owner address>]}
add admin aergo.enterprise 0 aergo {"Name":"appendAdmin","Args":[<new admin address>]}
remove admin aergo.enterprise 0 aergo {"Name":"removeAdmin","Args":[<admin address>]}
change raft cluster aergo.enterprise 0 aergo {"Name":"changeCluster","Args":[{"command":"add","name":"[node name]","address":"[peer address]","peerid":"[peer id]"}]}
add config aergo.enterprise 0 aergo {"Name":"appendConf","Args":[<config key>,<config value>]}
enable config aergo.enterprise 0 aergo {"Name":"enableConf","Args":[<config key>,<true|false>]}
remove config aergo.enterprise 0 aergo {"Name":"removeConf","Args":[<config key>,<config value>]}

The aergo.system transactions, including staking, unstaking and voting, can be sent about once per day per account. For staking and unstaking, there is a limit to the amount of requests. It must be over 10000 aergo based on the amount of staked. Therefore, the first staking request should exceed 10000 aergo, and in the case of the unstaking request, more than 10000 must be left or withdrawn altogether.

The aergo.enterprise transactions are only for the private blockchain network. if you want to enable aergo.enterprise, you should make the genesis block with "public":"false"

Transaction receipts

See also

See API → Receipt for a detailed explanation of all the receipt data.

Every transaction generates a receipt upon succesful execution. The status can be one of three values:

SUCCESS
Simple value transfer transactions and succesful contract executions. For contract calls, the result is available in result.
ERROR
Failed contract execution. The error message can be found in result.
CREATED
Succesful contract deployment transaction. The created address can be found in contractAddress.

Smart Contracts

Contracts are special kinds of accounts that have code, an ABI, and state.

This is a technical description of the protocol and execution. It is recommended to interact with contracts using higher level API supported by aergocli and the various SDKs.

Deployment

Contracts are deployed by sending a transaction with the contract code as payload to the null receiver (empty receiver address). Upon execution, the contract state is created at an address calculated from the sender and the nonce of the deployment transaction. You can find out the created contract address in the transaction receipt.

See here for details about address generation.

Calling Contracts

To call contract methods, send a transaction to the contract’s address specifying the function name and arguments as JSON payload.

Events

Contracts can log events during execution. This is the preferred way to notify the outside world of important state changes.

Logged events can be found as part of the transaction receipt and also easily searched for using the GetEvents API.

Transaction Fees

The Aergo protocol includes transaction fees that need to be paid according to the configuration of the network.

Currently, the public mainnet has a minimum fee of 0.002 aergo.

And additional fees is required to use a contract.

  • 5 gaer per byte of the tx’s payload
  • 5 gaer per byte requested to update the state DB

Because Aergo does not have gas prime and gas limit, during the early period, execution of the contract has some limitations.

  • To send a coin transfer TX, the sender must have a balance of 1.026 aergo or more.
  • And the sender who to execute a contract must have a balance of 2.05 aergo or more.
  • The maximum size of the state DB that can be modified per contract is 200 KB.

This fee system may change in the future.

Sidechains can configure a custom fee. For private chains, free transactions are also possible.

Blocks

Block header

Field Type Description
ChainID []byte identifier of chain
PrevBlockHash []byte hash of previous block
BlockNo uint64 height of block
Timestamp int64 block timestamp
BlocksRootHash []byte root hash of State SMT(sparse merkle tree)
TxsRootHash []byte Merkle root of transactions
ReceiptsRootHash []byte Merkle root of transaction receipts
Confirms uint64 indicates how many block is confirmed by block in DPOS consensus
PubKey []byte public key of the block producer (BP)
CoinbaseAccount []byte the account address to which block reward is given
Sign []byte BP’s Signature for block header
ChainID

It is used to prevent the wrong block transmission from other chains.

Field Type Description
Version int32 version number of chain
PublicNet bool true if public net
MainNet bool true if main net
CoinbaseFee string Fee consumed per tx. Fixed value
Magic string Magic string, arbitrarily chosen by each blockchain
Consensus string dpos or sbp
Version

Version is used to identify when the block format changes or when the function of the chain changes.

PublicNet

Differentiate between public and private networks.

MainNet

Differentiate between main net and other test net or other use net.

CoinbaseFee

CoinbaseFee is used to set the peak per Tx.

Magic

Magic can be considered as a name of a blockchain. The two blockchains with different magic strings reject each other’s blocks (they are seperate, indenpendent blockchains).

Consensus

Specify the concensus method name used in the chain.

Block body

Field Type Description
Txs []Tx Transactions

P2P

P2P wire protocol

This page describe the p2p wire protocol for protocol version 0.3.3

Note: Some contents are work in progress and will be implemented before the launch of the mainnet.

Messages
Handshake message

A handshake message is used once at starting handshake. The outbound peer sends HSReqHeader and the inbound peer send HSResp to select perper handshake protocol version. As of Aergo v1.2.0, the protocol version is 0.3.2 and can accept 0.3.1 and 0.3.0

HSReq is variable length byte stream which contains accepted protocol versions

  • 4 : Magic
  • 4 : count of accepted protocol versions
  • 4*n : list of accepted versions. The former is perfered version (actually the newest version is the first)

HSResp is 8 bytes length byte stream

  • 4 : The same Magic as HSReq request or zero if handshaking is not possible
  • 4 : The selected protocol version or error code if first 4 byte value is zero
Handshake response error codes
Name Code Remark
HSCodeWrongHSReq 0001 Request header is wrong
HSCodeNoMatchedVersion 0002 The inbound server have no prefer protocol version
HSCodeAuthFail 0003 Wrong peer identiry
P2P version notation
  • 2 : Major verion
  • 1 : Minor version
  • 1 : Patch version
Normal message

Header (48bytes) + Payload (variable size)

Message header
  • 4 : code number of subprotocol . Big endian number
  • 4 : payload size. Big endian number.
  • 8 : creation time of this message. unix timestamp with precision of nanosecond . Big endian number
  • 16 : message id. binary form of uuid.
  • 16 : original request id. only meaningful if message is response message. binary form of uuid.
Message payload

Payload is serialized form of protobuf struct. The size and struct type is differ by subprotocol.

List of Subprotocols

Code is hexadecimal number. Refer to Subprotocols for detailed information of each subprotocol.

Name Code Summary
StatusRequest 0001 Used in handshake
PingRequest 0002 Ping including last block hash and number
PingResponse 0003 Response ping
GoAway 0004 Disconnect notice with reason
AddressesRequest 0005 Query request to get list of connected peers
AddressesResponse 0006 Response for AddressesRequest.
GetBlocksRequest 0010 request for getting datas of blocks
GetBlocksResponse 0011 response of GetBlocksRequest. Multiple responses for a single request if size of blocks is too big
GetBlockHeadersRequest 0012 request list of headers of consecutive blocks.
GetBlockHeadersResponse 0013 response of GetBlockHeadersRequest
NewBlockNotice 0016 notice of block which the sender was not produced; i.e. it is relay of block notice.
GetAncestorRequest 0017 request for finding common ancestor. used for peer sync
GetAncestorResponse 0018 response of GetAncestorRequest
GetHashesRequest 0019 request for get hashes of consecutive blocks.
GetHashesResponse 001A response of GetHashesRequest
GetHashByNoRequest 001B request for get hash of single block by number
GetHashByNoResponse 001C response of GetHashByNoRequest
GetTXsRequest 0020 request for getting datas of txs
GetTxsResponse 0021 response of GetTXsRequest. Multiple responses for a single request if size of blocks is too big
NewTxNotice 0022 notice of valid tx
BlockProducedNotice 0030 block notice from block producer
List of Response Status

Some subprotocols for responsing other message have ResultStatus property.

Name Code Remark
OK 0 OK is returned on success.
CANCELED 1 when operation was canceled
UNKNOWN 2  
INVALID_ARGUMENT 3 INVALID_ARGUMENT is missing or wrong value of argument
DEADLINE_EXCEEDED 4 timeout
NOT_FOUND 5 Resource is not found
ALREADY_EXISTS 6  
PERMISSION_DENIED 7  
RESOURCE_EXHAUSTED 8  
FAILED_PRECONDITION 9  
ABORTED 10  
OUT_OF_RANGE 11  
UNIMPLEMENTED 12 indicates operation is not implemented or not supported/enabled in this service.
INTERNAL 13  
UNAVAILABLE 14 Unavailable indicates the service is currently unavailable.
DATA_LOSS 15  
UNAUTHENTICATED 16 indicates the request does not have valid authentication credentials for the operation.
Payload of Subprotocols
StatusRequest
  • sender: information of sender (address, port, peerID or etc)
  • bestBlockHash: current best block of sender
  • bestHeight: current best block height of sender
  • chainID: ChainID which sender is storing
  • genesis: hash of genesis block, added since protocol version v0.3.2
PingRequest
  • bestBlockHash: current best block of sender
  • bestHeight: current best block height of sender
GoAway
  • reason: description text
AddressesRequest
  • sender: address information of requester
  • maxSize: limit of response size
AddressesResponse
  • status: response status code
  • peers: list of peers
GetBlocksRequest
  • hashes: array of block hashes
GetBlocksResponse
  • status: response status code
  • blocks: list of block data
  • hasNext: boolean flag indicating there are more response(s) for the request
GetBlockHeadersRequest
  • hash: starting hash to get.
  • height: starting height to get. height is ignored if hash is not empty.
  • size: maximum header count to get.
GetBlockHeadersResponse
  • status: response status code
  • hashes: array of block hashes which the response contains.
  • headers: list of block headers. the order of hashes and headers is matching
  • hasNext: boolean flag indicating there are more response(s) for the request
NewBlockNotice
  • blockHash: hash of new block
  • blockNo: block number
GetAncestorRequest
  • hashes: list of block hashes
GetAncestorResponse
  • status: response status code
  • ancestorHash: block hash of common ancestor
  • ancestorNo: block number of common ancestor
GetHashesRequest
  • prevHash: block hash of starting point. the hash and number must match to actual block
  • prevNumber: block number of starting point
  • size: maximum hash count to get.
GetHashesResponse
  • status: response status code
  • hashes: array of block hashes which the response contains.
GetHashByNoRequest
  • blockNo: block number
GetHashByNoResponse
  • status: response status code
  • blockHash: hash of requested block
GetTXsRequest
  • hashes: array of tx hashes
GetTXsResponse
  • status: response status code
  • hashes: array of tx hashes which the response contains.
  • txs: list of tx data. the order of hashes and txs is matching
  • hasNext: boolean flag indicating there are more response(s) for the request

Legacy version infomation

v0.3.0
Handshake message

-A handshake message is used once at starting handshake. It contains two 4-byte number. Both outbound peer send HSReq

+HSReq is 8 byte stream which p2p protocol version

+4 : Magic +4 : p2p protocol version of outbound peer. The inbound peer accept handshake if version is matching or close connection if not.

Peer Connect

NOTE: Some document is not translated yet.

Node Discovery

When the Aergo server starts running, you need a way to connect to the network. To do this, you need to know and connect to other Aergo server nodes already connected to the chain. Aergo does this using several methods.

Query polaris

Polaris keep list of aergo server nodes, such like DNS. Aergo server connect and query to official Aergo Polaris automitically, if the chain is Official AergoMainNet or AergoTestNet.

You can build and run custom Polaris for your private chain or custom public chain. You should configure to use custom Polaris by modifying config file.

Designate Peer

You can add a list of designated known peers to connect to at boot time in configuration file using the option ‘npaddpeers’.

Dynamic peer discovery

Aergo server requests peer list from other connected peers as well as Polaris if it cannot find enough peers.

Choosing remote peers

(This feature is currently work in progress)

The list of peers to connect to is managed in Kademlia-like manner. The number of peers that are closer to the peer is larger and the number of peers that are connected to the peer is smaller. The peer’s distance is based on the difference based on the hash value, not the physical distance.

Peer connect process

The network communication of Aergo server operates on libp2p basis, and libp2p is responsible for encryption and node distinction at transmission level. After a tcp session is created, both peers start the handshake operation.

Peer Handshake

In the Handshake phase, peers exchanges each other’s version, chain ID and state to determine whether to connect. If the other node version is not supported by the current server or the operating chain ID is different, the connection is stopped. Once the handshake is successful, the difference in block height is compared and synchronization started.

Keep Alive

Aergo server maintains a connection-based communication. Both peers disconnect when the internally defined retention score increases beyond a certain level. This score decreases to a low level when a query is requested, and increases when a bad block or TX notification is sent.

Peer blacklist

(This feature is currently work in progress)

When an internally defined ban score exceeds a certain level, the Aergo server blocks the peer’s connection. This score increases due to the connection being disconnected due to exceeding the connection maintenance score, etc., and the blocking period is also changed by calculating the score or the number of blocking times. You can also permanently block by specifying a block address in the configuration file.

Block Management

This article describes implementation details of management of blocks in the Aergo server. It is aimed at blockchain server developers.

Block generation

The block factory is responsible for generating blocks and part of the consensus engine.

The consensus engine manages when blocks are created on which nodes. AERGO uses DPoS by default. A new block producer is selected every second.

The process for creating blocks in the block factory is as follows.

  1. Select transactions from from mempool
  2. Perform a transaction one by one. If the execution is successful, the transaction is included in the block.
  3. If the block size and time limit are exceeded, the transaction is no longer included.
  4. Create blocks that contain executed transactions and add signatures to blocks.

The block factory sends the generated blocks to the chain service for propagation and storage.

Notify block

Blocks passed to the chain service are propagated to the connected peer nodes and stored in the database.

The chain service of a node that received the block verifies the block, executes the transactions, and adds the block to its own database.

Save block

The chain service stores the generated blocks in the DB for permanent storage. It also stores additional meta information to store connection information about the chain.

AERGO uses the Badger database as its permanent storage. Badger stores data in key/value form and supports the concept of transactions similar to a typical database.

Information stored in the DB is as follows.

The DB is managed in two separate categories, ChainDB and StateDB. This article describes the ChainDB used to store chain information.

Block info

This information is used to search for blocks in a chain using a hash. Typically, when a block is requested as a hash from another node, the Hash is searched for and responded to the block with a key.

Key Value
Hash of Block serialized data of Block
Chain info

Chain info is the information that indicates when a block is connected to the main branch.

If the main branch is not connected, that is, only block info is saved and the chain info is not stored.

You can search the blocks of every height of the main branch using the chain info. You can know the height of the top block of the chain.

Chain info is also used to determine whether the block belongs to the main branch or the sub branch.

Key Value
Number of Block block hash
Latest block Key latest block number of main branch
Transaction Info

tx info is meta information of the transaction that was performed in the main branch. If you search the DB with transaction hash, you can see which block the transaction is stored in and where the transaction is stored in the block.

The contents of the transaction are not saved separately. Therefore, in order to know the contents of the actual transaction, you must search Block info using Block hash and index found in tx info.

Key Value
Transaction hash (Block Hash, index of transaction in block)

Chain Management

This article describes implementation details of chain management in the Aergo server. It is aimed at blockchain server developers.

The chain service is responsible for managing the chain. It performs the following tasks in large part:

  1. Validation
  2. Insert block to chain
  3. Reorganization
  4. Syncronization

Block validation

The blocks received in the network may not be valid, so a number of checks are made.

Pre-execution execution

The validator module ensures that the block was generated from a valid BP and the transaction contained in the block was not forged.

  • Consensus validation

    Validate the block generated by the valid BP through block creation time and signature.

  • Transaction merkle validation

    Validate that the transactions were not forged. The verifier module generates a merkle tree with the transactions and checks if it is the same as the transaction merkle root stored in the block header.

Post-execution validation

These checks ensure that the results of the transaction contained in the block are the same as the results of the BP node that generated the block.

  • State root validation

    Checks if the changed state root node hash is the same as the blocksRootHash stored in the block head.

  • Receipt merkle validation

    Generates a merkle tree with the receipts generated as a result of the transactions and checks if they are identical to the receipts stored in the block header.

Insert block into chain

There are two cases in which the chain service adds blocks:

  1. Block generated by block factory

When it is a BP node’s turn, it generates new blocks in the block factory.

The block factory performs all transactions and forwards the block to the chain service. The execution results are included with the block.

The execution results include the results of the transaction, receipt, and state changed entry indicating the change to the account.

The chain service stores information related to blocks in the ChainDB and information about accounts in the StateDB.

  1. Block received from another peer node

For blocks received from other peer nodes, there are three main cases:

  • Orphan block

    This is the case if the parent block has not yet been stored in the DB. Orphan blocks are stored in the orphan block cache on memory. Then, when the parent block is received, it is removed from the organ block cache and reprocessed.

  • Side branch block

    In case the parent block is stored but is not part of the main branch. In this case, the block is not performed and only the block info{hash, block} is stored.

  • Main branch block

    In case the head of the main branch is the next block. In this case, the blocks are stored after performing the transactions.

The process for storing blocks in the main branch is as follows:

  1. Validation before execution
  2. Execute transactions
  3. Apply changed account entries state merkle tree
  4. Validate after execution
  5. Save state merkle tree to StateDB
  6. Save chain meta data to ChainDB

Reorganization

The chain service selects and maintains the longest chain as the main branch. The side branches are not executed and only the block info is stored in the DB. If the side branch received from another peer is longer than the main branch held by the node, the side branch is changed to the main branch. This is called the reorgnize process.

The reorgnization is performed as follows.

  1. Find common ancestor
Syncer finds the last common ancestor block of the main branch and side branch.
  1. Rollback master branch
State is reset to the point at which the common ancestor block was executed
  1. Rollforward side branch
Syncer runs from the next number of the common ancestor block to the head block of the side branch. At this time, only StateDB is changed and Chain info and Tx info are not changed.
  1. Swap chain meta

Syncer do not change the chain info during rollback and rollforward to atomically change the chain. Change the chain meta information after the previous process has been successfully completed. At this time, chain info and transaction info are deleted for the rollbacked block, and new chain info and transaction info are added for the rollforwarded block.

Transactions belonging to rollbacked blocks but not included in rollforwarded blocks are returned to mempool. This is to prevent transaction loss.

Syncronization

When you add a new node or restart a node that was temporarily stopped, you need to get the latest chain information from existing nodes. This is called the synchonization process.

The situation that causes sync is as follows:

  • When the peer goes through a handshake process to connect, the height of the chain of the remote peer is higher than the current node
  • If the height of the block notified in the peer is higher than the head of the current main branch

The syncer specifies the node that sent the block that caused the sync to the target node and synchronizes with the chain of that node.

To synchronize a long chain, a large amount of block information must be received from the peer node. This is likely to cause a performance degrade at the peer node. Therefore, it gets information from as many peers as possible to distribute the load.

Synchronize step
  1. Find common ancestor: Syncer finds the last common ancestor of the current node chain and the target node chain.
  2. Get hashes: It gets the hashes of the block after the common ancestor from the target node.
  3. Get blocks: N blocks are requested from all valid peers connected to the current node.
  4. Insert blocks to chain: The received block is added to the chain using the chain service.

2, 3, and 4 are performed in parallel. Most of the time is spent in the insert part of the chain.

Contributing

As AERGO is an open-source platform, individual contributions are vital.

There are many ways that you can help, no matter if you are a novice or advanced programmer or user.

Ways to Contribute

These are just some examples for welcome contributions.

  • Improve this documentation
  • File a bug report
  • Submit a pull request
  • Discuss protocol changes
  • Help answering questions

Join the Community

An open-source platform lives from its community. You can reach out to the Aergo team and other members of the developer community via these channels:

Building from Source

This page explains how you can build aergo from source.

If you are only interested in running the aergo tools, it is easier to use pre-built binaries or Docker images instead, as explained in Quickstart.

Linux

  1. Install dependencies

    apk update
    apk add git build-base go libgcc
    
  2. Install aergo

    go get -d github.com/aergoio/aergo
    cd ${GOPATH}/src/github.com/aergoio/aergo
    git submodule init && git submodule update
    make
    
  3. Set environment

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GOPATH}/src/github.com/aergoio/aergo/libtool/lib
    

macOS

  1. If you haven’t already, install homebrew.

  2. Install dependencies

    brew install go
    brew install cmake  # optional
    brew install protobuf  # optional
    
  3. Install aergo

    go get -d github.com/aergoio/aergo
    cd `go env GOPATH`/src/github.com/aergoio/aergo
    git submodule init
    git submodule update
    make
    
  4. Set environment

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GOPATH}/src/github.com/aergoio/aergo/libtool/lib
    
  5. Run server

    ./bin/aergosvr
    

Windows

Building on Windows is currently not supported.

Generating protobuf files

If you changed the protobuf files, you need to re-compile the type definitions.

  1. Install protoc-gen-go

    GIT_TAG="v1.1.0" # set version of protoc-gen-go to 1.1.0, on which aergo v0.8.x depends.
    go get -u github.com/golang/protobuf/protoc-gen-go
    git -C "$(go env GOPATH)"/src/github.com/golang/protobuf checkout $GIT_TAG
    go install github.com/golang/protobuf/protoc-gen-go
    
  2. Generate type definitions from protobuf files

    make protoc
    

SDKs

Aergo offers language-specific SDKs to make it easy to develop Dapps. There are currently SDKs for Java, Javascript, and Python programming environments.

_images/dapp-overview.png

Heraj

Please refer to the Github Wiki pages for Heraj.

Herajs

Please refer to the Herajs documentation.

Herapy

Please refer to the Herapy documentation.

Other Languages

If you are using another language that is currently not supported by a decicated SDK, you can still interact with AERGO using the API directly.

Please refer to the API reference.

Tools

Aergocli

aergocli is a command line tool that interfaces with the GRPC exposed by aergosvr.

Installation

Using the binary

You can find the latest binary release on Github. Just download and extract the archive.

Using Docker

You can also use the Docker image aergo/tools. Example: docker run --rm aergo/tools aergocli version

Usage

In order to use all features of aergocli you will need to have the end point (IP address and port number) to a aergosvr instance.

For a list of all commands known to aergocli, simply run it with no arguments.

Usage:
aergocli [command]

Available Commands:
account     account command
blockchain  Print current blockchain status
bp          show bp voting stat
chaininfo   Print current blockchain information
committx    Send transaction
contract    contract command
event       Get event
getblock    Get block information
getpeers    Get Peer list
getstate    Get account state
gettx       Get transaction information
help        Help about any command
keygen      Generate private key
listblocks  Get block headers list
metric      Show metric informations
name        Name command
node        Show internal metric
receipt     receipt command
sendtx      Send transaction
signtx      Sign transaction
verifytx    Verify transaction
version     Print the version number of Aergocli

Flags:
    --config string   config file (default is config.toml) (default "config.toml")
-h, --help            help for aergocli
    --home string     aergo home path (default ".")
-H, --host string     Host address to aergo server (default "localhost")
-p, --port int32      Port number to aergo server (default 7845)

Use "aergocli [command] --help" for more information about a command.

Examples

Create account
$ aergocli account new --password yourpasswordhere
AmP96xd6WYRe1jrWixC3VyFXRCzwZxAJtU3Uc54vn182xG9Yn9Cs

or

$ aergocli account new
Enter Password:
Repeat Password:
AmP96xd6WYRe1jrWixC3VyFXRCzwZxAJtU3Uc54vn182xG9Yn9Cs

Now we can use the account in aergosvr. Please remember the password carefully because there is no way to retrieve the password again.

Send transaction

Before request send transaction you must unlock your account first

$ aergocli account unlock --address AmQFgm1gCvoRw2RfBXnipRmeCLEc6tTQ1kBMmLEzHjp91xYnXK78
Enter Password:
AmQFgm1gCvoRw2RfBXnipRmeCLEc6tTQ1kBMmLEzHjp91xYnXK78

or

$ aergocli account unlock --address AmQFgm1gCvoRw2RfBXnipRmeCLEc6tTQ1kBMmLEzHjp91xYnXK78 --password yourpasswordhere
AmQFgm1gCvoRw2RfBXnipRmeCLEc6tTQ1kBMmLEzHjp91xYnXK78

and then

$ ./aergocli sendtx --from AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q --to AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ --amount 1aergo
{
 "hash": "AkjqFcayutenhonnZPU4X5QB1fNBTZv3o2fNzMLNQR3q"
}
Look up transaction

Use gettx command. If transaction is in block, return transaction with index that represent where it’s included.

When transaction is in mempool, gettx result is like below

$ aergocli gettx 9cAphBMD2zJCD13QfCn7rmxh5iDfrj6M9Wmo54TPNPCg
{
 "Hash": "9cAphBMD2zJCD13QfCn7rmxh5iDfrj6M9Wmo54TPNPCg",
 "Body": {
  "Nonce": 2,
  "Account": "AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q",
  "Recipient": "AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ",
  "Amount": "1230000000000000000",
  "Payload": "",
  "Limit": 0,
  "Price": "0",
  "Type": 0,
  "Sign": "AN1rKvt8EZHKEE2wNPXAhGcDA4pMo7yRRjTWCcpyrW9QCMv6nMhvhqriWujHdaDJgJ6ft6VLDActEFtUFA2pRnRJFVFSWxPSR"
 }
}

When transaction is in block, gettx result is like below

$ aergocli gettx 9cAphBMD2zJCD13QfCn7rmxh5iDfrj6M9Wmo54TPNPCg
{
 "TxIdx": {
  "BlockHash": "ECVG696Jc7FvUL86sDSxT28akh4Hf1RXFRzmGqtAv9zU",
  "Idx": 1
 },
 "Tx": {
  "Hash": "9cAphBMD2zJCD13QfCn7rmxh5iDfrj6M9Wmo54TPNPCg",
  "Body": {
   "Nonce": 2,
   "Account": "AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q",
   "Recipient": "AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ",
   "Amount": "1230000000000000000",
   "Payload": "",
   "Limit": 0,
   "Price": "0",
   "Type": 0,
   "Sign": "AN1rKvt8EZHKEE2wNPXAhGcDA4pMo7yRRjTWCcpyrW9QCMv6nMhvhqriWujHdaDJgJ6ft6VLDActEFtUFA2pRnRJFVFSWxPSR"
  }
 }
}
Check block
$ aergocli getblock --hash GGT9wahqcKKGKUncMuhRLLL3JaCs2MEBx7V8UdrK9JNi
{
 "Hash": "FwBq14HiBPMPoGV6jYxW4AaGHsgoD9UJjmYyWwnQR6xU",
 "Header": {
   "ChainID": "1111117eaxEoT4pDHzFTCyKv93acfDHbsytUPK3oqU6",
   "PrevBlockHash": "GocCiGXUVV4ygsbEi1VaJKkBwyvRsV4W4Qj72J5ZciZK",
   "BlockNo": 17655,
   "Timestamp": 1548314097754698000,
   "BlockRootHash": "5etqxP9HTtzgN8a3tN5Ev8ka4aG3aQM5GYNikwmsV41q",
   "TxRootHash": "AkjqFcayutenhonnZPU4X5QB1fNBTZv3o2fNzMLNQR3q",
   "ReceiptsRootHash": "7ZpYoMA2feXoXAit5J2FFuX16cwz9hp8twGwu7rUHCRZ",
   "Confirms": 2,
   "PubKey": "GZsJqUTtFVJTJ5SbwuFac4NxZFWgTRjpioPD76UL1DHZLhxmWg",
   "Sign": "AN1rKvtSPyBqB34TGmEQ6FQ8Lz61dvQ4zVAHodAnPGTnXD7gihmSkgrWcyeEoXNeS6zLTtgjukcTiwSKTHmMATGe8PXgwcJJK",
   "CoinbaseAccount": ""
  },
  "Body": {
   "Txs": [
    {
     "Hash": "AkjqFcayutenhonnZPU4X5QB1fNBTZv3o2fNzMLNQR3q",
     "Body": {
      "Nonce": 3,
      "Account": "AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q",
      "Recipient": "AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ",
      "Amount": "1000000000000000000",
      "Payload": "",
      "Limit": 0,
      "Price": "0",
      "Type": 0,
      "Sign": "381yXZAWNW8ZiST7PCLmywUsNVQvzgwhiyu9pxVDSvUhwyLHmoL7BQGXQhCNp7QZQycvbwT2nQJ7etscArfRbHu98Qi5MSmY"
     }
    }
   ]
  }
 }
Sign transaction

After unlock the account

$ aergocli signtx --jsontx "{ \
\"Nonce\": 2, \
\"Account\": \"AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q\", \
\"Recipient\": \"AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ\", \
\"Amount\": \"1.23aergo\", \
\"Payload\": \"\", \
\"Limit\": 0, \
\"Price\": \"0\", \
\"Type\": 0 }"
{
 "Hash": "9cAphBMD2zJCD13QfCn7rmxh5iDfrj6M9Wmo54TPNPCg",
 "Body": {
  "Nonce": 2,
  "Account": "AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q",
  "Recipient": "AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ",
  "Amount": "1230000000000000000",
  "Payload": "",
  "Limit": 0,
  "Price": "0",
  "Type": 0,
  "Sign": "AN1rKvt8EZHKEE2wNPXAhGcDA4pMo7yRRjTWCcpyrW9QCMv6nMhvhqriWujHdaDJgJ6ft6VLDActEFtUFA2pRnRJFVFSWxPSR"
 }
}
Commit Transaction

Send given transactions to aergosvr

$ aergocli -p 27845 committx --jsontx "{
\"Hash\": \"9cAphBMD2zJCD13QfCn7rmxh5iDfrj6M9Wmo54TPNPCg\",
\"Body\": {
  \"Nonce\": 2,
  \"Account\": \"AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q\",
  \"Recipient\": \"AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ\",
  \"Amount\": \"1230000000000000000\",
  \"Payload\": \"\",
  \"Limit\": 0,
  \"Price\": \"0\",
  \"Type\": 0,
  \"Sign\": \"AN1rKvt8EZHKEE2wNPXAhGcDA4pMo7yRRjTWCcpyrW9QCMv6nMhvhqriWujHdaDJgJ6ft6VLDActEFtUFA2pRnRJFVFSWxPSR\"
}
}"
{
 "results": [
  {
   "hash": "9cAphBMD2zJCD13QfCn7rmxh5iDfrj6M9Wmo54TPNPCg"
  }
 ]
}
Get Account state

Check account’s state (nonce, balance)

$ aergocli getstate --address "AmNvFyqKFGVWvQ3MTi3eMFiNB9zvL9cK43B9c9bzcA732YZjZgfn"

Get state with a compressed merkle proof.

$ aergocli getstate --address "AmNvFyqKFGVWvQ3MTi3eMFiNB9zvL9cK43B9c9bzcA732YZjZgfn" --proof --compressed

By default, the returned state is the one at the latest block, but you may specify any past block’s state root.

$ aergocli getstate --address "AmNvFyqKFGVWvQ3MTi3eMFiNB9zvL9cK43B9c9bzcA732YZjZgfn" --root "9NBSjkcNTdE5ciBxfb52RmsVW7vgX5voRsv6KcosiNjE"
Show connected peers

Use getpeers to show list of peers connected to a aergosvr.

It shows remote peers by default, but with --self options, local aergosvr itself is shown in list. You can find it by checking Self property.

[
 {
  "Address": {
   "Address": "13.124.83.51",
   "Port": "7846",
   "PeerId": "16Uiu2HAmQn3nFBGhJM7TnZRguLhgUx1HnpNL2easdt2JrxdbFjtb"
  },
  "BestBlock": {
   "BlockHash": "BXAFbTbwEuywukzBqRKdCsuUpinnNQsVJCAXNVJAR6F4",
   "BlockNo": 1251651
  },
  "LastCheck": "2019-02-27T11:26:38.481451+09:00",
  "State": "RUNNING",
  "Hidden": false,
  "Self": true
 },
 {
  "Address": {
   "Address": "13.211.156.203",
   "Port": "7846",
   "PeerId": "16Uiu2HAkvbHmK1Ke1hqAHmahwTGE4ndkdMdXJeXFE3kgBs17k2oQ"
  },
  "BestBlock": {
   "BlockHash": "AF68dtMMHd1h5LjxSyYY9AomMve6Qk2kBRSoQuuuSkhM",
   "BlockNo": 1251650
  },
  "LastCheck": "2019-02-27T11:26:38.349938+09:00",
  "State": "RUNNING",
  "Hidden": false,
  "Self": false
 },
 {
  "Address": {
   "Address": "203.109.12.23",
   "Port": "7846",
   "PeerId": "16Uiu2HAmAnQ5jjk7huhepfFtDFFCreuJ21nHYBApVpg8G7EBdwme"
  },
  "BestBlock": {
   "BlockHash": "BXAFbTbwEuywukzBqRKdCsuUpinnNQsVJCAXNVJAR6F4",
   "BlockNo": 1251651
  },
  "LastCheck": "2019-02-27T11:26:38.364262+09:00",
  "State": "RUNNING",
  "Hidden": false,
  "Self": false
 }
]

Example without aergosvr

There are some feature working on aergocli itself without aergosvr.

Create, Export, Import account

With --path option, aergocli creates an account in the given path and not in aergosvr.

$ aergocli account new --password yourpasswordhere --path path/to/save/account
AmNFcocofUvmyLtXA6WgpANbjiF7RScGvQ4memNyNzS4ARJox3yq

Private key of account is store in the given path.

Of course this account can be exported and imported to aergosvr or another path.

$ aergocli account export --address AmNFcocofUvmyLtXA6WgpANbjiF7RScGvQ4memNyNzS4ARJox3yq --password yourpasswordhere --path path/to/save/account
47rsdfckuUCcjY3SmzCtmthhQm336Cpz9341xQHq6sr5Wm3md9FaTZDj6Gkqtff3WBPoqtzVV
$ aergocli account import --if 47rsdfckuUCcjY3SmzCtmthhQm336Cpz9341xQHq6sr5Wm3md9FaTZDj6Gkqtff3WBPoqtzVV --password yourpasswordhere --path other/path/to/save/account
AmNFcocofUvmyLtXA6WgpANbjiF7RScGvQ4memNyNzS4ARJox3yq
Sign transaction

With --path option, aergocli can sign the transaction using private key of account in given path.

Unlike using aergosrv, parameter --address and --password are needed instead of unlock.

$ aergocli -p 17845 signtx --address AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q --jsontx "{ \
\"Nonce\": 2, \
\"Account\": \"AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q\", \
\"Recipient\": \"AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ\", \
\"Amount\": \"1.23aergo\", \
\"Payload\": \"\", \
\"Limit\": 0, \
\"Price\": \"0\", \
\"Type\": 0 }" --path path/to/save/account --password yourpasswordhere
{
 "Hash": "9cAphBMD2zJCD13QfCn7rmxh5iDfrj6M9Wmo54TPNPCg",
 "Body": {
  "Nonce": 2,
  "Account": "AmPLWBzx4tAYt91JM3jKWFs3aYWHSvKpYYzdUQuQMNa7jAw5t65q",
  "Recipient": "AmLnVfGwq49etaa7dnzfGJTbaZWV7aVmrxFes4KmWukXwtooVZPJ",
  "Amount": "1230000000000000000",
  "Payload": "",
  "Limit": 0,
  "Price": "0",
  "Type": 0,
  "Sign": "AN1rKvt8EZHKEE2wNPXAhGcDA4pMo7yRRjTWCcpyrW9QCMv6nMhvhqriWujHdaDJgJ6ft6VLDActEFtUFA2pRnRJFVFSWxPSR"
 }
}

Aergoluac

aergoluac is a command line tool that compile lua script to binary code for contract.

For a list of all commands known to aergoluac, simply run it with no arguments.

Usage:
aergoluac [flags] srcfile bcfile

Flags:
-a, --abi string   abi filename
-h, --help         help for aergoluac
    --payload      print the compilation result consisting of bytecode and abi

Examples

out to file
aergoluac test.lua test.bc -a test.abi
out to console
aergoluac test.lua --payload

Ship

Ship is a tool for developing lua smart contracts. Its main features are:

  • Manage project structure
  • Install and publish packages
  • Build source fragments
  • Run unit test cases
  • Deployment, execution and querying of a contract.

Please refer to the Ship Github Wiki for details.

Brick

Brick is an interactive shell program to communicate with an aergo VM for testing. This also provides a batch function to test and help to develop smart contracts.

The main advantage of using this tool is that you don’t need a real blockchain network. Instead, you can run operations directly in the aergo virtual machine.

See Brick reference

Polaris

Polaris is a server that provides node discovery for Aergo server.

For bootstrapping new nodes, the npaddpeers configuration option can be used to connect to designated peers.

However, since Aergo version 0.11, the new Polarais server has added the ability to automatically connect to nodes belonging to the specified block chain without manually creating the node list information.

Features

  • Aergo nodes can query addresses of other Aergo nodes. In this case, the chain of the Aergo node and the chain of Polaris must be the same.
  • Aergo nodes can register itself with Polaris. Polaris checks to see if it can connect to the Aergo node and adds it to the node list.
  • One Polaris server per designated block chain

Building Polaris

This section describes how to build Polaris from source without using the Docker. Polaris is available as a sub-module in the aergo project currently in version 0.11.

  1. Get the source from github.com/aergoio/aergo.
  2. Build the polaris executable with make polaris.

Configuration

Four files are used to set Polaris behavior.

  1. Polaris configuration file: Determines the overall operation of Polaris. It also specifies the path to other configuration related files.
  2. Private key file: PK file to use for Polaris communication. It uses the same format as aergosvr’s private key file.
  3. Genesis file: Contains the chain information of nodes to be provided by Polaris. Use the same format as the genesis file used to initialize aergosvr.
  4. Log configuration file: The file name is arglog.toml, and it uses the same format as the file used by aergosvr.
Configuration file creation and example
Create private key file

It can be generated by aergocli using the keygen command.

aergocli keygen mychain-polaris
Wrote files mychain-polaris.{key,pub,id}.
Genesis file creation
{
    "chain_id":{
        "magic": "[insert an identifier string for your network]",
        "public": false,
        "mainnet": false,
        "coinbasefee": "1000000000",
        "consensus": "dpos"
    },
    "timestamp": 1548918000000000000,
    "balance": {
    },
    "bps": [
    ]
}
Polaris configuration file
authdir = "/blockchain/polaris/auth"       # base directory for files about authentication and authorization

[rpc]
netserviceaddr = "127.0.0.1"               # RPC access address. The default setting is 127.0.0.1, which allows RPC access only on the local machine and blocks RPC connections remotely.
netserviceport = 8915

[p2p]
netprotocoladdr = "[real IP address]"      # An externally accessible IP address or domain name
netprotocolport = 8916
npbindaddr = ""
npkey = "mychain-polaris.key"              # Location of private key file

[polaris]
allowprivate = true                        # Whether to allow the private address of the node's access address. Used when building Polaris for private chains operated within a test or private network.
genesisfile = "[location of genesis file]" # Genesis file location
enableblacklist = false                    # Whether to turn on blacklist or not. blacklist entries will be saved in <authdir>
Log configuration file

Refer to the arglog documentation.

Running Polaris

Using Docker
docker run -d -w /tools -v /blockchain/polaris:/tools -p 8916:8916 -p 8915:8915 --restart="always" --name polaris-node aergo/polaris polaris --home /tools --config /tools/polaris-conf.toml
Manually

Manually build and run the live polaris executable in the following format:

./polaris --config polaris-conf.toml

Connecting to Polaris

To connect to a Polaris server, supply its address in the aergosvr configuration file.

See Node Configuration for details.

    [p2p]
    ...
    npusepolaris= true
    npaddpolarises = [
        "/ip4/192.168.0.2/tcp/8915/p2p/16Uiu2HAmJCmxe7CrgTbJBgzyG8rx5Z5vybXPWQHHGQ7aRJfBsoFs"
    ]
...

Colaris

Colaris is a client for Polaris RPC connection.

Building colaris

Like Polaris, build as a sub-module of aergo.

  1. Get the source from github.com/aergoio/aergo.
  2. Build the executable with make colaris.
Usage

It is the same interface as aergocli.

./colaris [flags] <command> [[arg1]...]
Flags
  1. -H <hostname> Address to remote server when requesting. The default value is localhost (127.0.0.1)
  2. -p <portnumber> RPC port number, default is 8915
Commands

node: returns the actor state of Polaris.

current: returns list of nodes registered in Polaris.

Example:

ubuntu@mypolaris:/blockchain/polaris$ ./colaris current
{
 "total": 1,
 "peers": [
  {
   "address": {
    "address": "52.231.31.38",
    "port": 7846,
    "peerID": "16Uiu2HAmBfFABqQ2eWwNMv1A2WJCqVykgPS2sz72jrYTHeZgyors"
   },
   "connected": 1549526282,
   "lastCheck": 1549526463
  }
 ]
}

config: set or get dynamic configurations of polaris. There is just a single config ‘blacklist’, in version 1.2.3.

blacklist: set or get blacklist configuration. blacklist entry can be set by peerID, ip address, cidr or combined. NOTE: it is NOT for security rather avoiding unintentional fork, since changing ip address or peer id is very easy.

Example:

ubuntu@mypolaris:/blockchain/polaris$ ./colaris config blacklist show
ubuntu@mypolaris:/blockchain/polaris$ ./colaris config blacklist add --peerid 16Uiu2HAmDFV41vku39rsMtXBaFT1MFUDyHxXiDJrUDt7gJycSKnX --address "192.168.1.11"
ubuntu@mypolaris:/blockchain/polaris$ ./colaris config blacklist add --address "192.168.1.11"
ubuntu@mypolaris:/blockchain/polaris$ ./colaris config blacklist add --cidr "2001:0db8:0123:4567:89ab:cdef:1234:5678/96"
ubuntu@mypolaris:/blockchain/polaris$ ./colaris config blacklist rm 2

API

The Aergo server exposes an RPC API over gRPC.

Using gRPC

gRPC is a standard for RPC APIs using protobuffer messages for data exchange. The main advantages are typed messages and efficiency: data is packed tightly and sent over HTTP2.

If you want to use the gRPC API directly, please refer to the official documentation to get started. You can find the protobuf definitions in aergoio/aergo-protobuf.

Alternatively, you can use one of the SDKs which wrap the same functionality in language-specific styles.

Protocol Documentation

This reference is auto-generated from aergoio/aergo-protobuf.

Top

rpc.proto

AergoRPCService

AergoRPCService is the main RPC service providing endpoints to interact with the node and blockchain. If not otherwise noted, methods are unary requests.

NodeState

Request Type: NodeReq
Response Type: SingleBytes

Returns the current state of this node

Metric

Request Type: MetricsRequest
Response Type: Metrics

Returns node metrics according to request

Blockchain

Request Type: Empty
Response Type: BlockchainStatus

Returns current blockchain status (best block’s height and hash)

GetChainInfo

Request Type: Empty
Response Type: ChainInfo

Returns current blockchain’s basic information

ChainStat

Request Type: Empty
Response Type: ChainStats

Returns current chain statistics

ListBlockHeaders

Request Type: ListParams
Response Type: BlockHeaderList

Returns list of Blocks without body according to request

ListBlockMetadata

Request Type: ListParams
Response Type: BlockMetadataList

Returns list of block metadata (hash, header, and number of transactions) according to request

ListBlockStream

Request Type: Empty
Response Type: Block

Returns a stream of new blocks as they get added to the blockchain

ListBlockMetadataStream

Request Type: Empty
Response Type: BlockMetadata

Returns a stream of new block’s metadata as they get added to the blockchain

GetBlock

Request Type: SingleBytes
Response Type: Block

Return a single block incl. header and body, queried by hash or number

GetBlockMetadata

Request Type: SingleBytes
Response Type: BlockMetadata

Return a single block’s metdata (hash, header, and number of transactions), queried by hash or number

GetBlockBody

Request Type: BlockBodyParams
Response Type: BlockBodyPaged

Return a single block’s body, queried by hash or number and list parameters

GetTX

Request Type: SingleBytes
Response Type: Tx

Return a single transaction, queried by transaction hash

GetBlockTX

Request Type: SingleBytes
Response Type: TxInBlock

Return information about transaction in block, queried by transaction hash

GetReceipt

Request Type: SingleBytes
Response Type: Receipt

Return transaction receipt, queried by transaction hash

GetABI

Request Type: SingleBytes
Response Type: ABI

Return ABI stored at contract address

SendTX

Request Type: Tx
Response Type: CommitResult

Sign and send a transaction from an unlocked account

SignTX

Request Type: Tx
Response Type: Tx

Sign transaction with unlocked account

VerifyTX

Request Type: Tx
Response Type: VerifyResult

Verify validity of transaction

CommitTX

Request Type: TxList
Response Type: CommitResultList

Commit a signed transaction

GetState

Request Type: SingleBytes
Response Type: State

Return state of account

GetStateAndProof

Request Type: AccountAndRoot
Response Type: AccountProof

Return state of account, including merkle proof

CreateAccount

Request Type: Personal
Response Type: Account

Create a new account in this node

GetAccounts

Request Type: Empty
Response Type: AccountList

Return list of accounts in this node

LockAccount

Request Type: Personal
Response Type: Account

Lock account in this node

UnlockAccount

Request Type: Personal
Response Type: Account

Unlock account in this node

ImportAccount

Request Type: ImportFormat
Response Type: Account

Import account to this node

ExportAccount

Request Type: Personal
Response Type: SingleBytes

Export account stored in this node

QueryContract

Request Type: Query
Response Type: SingleBytes

Query a contract method

QueryContractState

Request Type: StateQuery
Response Type: StateQueryProof

Query contract state

GetPeers

Request Type: PeersParams
Response Type: PeerList

Return list of peers of this node and their state

GetVotes

Request Type: VoteParams
Response Type: VoteList

Return result of vote

GetAccountVotes

Request Type: AccountAddress
Response Type: AccountVoteInfo

Return staking, voting info for account

GetStaking

Request Type: AccountAddress
Response Type: Staking

Return staking information

GetNameInfo

Request Type: Name
Response Type: NameInfo

Return name information

ListEventStream

Request Type: FilterInfo
Response Type: Event

Returns a stream of event as they get added to the blockchain

ListEvents

Request Type: FilterInfo
Response Type: EventList

Returns list of event

GetServerInfo

Request Type: KeyParams
Response Type: ServerInfo

Returns configs and statuses of server

GetConsensusInfo

Request Type: Empty
Response Type: ConsensusInfo

Returns status of consensus and bps

ChangeMembership

Request Type: MembershipChange
Response Type: MembershipChangeReply

Add & remove member of raft cluster

GetEnterpriseConfig

Request Type: EnterpriseConfigKey
Response Type: EnterpriseConfig

Returns enterprise config

GetConfChangeProgress

Request Type: SingleBytes
Response Type: ConfChangeProgress

Return a status of changeCluster enterprise tx, queried by requestID

AccountAddress
Field Type Label Description
value bytes

AccountAndRoot
Field Type Label Description
Account bytes
Root bytes
Compressed bool

AccountVoteInfo
Field Type Label Description
staking Staking
voting VoteInfo repeated

BlockBodyPaged
Field Type Label Description
total uint32
offset uint32
size uint32
body BlockBody

BlockBodyParams
Field Type Label Description
hashornumber bytes
paging PageParams

BlockHeaderList
Field Type Label Description
blocks Block repeated

BlockMetadata
Field Type Label Description
hash bytes
header BlockHeader
txcount int32
size int64 blocksize in bytes

BlockMetadataList
Field Type Label Description
blocks BlockMetadata repeated

BlockchainStatus

BlockchainStatus is current status of blockchain

Field Type Label Description
best_block_hash bytes
best_height uint64
consensus_info string
best_chain_id_hash bytes
chain_info ChainInfo

ChainId
Field Type Label Description
magic string
public bool
mainnet bool
consensus string

ChainInfo

ChainInfo returns chain configuration

Field Type Label Description
id ChainId
bpNumber uint32
maxblocksize uint64
maxtokens bytes
stakingminimum bytes
totalstaking bytes
gasprice bytes
nameprice bytes

ChainStats

ChainStats corresponds to a chain statistics report.

Field Type Label Description
report string

CommitResult
Field Type Label Description
hash bytes
error CommitStatus
detail string

CommitResultList
Field Type Label Description
results CommitResult repeated

ConfigItem
Field Type Label Description
props ConfigItem.PropsEntry repeated

ConfigItem.PropsEntry
Field Type Label Description
key string
value string

ConsensusInfo

info and bps is json string

Field Type Label Description
type string
info string
bps string repeated

Empty

EnterpriseConfig
Field Type Label Description
key string
on bool
values string repeated

EnterpriseConfigKey
Field Type Label Description
key string

EventList
Field Type Label Description
events Event repeated

ImportFormat
Field Type Label Description
wif SingleBytes
oldpass string
newpass string

Input
Field Type Label Description
hash bytes
address bytes repeated
value bytes
script bytes

KeyParams
Field Type Label Description
key string repeated

ListParams
Field Type Label Description
hash bytes
height uint64
size uint32
offset uint32
asc bool

Name
Field Type Label Description
name string
blockNo uint64

NameInfo
Field Type Label Description
name Name
owner bytes
destination bytes

NodeReq
Field Type Label Description
timeout bytes
component bytes

Output
Field Type Label Description
index uint32
address bytes
value bytes
script bytes

PageParams
Field Type Label Description
offset uint32
size uint32

Peer
Field Type Label Description
address PeerAddress
bestblock NewBlockNotice
state int32
hidden bool
lashCheck int64
selfpeer bool
version string

PeerList
Field Type Label Description
peers Peer repeated

PeersParams
Field Type Label Description
noHidden bool
showSelf bool

Personal
Field Type Label Description
passphrase string
account Account

ServerInfo
Field Type Label Description
status ServerInfo.StatusEntry repeated
config ServerInfo.ConfigEntry repeated

ServerInfo.ConfigEntry
Field Type Label Description
key string
value ConfigItem

ServerInfo.StatusEntry
Field Type Label Description
key string
value string

SingleBytes
Field Type Label Description
value bytes

Staking
Field Type Label Description
amount bytes
when uint64

VerifyResult
Field Type Label Description
tx Tx
error VerifyStatus

Vote
Field Type Label Description
candidate bytes
amount bytes

VoteInfo
Field Type Label Description
id string
candidates string repeated

VoteList
Field Type Label Description
votes Vote repeated
id string

VoteParams
Field Type Label Description
id string
count uint32

CommitStatus
Name Number Description
TX_OK 0
TX_NONCE_TOO_LOW 1
TX_ALREADY_EXISTS 2
TX_INVALID_HASH 3
TX_INVALID_SIGN 4
TX_INVALID_FORMAT 5
TX_INSUFFICIENT_BALANCE 6
TX_HAS_SAME_NONCE 7
TX_INTERNAL_ERROR 9

VerifyStatus
Name Number Description
VERIFY_STATUS_OK 0
VERIFY_STATUS_SIGN_NOT_MATCH 1
VERIFY_STATUS_INVALID_HASH 2 TODO: not yet impl

Top

blockchain.proto

ABI
Field Type Label Description
version string
language string
functions Function repeated
state_variables StateVar repeated

AccountProof
Field Type Label Description
state State
inclusion bool
key bytes
proofKey bytes
proofVal bytes
bitmap bytes
height uint32
auditPath bytes repeated

Block
Field Type Label Description
hash bytes
header BlockHeader
body BlockBody

BlockBody
Field Type Label Description
txs Tx repeated

BlockHeader
Field Type Label Description
chainID bytes chain identifier
prevBlockHash bytes hash of previous block
blockNo uint64 block number
timestamp int64 block creation time stamp
blocksRootHash bytes hash of root of block merkle tree
txsRootHash bytes hash of root of transaction merkle tree
receiptsRootHash bytes hash of root of receipt merkle tree
confirms uint64 number of blocks this block is able to confirm
pubKey bytes block producer's public key
coinbaseAccount bytes address of account to receive fees
sign bytes block producer's signature of BlockHeader

ContractVarProof
Field Type Label Description
value bytes
inclusion bool
proofKey bytes
proofVal bytes
bitmap bytes
height uint32
auditPath bytes repeated
key bytes

Event
Field Type Label Description
contractAddress bytes
eventName string
jsonArgs string
eventIdx int32
txHash bytes
blockHash bytes
blockNo uint64
txIndex int32

FilterInfo
Field Type Label Description
contractAddress bytes
eventName string
blockfrom uint64
blockto uint64
desc bool
argFilter bytes
recentBlockCnt int32

FnArgument
Field Type Label Description
name string

Function
Field Type Label Description
name string
arguments FnArgument repeated
payable bool
view bool

Query
Field Type Label Description
contractAddress bytes
queryinfo bytes

Receipt
Field Type Label Description
contractAddress bytes
status string
ret string
txHash bytes
feeUsed bytes
cumulativeFeeUsed bytes
bloom bytes
events Event repeated
blockNo uint64
blockHash bytes
txIndex int32
from bytes
to bytes

State
Field Type Label Description
nonce uint64
balance bytes
codeHash bytes
storageRoot bytes
sqlRecoveryPoint uint64

StateQuery
Field Type Label Description
contractAddress bytes
root bytes
compressed bool
storageKeys bytes repeated

StateQueryProof
Field Type Label Description
contractProof AccountProof
varProofs ContractVarProof repeated

StateVar
Field Type Label Description
name string
type string
len int32

Tx
Field Type Label Description
hash bytes
body TxBody

TxBody
Field Type Label Description
nonce uint64 increasing number used only once per sender account
account bytes decoded account address
recipient bytes decoded account address
amount bytes variable-length big integer
payload bytes
gasLimit uint64 currently not used
gasPrice bytes variable-length big integer. currently not used
type TxType
chainIdHash bytes hash value of chain identifier in the block
sign bytes sender's signature for this TxBody

TxIdx

TxIdx specifies a transaction’s block hash and index within the block body

Field Type Label Description
blockHash bytes
idx int32

TxInBlock
Field Type Label Description
txIdx TxIdx
tx Tx

TxList
Field Type Label Description
txs Tx repeated

TxType
Name Number Description
NORMAL 0
GOVERNANCE 1
REDEPLOY 2

Top

metric.proto

Metrics
Field Type Label Description
peers PeerMetric repeated

MetricsRequest
Field Type Label Description
types MetricType repeated

PeerMetric
Field Type Label Description
peerID bytes
sumIn int64
avrIn int64
sumOut int64
avrOut int64

MetricType
Name Number Description
NOTHING 0 NOTHING should not be used.
P2P_NETWORK 1 Metric for p2p network transfer

Scalar Value Types

.proto Type Notes C++ Type Java Type Python Type
double double double float
float float float float
int32 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. int32 int int
int64 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. int64 long int/long
uint32 Uses variable-length encoding. uint32 int int/long
uint64 Uses variable-length encoding. uint64 long int/long
sint32 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. int32 int int
sint64 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. int64 long int/long
fixed32 Always four bytes. More efficient than uint32 if values are often greater than 2^28. uint32 int int
fixed64 Always eight bytes. More efficient than uint64 if values are often greater than 2^56. uint64 long int/long
sfixed32 Always four bytes. int32 int int
sfixed64 Always eight bytes. int64 long int/long
bool bool boolean boolean
string A string must always contain UTF-8 encoded or 7-bit ASCII text. string String str/unicode
bytes May contain any arbitrary sequence of bytes. string ByteString str