Using the Ethereum RPC client in Python

Ethereum - RPC client

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

In this notebook I will try out the RPC client of Ethereum using Python. See JSON RPC for more information on JSON RPC .

In [2]:
import sys
sys.version
Out[2]:
'3.6.0 |Anaconda 4.3.0 (64-bit)| (default, Dec 23 2016, 12:22:00) \n[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]'

Prepare environment

Install the Python RPC client for Ethereum. Github

jitsejan@jjvps:~$ pip install ethereum-rpc-client

Start the blockchain making sure RPC is enabled.

jitsejan@jjvps:~$ geth --networkid 23 --nodiscover --maxpeers 0  --port 30333 --rpc

Verify that geth is running and the account is listed.

In [3]:
!geth account list
Account #0: {8cf9deda0712f2291fb16739f8759e4a0a575854} keystore:///home/jitsejan/.ethereum/keystore/UTC--2017-05-01T14-58-43.532247863Z--8cf9deda0712f2291fb16739f8759e4a0a575854

Connect to the RPC client

In [4]:
from eth_rpc_client import Client
client = Client(host="127.0.0.1", port="8545")

Inspect the client

In [5]:
import pdir
pdir(client)
Out[5]:
abstract class:
    __subclasshook__
attribute access:
    __delattr__, __dir__, __getattribute__, __setattr__
class customization:
    __init_subclass__
object customization:
    __format__, __hash__, __init__, __new__, __repr__, __sizeof__, __str__
other:
    _coinbase_cache, _coinbase_cache_til, _nonce, async_timeout, host, is_async, port, request_queue, request_thread, results, session
pickle:
    __reduce__, __reduce_ex__
rich comparison:
    __eq__, __ge__, __gt__, __le__, __lt__, __ne__
special attribute:
    __class__, __dict__, __doc__, __module__, __weakref__
descriptor:
    default_from_address: @property with getter, Cache the coinbase address so that we don't make two requests for every
function:
    _make_request: 
    call: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_call
    construct_json_request: 
    get_accounts: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_accounts
    get_balance: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getbalance
    get_block_by_hash: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash
    get_block_by_number: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbynumber
    get_block_number: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_blocknumber<F37>
    get_code: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getcode
    get_coinbase: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_coinbase
    get_filter_changes: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterchanges
    get_filter_logs: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterlogs
    get_gas_price: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gasprice
    get_logs: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
    get_max_gas: 
    get_nonce: 
    get_transaction_by_hash: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyhash
    get_transaction_receipt: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt
    make_request: 
    new_block_filter: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newblockfilter
    new_filter: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter
    new_pending_transaction_filter: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newpendingtransactionfilter
    process_requests: Loop that runs in a thread to process requests synchronously.
    send_transaction: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction
    uninstall_filter: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_uninstallfilter
    wait_for_block: 
    wait_for_transaction: 

Get the coinbase for the blockchain

In [6]:
address = client.get_coinbase()
address
Out[6]:
'0x8cf9deda0712f2291fb16739f8759e4a0a575854'

Retrieve the balance of the main address

In [7]:
client.get_balance(address)
Out[7]:
135000419895999999940

Set the addresses of the two other machines:

In [8]:
address_vps_one = "0xc257beaea430afb3a09640ce7f020c906331f805"
address_vps_two = "0xe86ee31b7d32b743907fa7438c422a1803717deb"
In [9]:
client.get_balance(address_vps_one)
client.get_balance(address_vps_two)
Out[9]:
6999160060000000000
Out[9]:
83000420044000000060

Transaction

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

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

1 GWEI = 0.000000001 Ether

Get the password to unlock the sending account

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

Unlock the account via the command line

(By lack of a better way)

In [12]:
command = r'geth --exec "personal.unlockAccount(\"%s\", \"%s\");" attach ' % (sending_address, pw)
result = !$command
if result[0] != 'true':
    print('Fail: %s' % result[0])
else:
    print('Account is unlocked!')
Account is unlocked!

Send the transaction

In [13]:
tx_hash = client.send_transaction(to=receiving_address, _from=sending_address, value=amount * 10**9)

Check the transaction details

In [14]:
client.get_transaction_by_hash(tx_hash)
Out[14]:
{'blockHash': '0x0000000000000000000000000000000000000000000000000000000000000000',
 'blockNumber': None,
 'from': '0x8cf9deda0712f2291fb16739f8759e4a0a575854',
 'gas': '0x15f90',
 'gasPrice': '0x4a817c800',
 'hash': '0x3d1a193ccfccc4e9ab2a411044069deeec2feef31a594bbf73726b463e8e90b4',
 'input': '0x',
 'nonce': '0xb',
 'r': '0xe8698846a461938e800698fcc34570e0c4e9a3425f0bc441bf3e0716dab7b3e0',
 's': '0x4fcd9bda8a1e98a7b0e8d953dec0cc733238c383d97393aa15c43963551f8daf',
 'to': '0xc257beaea430afb3a09640ce7f020c906331f805',
 'transactionIndex': '0x0',
 'v': '0x42',
 'value': '0x2cb417800'}

Perform one mining step

Execute the miner to validate the transaction.

In [15]:
prev_balance_sen = client.get_balance(sending_address)
prev_balance_rec = client.get_balance(receiving_address)
In [16]:
result = !geth --exec "miner.start();admin.sleepBlocks(1);miner.stop();" attach
if result[0] != 'true':
    print('Fail: %s' % result[0])
else:
    print("Mining finished!")
Mining finished!

Check if the Ether has been received

In [17]:
print("Received %d"% (client.get_balance(receiving_address)-prev_balance_rec))
Received 12000000000

Check if the Ether was sent

First check the difference in the balance.

In [18]:
print("Difference of the sender %d"% (client.get_balance(sending_address)-prev_balance_sen))
Difference of the sender 4999999988000000000

For mining, the miner will get a mining bonus.

In [19]:
mining_bonus = 5000000000000000000

To get the amount of Ether sent we need to substract the mining bonus.

In [20]:
print("Amount difference: %d" % int(client.get_balance(sending_address)-prev_balance_sen - mining_bonus))
Amount difference: -12000000000