Incubed for Python, Batteries Included

J. Paul R. Depraz
slock.it Blog
Published in
8 min readMay 15, 2020

Python gets the lightest blockchain client out there.

A comprehensive standard library powered Python’s “batteries included” motto in the 90s; 10 years later, the scientific community project SciPy rose in popularity by hosting Pandas, Numpy and other broadly adopted tools. More recently, AI and data mining demands inspired the creation of Jupyter, an interactive notebook that combines SciPy with gorgeous graphics and simulations.

In the Ethereum ecosystem, the language is also well-regarded: used for the first reference-implementation of its virtual machine, and now for its second, Trinity client for version 2.0 of the protocol. It inspired Vyper, a pythonic smart contract language; it’s used in Casper, the proof-of-stake consensus algorithm; and continues to be Vitalik’s weapon of choice.

Python is the №1 Googled programming language, according to Github’s “PYPL PopularitY of Programming Language.” When all search engines are considered, it is in the top three, along with C and Java, in the TIOBE index.

The Incubed network is designed to empower battery-powered devices, like smart phones and IoT devices, to efficiently transact on-chain as trustless as if operating a blockchain client onboard. It encourages dApp developers to run the Incubed Server, become part of the network, and contribute to the whole community that needs a stable blockchain API.

Incubed is the first blockchain client of its kind, supporting the decentralization of APIs by incentivizing the users to host them and help provide the community with access to reliable infrastructure.

Incubed adds a user maintained access layer for applications to send and gather verifiable data from Ethereum based blockchain networks and will provide access to other financial services in the future.

Participating in the network will not only guarantee extra security for decentralized applications, but help a myriad of other companies, individuals, devices, and systems to access verifiable blockchain data on demand.

The client is developed in C and ported to multiple platforms, including ARM and operating systems like Linux, Windows, and MacOS. The shared libraries contain an API for RPC that makes it easy for writing tools in higher-level programming languages, as we did with Java, C#, Javascript, and Python.

This means that with Python you can use Incubed on a Raspberry Pi the same way you would in a Windows machine — not a single additional line of code!

Well, I guess it became self-evident that we love both Python and Incubed, now let’s see get down to business!

For advanced Python and blockchain users, ReadTheDocs has the complete technical documentation of the tool.

Install Incubed for Python and run the Python interpreter:

system-wide:
pip3 install in3
python3

project-scope only:
virtualenv -p python3 venv
source venv/bin/activate
pip install in3
python

The library files are now installed, and the ominous >>> on the interpreter is waiting for a command.

Commands will be displayed as though they were written in the Python interpreter. Real scenarios would be wrapped in try-catch blocks, respect pep8 style guidelines, and so forth. We will keep it simple.

Next, import the Incubed library and initiate the client. It will load the Incubed shared library for the host system and configure it to communicate with the Ethereum main network.

import in3
client = in3.Client()

No error messages means it supports the host system. The client has yet to make a network request until now, however, there are some important things to consider before we move on to executing more commands.

Every time a new instance of the client is created, it will check for a previously cached index of network nodes to keep in memory. Nodes are community maintained and can be in downtime, misconfigured, or off sync; therefore, every client must administer its own list telling how much they are inclined to ask for an individual node to attest blockchain data.

From time-to-time (and certainly the first time you ask for ‘live’ data from the network), the client will request an updated list of nodes in the Incubed registrar smart contract. This is the decentralized source-of-truth for who can participate in the Incubed network. You can check the client’s known nodes by executing client.config()or by requesting an updated node list with client.refresh_node_list().

Let’s continue to request the latest block and print it on the console.

block: in3.eth.Block = client.eth.block_by_number('latest')
import json
print(json.dumps(block.to_dict(), indent=4, sort_keys=True))

An Ethereum block is beautifully printed with a long list of transaction hashes on your terminal. If it fails the first time, worry not, simply try again. The reason being, as the network gets larger and the client instance continues to blacklist unresponsive nodes, it gets more stable — that is the goal!

We used a Python3 feature called annotation to inform the user and the IDE that the object type return is an Ethereum block. An advanced tool like PyCharm would already know the return type of this variable as it is already annotated in the function declaration.

All Ethereum API calls are available over client.eth for general network data,client.eth.account for creating accounts and sending transactions, and client.eth.contract for smart contract interactions.

Time to send our first transaction in the Görli Test Network:

import in3
client = in3.Client('goerli')
sender = client.eth.account.create()
print(sender)

Alternatively, use your own account (i.e.from Metamask) by pasting the private key in the secret field. Be sure it contains the 0x prefix.

secret='0xbeef'
sender=client.eth.account.recover_account(secret)

This first bit will create a new account locally. Copy the printed value and get you some Test Eth funds from our Görli Faucet.

Now execute print(client.eth.account.balance(str(sender))) until the balance is positive. We’ve provided you with test ETH to spend, let’s do it!

receiver = "0x0b56Ae81586D2728Ceaf7C00A6020C5D63f02308"
tx = in3.eth.NewTransaction(to=receiver, value=1463926659)
tx_hash = client.eth.account.send_transaction(sender, tx)
print('https://goerli.etherscan.io/tx/{}'.format(tx_hash))

You’ll know the transaction was accepted by the network, including both Incubed and Görli, if it printed the transaction link, but this doesn’t mean that the funds left the account. We must wait for the transaction receipt that confirms it was mined and tells us how much gas it spent, along with other important details.

Follow the link, or repeatedly try getting the transaction receipt via Incubed:

receipt = client.eth.transaction_receipt(tx_hash)
print(json.dumps(receipt.to_dict(), indent=4, sort_keys=True))

Görli is pretty fast, but Ethereum transactions can take several minutes to be mined, depending on how much additional gas is set as transaction fee. The send_transaction command sets it automatically for the user.

That was your first Ethereum transaction over Incubed, or at least with Python. Congratulations!

You’ve seen how creating a new account and casually sending funds is very fun. Still, the crème de la crème of blockchain are smart contracts and all the possibilities it brings to financial services and internet decentralization. To start, let’s take a loot at ENS.

ENS stands for the Ethereum Name Service and is the community-driven version of DNS, available in the Ethereum main network and some of the test chains. The main registry smart contract resolves a domain name to its delegated resolver contract that can be customized by the domain owner. See UML diagram for an example.

To register a name in Görli, just get more funds from the faucet in a Metamask account, and use the ENS dApp to get your own domain.

UML sequence diagram of how Ethereum Name Service (ENS) resolves a name.

source: https://docs.ens.domains/

Back to the terminal, let’s use Incubed client.eth.contract module to print the registered resolver contract address of a valid ENS registry. If you already registered a domain, replace depraz.eth with your domain name, and check if the resolver contract address match.

client = in3.Client('goerli')domain_name = client.ens_namehash('depraz.eth')
ens_registry_addr = '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e'
ens_resolver_abi = 'resolver(bytes32):address'
tx_data = client.eth.contract.encode(ens_resolver_abi, domain_name)
resolver_tx = {
"to": ens_registry_addr,
"data": tx_data
}
tx = in3.eth.NewTransaction(**resolver_tx)
encoded_resolver_addr = client.eth.contract.call(tx)
client.eth.contract.decode(ens_resolver_abi, encoded_resolver_addr)

This piece of code is a bit complex, so let’s break it down.

All actions in a blockchain happen by sending transactions. When a transaction triggers a state change, like moving funds, storing data, or changing smart contract code, there is a cost to do so. However, there is no cost to retrieve data, that is why the transaction value is blank.

When executing code in a remote application, we need to know the function name we will call, the parameters it expects to receive, as well as whatever it may return. That is what the ens_resolver_abi describes.

The encode and decode methods use this function descriptor to translate data sent to and from the Ethereum Virtual Machine (EVM). The EVM is one of the main components of Incubed; whenever the user calls a smart contract function, the client will ask the network for an attested copy of that code, execute it with given parameters, and return the calculated value.

Incubed does not trust the network response, but gathers all necessary information to execute the EVM code and verify that the answer is correct.

ENS is an essential part of the Ethereum ecosystem, and Incubed wouldn’t be a great tool if you had to write all that code to resolve names, right?

client.ens_resolver('depraz.eth')

Voilá! Find the domain name owner by calling client.ens_owner, and the account address that the domain points to with client.ens_address.

The ENS smart contract snippet is part of the examples. Try them out!

Another great feature of the client that Python enhances is the modular transport function. The network of Incubed nodes only listens to HTTP requests, but maybe you’re running the client on a smartwatch and can only connect over Bluetooth to a smartphone. We’ve got you covered! Simply write a transport function that will handle the Bluetooth communication and pass it to the client.

client = in3.Client(transport=bluetooth_transport)

On the smartphone watch app you wrote, the messages received from the smartwatch must have all information needed to make the HTTP requests to the Incubed network over the internet and route back the responses over Bluetooth to the Incubed client in the smartwatch.

You can now set up your smartwatch to pay yourself some ETH each time you complete that morning exercise you committed yourself to doing. Incentivized workout could be a revolution!

This Python distribution was developed with PEP20, the Zen of Python, in mind, and we plan to refine and enhance it while maintaining our respect for this philosophy. If you have suggestions and feedback, we’d love to hear it!

The Zen of PythonBeautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
...

Thank you for hanging until the end of the tutorial! We appreciate it and hope you had fun learning about our Ethereum tools.

We are planning new releases of the Python bindings with new features, facilitators, a more intuitive account and smart contract interfaces, Bitcoin support, and more. Stay tuned!

For the complete Incubed technical documentation visit ReadTheDocs.

To push Web3.0 further, we also maintain a WASM distribution. Try it!

If you simply want to fiddle with Incubed before adding it to your project, we highly recommend trying the command-line tool.

We also support other Incubed releases, check them on Github.

--

--