DEV Community

CoinMonks
CoinMonks

Posted on • Originally published at Medium on

Web3.py: From Ganache to Infura

Photo by Shahadat Rahman on Unsplash

You can find the full code for this tutorial here

I have been experimenting with smart contracts for some time but until recently I was only using Ganache (a personal development blockchain) to test things. Ganache is great for development and testing purposes, but any serious project eventually needs to be moved to a testnet for further testing. In this article, I will go through the changes I needed to make to my code in order to deploy and interact with my smart contracts on the Ropsten testnet using a hosted node like Infura.

You don’t necessarily need to use Infura to deploy a smart contract on the testnet. Some people chose to run their own nodes, and I imagine the transition from Ganache to a local node would be really smooth with the only code change being the web3 provider. Unfortunately, running a local node requires a lot of storage, computation and bandwidth and therefore not everyone is willing to do it. So for most, the only option is to use a hosted node like Infura. Using Infura requires some change to our code however.

In order to illustrate these changes, let’s start with a really simple smart contract that just stores a number and allows anyone to change it. The contract will also emit an event informing listeners that the number has changed.

contract darkPool {
  uint public num;

  event chage(uint number);

  function set(uint _num) external {
    num = _num;
    emit change(num);
  }
}
Enter fullscreen mode Exit fullscreen mode

Next, we will see the changes we need to make to deploy our contract, send transactions and listen to events when using a hosted node.

The first change in our code should be the web3 provider. Using Ganache we usually have something like this:

w3 = Web3(HTTPProvider("[http://127.0.0.1:8545](http://127.0.0.1:8545)"))
Enter fullscreen mode Exit fullscreen mode

Using Infura is not much different, we just need to provide the Infura endpoint for our project, which can be found under project settings in Infura, and should look something like this for the Ropsten testnet:

w3 = Web3(HTTPProvider("https://ropsten.infura.io/v3/<PROJECT ID>"
Enter fullscreen mode Exit fullscreen mode

The next change we need to make, is in the way we deploy our contract. Using Ganache we just call the constructor:

tx_hash = contract.constructor().transact()
Enter fullscreen mode Exit fullscreen mode

Using a hosted node, we can't just do that since the node doesn’t manage our keys for us so we need to do a bit more work. We first need to build the transaction providing some parameters like the ones below, then sign it using our private key and finally send it to the node:

# build transaction
build_tx = contract.constructor().buildTransaction({
    'from': ...,
    'nonce': ...,
    'gas': ...,
    'gasPrice': ...
})
private_key = ...
# sign transaction
sign_tx = w3.eth.account.signTransaction(build_tx, private_key)
# send the transaction
tx_hash = w3.eth.sendRawTransaction(sign_tx.rawTransaction)
Enter fullscreen mode Exit fullscreen mode

Executing functions locally (i.e. calls) remains the same, so getting the current number stored in our contract is the same for both Ganache and Infura:

num = contract.functions.num().call()
Enter fullscreen mode Exit fullscreen mode

Executing functions by sending transactions on the other hand is again different (as we saw with the contract constructor). Using Ganache we simply write:

tx_hash = contract.functions.set(num).transact()
Enter fullscreen mode Exit fullscreen mode

To run the same thing on the testnet using Infura, we can do the following:

num = ...
# build transaction
build_tx = contract.functions.set(num).buildTransaction({
    'from': ...,
    'nonce': ...,
    'gas': ...,
    'gasPrice': ...
})
# sign transaction
sign_tx = w3.eth.account.signTransaction(build_tx, private_key)
# send the transaction
tx_hash = w3.eth.sendRawTransaction(sign_tx.rawTransaction)
Enter fullscreen mode Exit fullscreen mode

Finally, when using a local node, we can create event filters and later get all published events. Using Ganache we can do the following:

filter = contract.events.change.createFilter(fromBlock="latest")

...

changes = filter.get_new_entries()
Enter fullscreen mode Exit fullscreen mode

Our connection to Infura on the other hand is stateless so we can’t do the same. An alternative that works is:

start = ... # the block from which to start getting logs
changes = contract.events.change.getLogs(fromBlock=start)
Enter fullscreen mode Exit fullscreen mode

I spent some time trying to figure how to make my code work the first time I tried to test a smart contract on the testnet. Hopefully, this article (and the accompanying code) will save you the trouble!


Top comments (0)