Using the Ethereum Web3 client in Python

Ethereum - Web3

Similar to the RPC client, I will use the web3 API to make a transaction on my private blockchain.

In [1]:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

I willl use the Python 2.7 environment since Python 3.6 is not yet supported.

In [2]:
import sys
sys.version
Out[2]:
'2.7.13 |Anaconda 4.3.1 (64-bit)| (default, Dec 20 2016, 23:09:15) \n[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]'
(python2) [email protected]:~$ pip install web3
Collecting web3
Requirement already satisfied: requests>=2.12.4 in /home/jitsejan/anaconda3/envs/python2/lib/python2.7/site-packages (from web3)
Collecting ethereum-utils>=0.2.0 (from web3)
Requirement already satisfied: pysha3>=0.3 in /home/jitsejan/anaconda3/envs/python2/lib/python2.7/site-packages (from web3)
Collecting ethereum-abi-utils>=0.4.0 (from web3)
Requirement already satisfied: rlp>=0.4.7 in /home/jitsejan/anaconda3/envs/python2/lib/python2.7/site-packages (from web3)
Collecting pylru>=1.0.9 (from web3)
Installing collected packages: ethereum-utils, ethereum-abi-utils, pylru, web3
Successfully installed ethereum-abi-utils-0.4.0 ethereum-utils-0.2.0 pylru-1.0.9 web3-3.8.1

Note: make sure geth is started with arguments --rpc and --rpcapi="db,eth,net,web3,personal,web3"

[email protected]:~$ geth --networkid 23 --nodiscover --maxpeers 0  --port 30333 --rpc --rpcapi="db,eth,net,web3,personal,miner"
In [3]:
import web3
from web3 import Web3, KeepAliveRPCProvider, IPCProvider
web3.__version__
Out[3]:
'3.8.1'

Setup RPC connection

In [4]:
web3 = Web3(KeepAliveRPCProvider(host='localhost', port='8545'))

Retrieve the accounts

In [5]:
web3.eth.accounts
Out[5]:
[u'0x8cf9deda0712f2291fb16739f8759e4a0a575854']
In [6]:
address = web3.eth.accounts[0]

Set the two other machines

In [7]:
address_vps_one = "0xc257beaea430afb3a09640ce7f020c906331f805"
address_vps_two = "0xe86ee31b7d32b743907fa7438c422a1803717deb"

Show their balances

In [8]:
print "Host has %d Ether"% web3.fromWei(web3.eth.getBalance(address), 'ether')
print "VPS 1 has %d Ether" % web3.fromWei(web3.eth.getBalance(address_vps_one), 'ether')
print "VPS 2 has %d Ether" % web3.fromWei(web3.eth.getBalance(address_vps_two), 'ether')
prev_host_amount = float(web3.fromWei(web3.eth.getBalance(address), 'ether'))
Host has 411 Ether
VPS 1 has 150 Ether
VPS 2 has 83 Ether

Transaction

Lets send 12 Ether from the main machine to VPS one.

In [9]:
amount = 12 # Ether
sending_address = address
receiving_address = address_vps_one

Get the password to unlock the sending account

In [10]:
from getpass import getpass  
pw = getpass(prompt='Enter the password for the sender: ')
Enter the password for the sender: ········

Unlock the account

In [11]:
web3.personal.unlockAccount(address, pw)
Out[11]:
True

Create the transaction

In [12]:
params = {}
params['to'] = receiving_address
params['from'] = sending_address 
params['value'] = web3.toWei(amount, "ether")
tx_hash = web3.eth.sendTransaction(params)

Check the transaction

In [13]:
web3.eth.getTransaction(tx_hash)
Out[13]:
{u'blockHash': u'0x0000000000000000000000000000000000000000000000000000000000000000',
 u'blockNumber': None,
 u'from': u'0x8cf9deda0712f2291fb16739f8759e4a0a575854',
 u'gas': 90000,
 u'gasPrice': 20000000000,
 u'hash': u'0x46e0a5a96dbea0391adbfd401b087ad1d1dfb120684462d8652df7d8b8d7f069',
 u'input': u'0x',
 u'nonce': 24,
 u'r': u'0x63d0a6d39e9f57bf42e874bb268fc11c67cdb72d86cd21a65181b48063ddb531',
 u's': u'0x44bb390959b28e0f14d4a7891b5ac44c84816a69c2434aeafdc5c94a42997b2b',
 u'to': u'0xc257beaea430afb3a09640ce7f020c906331f805',
 u'transactionIndex': 0,
 u'v': u'0x42',
 u'value': 12000000000000000000L}

Check the receipt

The miner is not running, so the receipt returns nothing

In [14]:
web3.eth.getTransactionReceipt(tx_hash)

Start and stop the miner

Note: web3.admin.sleepBlocks seems not te be available so I use a simple sleep. Within this sleep it could be that there are more than 1 mining cycles.

In [15]:
import time
miner = web3.miner
miner.start(1)
time.sleep(5)
miner.stop()
Out[15]:
True

Check the receipt again

Now the transaction has taken place

In [16]:
web3.eth.getTransactionReceipt(tx_hash)
Out[16]:
{u'blockHash': u'0x635486b2100a4a9de155b57c1a9fad4dfafcf1db1d62f9aa55bd38d6a3864869',
 u'blockNumber': 110,
 u'contractAddress': None,
 u'cumulativeGasUsed': 21000,
 u'from': u'0x8cf9deda0712f2291fb16739f8759e4a0a575854',
 u'gasUsed': 21000,
 u'logs': [],
 u'logsBloom': u'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
 u'root': u'0xe7ca6b8a99b6e69f52c2834ae84276dd9b0b89daf459c7391d29e2121e49e27e',
 u'to': u'0xc257beaea430afb3a09640ce7f020c906331f805',
 u'transactionHash': u'0x46e0a5a96dbea0391adbfd401b087ad1d1dfb120684462d8652df7d8b8d7f069',
 u'transactionIndex': 0}

Check the balances again

The host should have 12 Ether less, but received 5 Ether for each mining cycle. The first VPS should have received 12 Ether.

In [17]:
print "Host has %d Ether"% web3.fromWei(web3.eth.getBalance(address), 'ether')
print "VPS 1 has %d Ether" % web3.fromWei(web3.eth.getBalance(address_vps_one), 'ether')
print "VPS 2 has %d Ether" % web3.fromWei(web3.eth.getBalance(address_vps_two), 'ether')
Host has 404 Ether
VPS 1 has 162 Ether
VPS 2 has 83 Ether
In [18]:
mine_bonus = 5 # Ether
num_cycles = (float(web3.fromWei(web3.eth.getBalance(address), 'ether')) - prev_host_amount + amount)/mine_bonus
print "%d mining cycle(s) are elapsed" % num_cycles
1 mining cycle(s) are elapsed