Skip to main content

Update a dapp chain

Dapps evolve over time. This section discusses how to update a dapp chain to a new version seamlessly.

There are two approaches to updating a chain:

  • Specify different config entry points for old and new versions, or
  • Reference compiled configuration of the old version

Project structure before the update

We use an example project with a basic ft3 structure for both approaches

You have all the chain's code within the rell/src folder:

rell/src
├── lib
│ ├── ft3
│   └── … (other optional libraries)
└── module.rell

And config.template.xml must look like the following:

<run wipe-db="true">
<nodes>
<config src="../../node-config.properties" add-signers="true" />
</nodes>
<chains>
<chain name="YOUR_CHAIN_NAME" iid="0">
<config height="0">
<app module="">
<args module="lib.ft3.core">
<!-- ... (your chain configs) -->
</args>
</app>
</config>
</chain>
</chains>
</run>

Update by specifying different entry points

Use this approach to have a clear overview of the old version's code.

note

An example project to demonstrate this approach is available at branch example/update-chain-keep-old-code of develop-chromia:

git clone https://bitbucket.org/chromawallet/develop-chromia.git
git checkout example/update-chain-keep-old-code

Restructure the code

As mentioned earlier, this approach's target is to have a clear overview of old code after several updates. Creating different entry modules for each chain version is an excellent procedure.

We name each module with the current version tag so that it's clear what's run in the past. After that, we need to update the config.template.xml file by adding each version configuration and the height at which the changes become effective.

The Rell structure then looks like the following:

rell/src
└── v0_0_1
├── lib
│ ├── ft3
│   └── … (other optional libraries)
└── module.rell

So essentially, we just created a folder v0_0_1 inside src and moved all the previous files there.

We need to update the config.template.xml file to reflect this change. Note the change at <app> and <arg> tags:

<run wipe-db="true">
<nodes>
<config src="../../node-config.properties" add-signers="true" />
</nodes>
<chains>
<chain name="YOUR_CHAIN_NAME" iid="0">
<config height="0">
<app module="v0_0_1">
<args module="v0_0_1.lib.ft3.core">
<!-- ... (your chain configs) -->
</args>
</app>
</config>
</chain>
</chains>
</run>
note

As a matter of information, the project's entry path is available under postchain/config/nodes/dev/blockchains/app/entry-file.txt.

Confirm the new configuration is working properly by starting the chain:

./postchain/bin/run-node.sh dev

Add new code

Now that you've restructured the code, you can upgrade the code. To do that, you must copy the v0_0_1 folder and rename it as v0_0_2.

rell/src
├── v0_0_1
│ ├── lib
│ │ ├── ft3
│ │   └── … (other optional libraries)
│ └── module.rell

└── v0_0_2
├── lib
│ ├── ft3
│   └── … (other optional libraries)
└── module.rell

For easy testing, you can add one new query in the module.rell file of v0_0_2:

module;

import lf: .lib.ft3.ft3_basic_dev;

query get_version() {
return "0.0.2";
}

If everything works correctly, you need not receive any response when running the module v0_0_1 but you receive 0_0_2 when running the module v0_0_2.

Set the migration to a new module

To migrate to the new module, you need to update the config.template.xml file.

You add a new <config> tag inside the <chain>, and enable at a certain (block) height:

<run wipe-db="true">
<nodes>
<config src="../../node-config.properties" add-signers="true" />
</nodes>
<chains>
<chain name="YOUR_CHAIN_NAME" iid="0">
<config height="0">
<app module="v0_0_1">
<args module="v0_0_1.lib.ft3.core">
<!-- ... (your chain configs) -->
</args>
</app>
</config>
<config height="20">
<app module="v0_0_2">
<args module="v0_0_2.lib.ft3.core">
<!-- ... (your chain configs) -->
</args>
</app>
</config>
</chain>
</chains>
</run>

In this example, after 20 blocks, the chain changes app module to v0_0_2.

caution

Ensure that the block height for the new configuration is safely higher than the current height. Setting a block height lower than the current height might cause problems for nodes that want to sync by re-applying all the transactions.

Test the chain

Start the chain with

./postchain/bin/run-node.sh dev

Recall the new query get_version() we created earlier. We can test the chain's version with a simple script such as:

const pcl = require("postchain-client");
const node_api_url = "http://localhost:YOUR_NODE_PORT";

// default blockchain identifier used for testing
const blockchainRID = YOUR_NODE_BRID;

const rest = pcl.restClient.createRestClient(node_api_url, blockchainRID, 5);
const gtvHash = pcl.gtv.gtvHash;

const gtx = pcl.gtxClient.createClient(
rest,
Buffer.from(blockchainRID, "hex"),
[]
);

const gtv = pcl.gtv;
const gtxU = pcl.gtx;

(async () => {
try {
const version = await gtx.query("get_version", {});
} catch (e) {
console.log("New version not yet implemented");
} finally {
if (version) {
console.log(`New version running: ${version}`);
}
}
})();

We can monitor the blockchain by linking it to the Explorer :

At block 20, you start getting a result back from the chain. It returns something like this:

POST URL http://localhost:7743/query/A54320E7D063AB94513467806FE800A1B95B26BF65C4F11D30C5D65859E4025C

0.0.2

Update by referencing the old configuration

You can use the second approach to specify previously compiled configurations in the config tag.

Use this approach if you want a cleaner code structure.

note

An example project to demonstrate this approach is available at branch feature/CCD210-update-chain-tutorial of develop-chromia:

git clone https://bitbucket.org/chromawallet/develop-chromia.git
git checkout feature/CCD210-update-chain-tutorial

What does run-node.sh do?

To discuss this approach, we must first explain what happened when you execute ./postchain/bin/run-node.sh dev in the console.

This command does three things.

  1. First, it creates a target folder where the compiled blockchain configuration is available, something like:
mkdir -p ./postchain/runtime/nodes/dev
  1. Then it generates the blockchain configuration by compiling the Rell code with the config.template.xml file.

The BRID is also generated at this step if it's a new chain (started with the -W option). You don't want the BRID to change, so you must not use the -W option while updating the chain.

./postchain/lib/multigen.sh ./postchain/config/nodes/dev/blockchains/app/config.template.xml -d ./rell/src -o ./postchain/runtime/nodes/dev/

It should create the following architecture inside postchain/runtime/nodes/dev:

postchain/runtime/nodes/dev
├── blockchains
│ └── 0
│ ├── 0.gtv (creates a one file rell module)
│ ├── 0.xml (creates the configuration that will be run, also by using the just created 0.gtv)
│ └── brid.txt (just a file where is output the brid of the chain, n.b. it will remain constant nevertheless the updates)

├── node-config.properties
└── private.properties
  1. Finally, it runs the new configuration with
./postchain/lib/postchain.sh run-node-auto -d ./postchain/runtime/nodes/dev

Backup old configuration

Compile the current code (by executing ./postchain/bin/run-node.sh dev or only steps 1 and 2 described above).

In the generated configuration folder, copy runtime/nodes/dev/0.xml into postchain/config/nodes/dev/blockchains/app, and rename it 0.0.1.xml.

Adding new codes

In the previous approach, you kept track from a code point of view of previous versions. You don't have to do that this time, so you can change the code directly without copying anything.

Add the following query in the module.rell file:

module;

import lf: .lib.ft3.ft3_basic_dev;

query get_version() {
return "0.0.2";
}

Set the migration to a new module

Update the config.template.xml file to config the migration.

Note that, unlike the other approach, this time, you don't have to change the <app> and <args> tags:

<run wipe-db="true">
<nodes>
<config src="../../node-config.properties" add-signers="true" />
</nodes>
<chains>
<chain name="YOUR_CHAIN_NAME" iid="0">
<config height="0">
<gtv src="0.0.1.xml"/>
</config>
<config height="20">
<app module="">
<args module="lib.ft3.core">
<!-- ... (your chain configs) -->
</args>
</app>
</config>
</chain>
</chains>
</run>
info

Ensure that the block height for the new configuration is safely higher than the current height. Setting a block height lower than the current height might cause problems for nodes that want to sync by re-applying all the transactions.

Compile the new configuration and start the chain:

./postchain/bin/run-node.sh dev

We can now Test the chain as before. If you try to query for get_version() after block 20, you must see 0.0.2.