Photo by Todd Quackenbush on Unsplash

Command Line Tools for RSK Node

Today I was working adding some command line entry points to rskj implementation. My work is in the branch cliutils based on a release candidate 2.0.

Update: Today (September 9th 2020) a new RSKJ release was published. It includes the command line tools described in this post. The main difference is that the package name was changed to co.rsk.cli.tools .

The new release blog post at https://blog.rsk.co/noticia/papyrus-release-v2-1-0-is-here/

Exporting Blocks

In some of my experiments I want to have a range of blocks in hexadecimal format. Now, I can execute

java -cp rsk.jar co.rsk.ExportBlocks 500000 510000 --testnet

In each output line, there is four fields:

  • Block number
  • Block hash (hexadecimal)
  • Block TOTAL difficulty (hexadecimal)
  • Encoded Block (hexadecimal)

Notice that the total difficulty IS NOT part of the serialized block: it is a value calculated by each node, that adds the block difficulty to the TOTAL difficulty of its parent. The block with better total difficulty wins in the consensus algorithm.

Which could be the use case for this utility? To dump some blocks (from mainnet, testnet or local network) and then re-execute them many times, taking performance and memory usage. So, I can experiment with different algorithms for key value cache in block execution, or trie save, or transaction execution, with a repeatable block range.

Import Blocks

Using a file generated with the previous command, using a redirection

java -cp rsk.jar co.rsk.ExportBlocks 500000 510000 --testnet > blocks.txt

you can import the blocks into another node:

java -cp rsk.jar co.rsk.ImportBlocks blocks.txt --testnet

The nodes will be added to the node block store WITHOUT validating or executing them, and marked as the best block at their heights. I should explore the options:

  • Add the blocks to the block store, but without marking them as members of the best chaing
  • Add the blocks executing them (maybe this case deserves a separated command)

Execute Blocks

Having the blocks within the node block store, you can (re)execute them using:

java -cp rsk.jar co.rsk.ExportBlocks 500000 510000 --testnet

One interesting use case: generates the logs with detailed information, or run the command with some internal metrics activated. Also, it could repair a database that have some trie missing. Executing the blocks does not imply their adding to the blockchain (the above comamnd execute blocks ALREADY in blockchain), and does not save the generated receipts.

Export State

Recently I did memory and performance research with my personal blockchain project (read Trie Memory and Performance Experiments). Also, I explained the use of the trie as world state (read A Simple Trie Pruning Algorithm). To execute a new block, the state (account, storage, code) at the end of its parent block should be known. In Ethereum and in my implementation, that state is in many stores (I prefer that way: clear separation of concerns for storage), but the process is the same: export the full state at an specified height.

For RSK I just wrote another entry point:

java -cp rsk.jar co.rsk.ExportState 500000 --testnet

to dump the full state to standard output, according to the state at the end of execution of block 500_000.

Show State Information

This command outputs state information:

java -cp rsk.jar co.rsk.ShowStateInfo 100 --testnet

The output:

Block: 100
Block hash: 4161f4279871f416ad98aacac781532a52927119133c30594740606c46cc1ed0
Root hash: f700679bdcbe6e892d509d0753135166396d6ba75f4e2d947ac1eb14dc2440c3
Trie nodes: 45
Trie long values: 0
Trie MB: 0.0018596649169921875

(In RSK, the node values, if huge, could be saved alone; I could name them the long values).

It is interesting to discover, that in many cases, the state of a block is light compared with the state of the full blockchain.

Import State

Given a file with the exported state, this command reads the states and save them into the node database.

I should write this command, yet.

Update: in the current RSK release (mentioned at the beginning of this post) this command is included:

java -cp rsk.jar co.rsk.tools.cli.ImportState statefile.txt --testnet

Connect Blocks

Loads blocks from a file, and executes them using the blockchain process. If they are valid, they are saved. If they are the best blocks, they are added to the blockchain. Their receipts with logs are saved.

Example

java -cp rsk.jar co.rsk.ConnectBlocks blocks.txt --testnet

The provided file should be the format of the output of ExportBlocks command. The parent of the first block should be already present withing the node database (you can import it using ImportBlocks command). Also, some blocks before that first parent, because they are needed by the REMASC smart contract logic: 10 blocks in regtests, 50 blocks in testnet, and 4000 blocks in mainnet. And the full state at the end of the parent block should be in the node database: you can use ImportState commands.

Use cases

Suppose you want to start a new node, running in mainnet, but without executing the long synchronization process. Well, if you or anyone has a synchronized node, you can export the state at height H, then export the block in main chain at that height. So, in the new node, you can import the block, the full state of that node at the end of its execution. When you launch the node, it could start the synchronization SINCE that block. No need to run all the previous ones.

Or you can do a performance run, to get a report, using different releases, but using the same block data. So, you can export the state at block 2_000_000 from mainnet, and then, export the blocks from 2_000_000 to 2_100_000. Now, at any moment, you can import the state into the test node, import the first block 2_000_000 and (re)execute the rest of blocks, the times you need.

To Do

I should write a post with detailed step by step instructions to get a clone of other node, ie testnet or mainnet, using few exported blocks and one state.

Angel “Java” Lopez