Skip to content
This repository has been archived by the owner on Aug 8, 2018. It is now read-only.

The_Console

heikoheiko edited this page May 24, 2015 · 10 revisions

The ipython console allows to introspect and interact with the running client.

Invocation

  • Start the client (with logs turned off e.g. pyethapp -l:error run, if you get distracted by logs in the console)
  • Wait three seconds
  • hit CTRL-z

Now you should see:

Entering Console
Tip: use loglevel `-l:error` to avoid logs
>> help(eth)
Python 2.7.9 (default, Jan  1 2015, 17:29:49) 
...

At this point the client is still running and interacting with other peers.

You can leave the console by hitting CRTL-d. Note that currently the client will exit after leaving the console.

The eth object

An object called eth is in the globals of the ipython session you entered. Type help(eth) for more info.

Usage Examples

Inspect the chain

eth.latest and eth.pending refer to the latest (head of chain) and pending (not yet mined) blocks respectively.

In [12]: eth.latest
Out[12]: <CachedBlock(#432199 ea119fcd)>

wait a few seconds, and you should see, a new latest block

In [13]: eth.latest
Out[13]: <CachedBlock(#432201 4466aa6b)>

Balance of the client's coinbase.

In [54]: eth.latest.get_balance(eth.coinbase)
Out[54]: 1606938044258990275541962092341162602488823645322492765499285L

Inspect the block header

In [16]: eth.latest.header
Out[16]: <BlockHeader(#432209 d1153010)>

In [20]: eth.latest.header.difficulty
Out[20]: 12519046990

In [21]: eth.latest.header.check_pow()
Out[21]: True

In [22]: eth.latest.header.coinbase.encode('hex')
Out[22]: '4d5c04cc051e1781e4f8326b8eda46532b64d9b0'

In [29]: eth.latest.to_dict()
Out[29]: 
{'header': {'bloom': '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
  'coinbase': '430b90576bf17f691dd1b8420853c9fd59e330f7',
  'difficulty': '12506812416',
  'extra_data': '0x',
  'gas_limit': '3141592',
  'gas_used': '0',
  'mixhash': '0x4aac9619472743a380c1c469816ff363abfe5a841a6eff1582b6dfd5b539cff5',
  'nonce': '0x3e38d9552269831a',
  'number': '432229',
  'prevhash': '0x48af63a56d74bab1f41554431c062d01aadcc990538ed357ad365b0c936785a0',
  'receipts_root': '56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  'state_root': '05153dd481ac06f7d05739ada449525fa7ebf052225fdf6d1bee90de72d564aa',
  'timestamp': '1432459127',
  'tx_list_root': '56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  'uncles_hash': '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347'},
 'transactions': []}

Get Transactions:

In [36]: eth.latest.get_transactions()
Out[36]: [<Transaction(ba4a)>, <Transaction(d5bd)>]

In [46]: tx = eth.latest.get_transactions()[0]

In [47]: tx.value
Out[47]: 14444999

In [48]: tx.sender.encode('hex')
Out[48]: '00fc572550f3bdfe84f72e3eaa99d02a43f69733'

In [49]: tx.log_dict()
Out[49]: 
{'data': '',
 'gasprice': 10000000000000,
 'hash': '6cf99d59ee667dd56cdc34c5b4f5349fdc2377ea9b715c27d1a9d2ba17796636',
 'nonce': 5047,
 'r': 37949441106074605966811028217872197823963701877937951182924847227904959108149L,
 's': 7840037590794696459998581397264706147072541541675627162552725158699447211262L,
 'sender': '00fc572550f3bdfe84f72e3eaa99d02a43f69733',
 'startgas': 90000,
 'to': 'd63b635a458b99f7e900477e2d261d5d13e45d59',
 'v': 27,
 'value': 14444999}

Creating Transactions

In [53]: eth.transact?
Signature: eth.transact(to, value=0, data='', sender=None, startgas=25000, gasprice=10000000000000)
In [55]: tx = eth.transact('d63b635a458b99f7e900477e2d261d5d13e45d59', value=100)
In [56]: eth.find_transaction(tx)
Out[56]: {'block': <Block(#432282 7dd76ad5)>, 'index': 0, 'tx': <Transaction(3384)>}
In [59]: eth.find_transaction(tx)['block'].get_transactions()[0] == tx
Out[59]: True

Creating Contracts

In [60]: code ="""
   ....: contract NameReg  {
   ....:        event AddressRegistered(bytes32 indexed name, address indexed account);
   ....:        mapping (address => bytes32) toName;
   ....: 
   ....:        function register(bytes32 name) {
   ....:                toName[msg.sender] = name;
   ....:                AddressRegistered(name, msg.sender);
   ....:        }
   ....: 
   ....:        function resolve(address addr) constant returns (bytes32 name) {
   ....:                return toName[addr];
   ....:        }
   ....: }
   ....: """

In [61]: evm_code = solidity.compile(code)
In [62]: abi = solidity.mk_full_signature(code)
In [64]: eth.transact?
Signature: eth.transact(to, value=0, data='', sender=None, startgas=25000, gasprice=10000000000000)
In [67]: tx = eth.transact(to='', data=evm_code, startgas=500000)
In [68]: eth.find_transaction(tx)
Out[68]: {'block': <Block(#432447 cf97e384)>, 'index': 0, 'tx': <Transaction(1553)>}

Now lets create a proxy to call this contract. The address of the created contract can be found in tx.creates.

In [69]: tx.creates.encode('hex')
Out[69]: '01ac2517022e28782fbbbe01e7d614cf0b21a89e'
In [70]: eth.new_contract?
Signature: eth.new_contract(abi, address, sender=None)
In [71]: namereg = eth.new_contract(abi, tx.creates)

The abi is used to automatically generate methods which show the args in their docstring.

In [72]: namereg.register?
Type:           abi_method
Signature:      namereg.register(this, *args, **kargs)
Docstring:      register(bytes32 name)
In [73]: namereg.resolve?
Type:           abi_method
Signature:      namereg.resolve(this, *args, **kargs)
Docstring:      resolve(address addr)

Ok, let's interact.

In [72]: tx = namereg.register('alice')
In [73]: eth.find_transaction(tx)
Out[73]: {}
In [75]: eth.find_transaction(tx)
Out[75]: {'block': <Block(#432458 5e1a914b)>, 'index': 0, 'tx': <Transaction(2b2f)>}
In [76]: namereg.resolve(eth.coinbase)
Out[76]: 'alice\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

Automating transactions

Lets try to update the contract every block. We register a callback with the chainservice which gets triggered, whenever there is a new head of the chain.

Let's try a simple callback first.

In [124]: def cb(blk):
   .....:     assert blk == eth.latest
   .....:     print('new head', blk)
   .....:     
In [125]: eth.chainservice.on_new_head_cbs.append(cb)
('new head', <Block(#432673 cb5e3f0b)>)
('new head', <Block(#432674 49ad8042)>)
('new head', <Block(#432675 104e1f81)>)
In [126]: eth.chainservice.on_new_head_cbs.remove(cb)

Ok, now we let new heads trigger a transaction and check if it was added to the next block. Note: The callback is called from within add_blocks which has set eth.chainservice.add_transaction_lock. We need to release, otherwise we'll have a deadlock.

In [33]: def cb(blk):
    print 'new head', blk
    eth.chainservice.add_transaction_lock.release()
    namereg.register('we are at block #%d' % blk.header.number)
    if namereg.address in [tx.to for tx in blk.get_parent().get_transactions()]:
        print 'namereg was called in the previous block'
   ....:         

In [34]: cb(eth.latest)
new head <CachedBlock(#432934 957485b0)>

In [35]: eth.chainservice.on_new_head_cbs.append(cb)

new head <Block(#432935 0479bc93)>
new head <Block(#432936 5af01a9d)>
new head <Block(#432937 bd41d3ac)>
namereg was called in the previous block
new head <Block(#432938 c003bbf3)>
new head <Block(#432939 50cc4401)>
namereg was called in the previous block
new head <Block(#432940 f9a802d5)>
new head <Block(#432941 1805dbb0)>
namereg was called in the previous block
new head <Block(#432942 3aa6a7ed)>
new head <Block(#432943 40d501dc)>
namereg was called in the previous block

In [36]: eth.chainservice.on_new_head_cbs.remove(cb)

Note, not every miner includes our block. Let's name them.

In [62]: from collections import Counter
In [63]: miners = []
In [76]: def cb(blk):
   ....:         print 'new head', blk
   ....:         eth.chainservice.add_transaction_lock.release()
   ....:         namereg.register('we are at block #%d' % blk.header.number)
   ....:         parent = blk.get_parent()
   ....:         if namereg.address in [tx.to for tx in parent.get_transactions()]:
   ....:             print 'namereg was called in the previous block'
   ....:         else:
   ....:             miners.append(parent.header.coinbase)

In [89]: [(k.encode('hex'),v) for k,v in Counter(miners).items()]
Out[89]: 
[('54f0f931bce7a76457a93211213ac63f72028df3', 2),
 ('4278273854a158e72fcf5e752fd5fda7238ebea8', 1),
 ('b4e64290541cbf36159e727dfd8d873f77b42149', 1),
 ('027b1495165fec8cfc49bdb8450ded4cbce4b12e', 4),
 ('d95e199a7a99e0f25bfe9db41fb565f51c34a3fc', 1),
 ('82b27dbe07d34fb96309d2306e2729b6c5d155ff', 8),
 ('60cf7a1cf99fe2b4cd4d75060872f6c729cdb2c8', 1)]

Networking

Show the active peers

In [92]: eth.services.peermanager.peers
Out[92]: 
[<Peer('50.103.117.68', 30303) ++eth/v0.9.23>,
 <Peer('52.5.26.15', 60764) ++eth/v0.9.23>,
 <Peer('144.76.62.101', 30303) pyethapp_1f66/v0.9.18>,
 <Peer('54.207.93.166', 30303) Geth/v0.9.23>,
 <Peer('79.98.29.154', 30303) Geth/v0.9.21.1>,
 <Peer('52.16.108.192', 54343) Geth/freequant>]

Get ping times

In [99]: for p in eth.services.peermanager.peers:
    p2p_proto = p.protocols.values()[0]
    print p, p2p_proto.monitor.latency()
   ....:     
<Peer('50.103.117.68', 30303) ++eth/v0.9.23> 0.297611525104
<Peer('52.5.26.15', 60764) ++eth/v0.9.23> 0.25300160487
<Peer('144.76.62.101', 30303) pyethapp_1f66/v0.9.18> 0.138624746569
<Peer('54.207.93.166', 30303) Geth/v0.9.23> 0.425052755019
<Peer('79.98.29.154', 30303) Geth/v0.9.21.1> 0.949464556397
<Peer('52.16.108.192', 54343) Geth/freequant> 0.209883757666

Stop some peers

In [102]: eth.services.peermanager.peers
Out[102]: 
[<Peer('144.76.62.101', 30303) pyethapp_1f66/v0.9.18>,
 <Peer('54.207.93.166', 30303) Geth/v0.9.23>,
 <Peer('79.98.29.154', 30303) Geth/v0.9.21.1>,
 <Peer('52.16.108.192', 54343) Geth/freequant>]
In [103]: eth.services.peermanager.peers[0].stop()
In [104]: eth.services.peermanager.peers[0].stop()
In [105]: eth.services.peermanager.peers[0].stop()
In [106]: eth.services.peermanager.peers
Out[106]: [<Peer('52.16.108.192', 54343) Geth/freequant>, <Peer('52.5.26.15', 30303) >]

In [112]: # wait a bit and it will have connected new peers
In [113]: eth.services.peermanager.peers
Out[113]: 
[<Peer('52.16.108.192', 54343) Geth/freequant>,
 <Peer('91.200.115.20', 30303) Geth/LVIV>,
 <Peer('14.192.203.78', 30303) Geth/v0.9.20>,
 <Peer('54.207.93.166', 30303) Geth/v0.9.23>,
 <Peer('52.5.26.15', 30303) >]