Blockchain in a shell

Simon Jentzsch
slock.it Blog
Published in
4 min readMar 9, 2020

Have you ever tried to send a transaction directly in your shell? Or how about a shell script running as a cron job, which reads events from the chain?

Of course, you can run and sync a local node and then run a curl command against your node:

curl -H "Content-Type:text/json" -X POST -d '{"method":"eth_getTransactionReceipt","params":["0xbbb6223001678b8694acaa13dc597692485598cd0a5310bce975418c54b65f14"],"id":1,"jsonrpc":"2.0"}' https://localhost:8545 | jq -r .result

Not nice, but since your full client is running, you should be able to trust the response. But what if you can’t or don’t want to run a local node and also don’t want to rely on a centralized remote service?

Incubed is a stateless minimal verification client you can directly use in your shell. The same request would look like this:

in3 eth_getTransactionReceipt 0xbbb6223001678b8694acaa13dc597692485598cd0a5310bce975418c54b65f14

Incubed doesn’t need any syncing node since it connects with the Incubed network and locally verifies the responses. You can learn more about how this works here.

Installing

The in3 executable is only 300 kB big and includes all you need (even the complete EVM) to fetch and verify data.

For Linux:

# Add the slock.it ppa to your system
sudo add-apt-repository ppa:devops-slock-it/in3
# install the commandline tool in3
apt-get install in3

For MacOS:

# Add a brew tap
brew tap slockit/in3
# install all binaries and libraries
brew install in3

For Windows:

Just download the latest release from https://github.com/slockit/in3-c/releases

For Docker:

docker run slockit/in3 eth_getBlockByNumber latest false

By the way, the whole Docker image is only 2.8 MB!

Let’s Play

Once installed, you can do most things you usually would do with the web3.js-library and even more on the command line.

Let’s get the first transaction of the latest block:

in3 eth_getBlockByNumber latest true | jq ‘.transactions[0]’

If you want to call a function of a contract, in3 will use the ABI encoder:

in3 call -to 0xbb9bc244d798123fde783fcc1c72d3bb8c189413 "numberOfProposals():uint"

In order to send a transaction, you can specify a keyfile. Incubed will then ask for your passphrase to decrypt it. You could also pass a raw key or add the password as an argument, but this is, of course, not recommended.

in3 send -pk mykeyfile.json -to 0x27a37a1210df14f7e058393d026e2fb53b7cf8c1 -gas 1000000 "registerServer(string,uint256)" "https://in3.slock.it/kovan1" 0xFF

Deploying contracts works the same way. You can even pipe the output of the Solidity compiler directly into Incubed. This command would compile, deploy a contract, wait until it is mined (-w option), and then return the transaction receipt, where we use the contractAddress.

CONTRACT=`solc — bin MyContract.sol | in3 send -gas 5000000 -pk my_private_key.json -d — -w | jq -r .contractAddress`

I have used this to create shell scripts for preparing test enviroments.

Even offline verifications are possible. You can pipe the proofs into a file, put it on a USB stick, and then verify the response on a different machine with no internet connection.

# getting the proof
in3 –ro eth_getTransactionReceipt 0x2736D225f85740f42D17987100dc8d58e9e162528d58e9e162 > proof.json
# verifying the proof
in3 –ri eth_getTransactionReceipt 0x2736D225f85740f42D17987100dc8d58e9e162528d58e9e162 < proof.json

If you like your shell and need to sign data, you can use the signing features:

in3 sign -st hash -pk my_private_key.json 0x487b2cbb7997e45b4e9771d14c336b47c87dc2424b11590e32b3a8b9ab327999

Or use ecrecover of a signature to verify the signature and find out who signed it:

in3 ecrecover -st hash 0x487b2cbb7997e45b4e9771d14c336b47c87dc2424b11590e32b3a8b9ab327999 0x0f804ff891e97e8a1c35a2ebafc5e7f129a630a70787fb86ad5aec0758d98c7b454dee5564310d497ddfe814839c8babd3a727692be40330b5b41e7693a445b71c

Incubed is a multichain client, so you can simply define the chain you want to work with by using the option -c goerli. In case you are running a test against your local client (maybe using a dev-chain), you can also specify ‘local’ (or the URL of your client).

in3 -c local eth_getBlockByNumber latest true 
| jq '.transactions[0]'

If you have a dApp that is connecting to a client running on localhost:8545 and you can’t or don’t want to sync a node, specifying the port will start Incubed as a proxy node and a replacement for a full or light client, but still verifying each request:

in3 -c goerli -s 1 -port 8545

Or as Docker :

docker run -p 8545:8545 slockit/in3 -c goerli -s 1 -port 8545

ENS

Addresses are good, but names are better. Using ENS in a shell is supported for all commands, and wherever you may use an address, domain names are accepted as well.

in3 call -to cryptokitties.eth "pregnantKitties():uint"

Autocompletion

Autocompletion can increase productivity on the shell. For Incubed, there is simple support for Bash, which you should include in your .bashrc:

_IN3_WORDS=`in3 autocompletelist`
complete -W "$_IN3_WORDS" in3

Or for zsh, the more advanced completion:

curl https://raw.githubusercontent.com/slockit/in3-c/develop/scripts/_in3.sh > /usr/local/share/zsh/site-functions/_in3.sh

There are a lot more features in these 300k, so give it a try and check out https://in3.readthedocs.io/en/develop/api-cmd.html

Simon Jentzsch
(CTO, slock.it and VP of Blockchain Development at Blockchains LLC)

--

--