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

The_Console

Ulrich Petri edited this page Oct 9, 2015 · 10 revisions

PyEthApp contains an embedded IPython console that you can use to interact with the running client.

Invocation

  • From within the running client:

    Press Ctrl-C, followed by the Return key.

  • From the command line:

    Add the option --console to the end of the run subcommand.

    For example pyethapp run becomes pyethapp run --console

In both cases you should see the following:

Entering Console
Tip:
	use `lastlog(n)` to see n lines of log-output. [default 10]
	use `lasterr(n)` to see n lines of stderr.
	use `help(eth)` for help on accessing the live chain.


Python 2.7.10 (default, Aug 13 2015, 14:32:11)
Type "copyright", "credits" or "license" for more information.
...

The client continues to run in the background.

You can leave the console by hitting CRTL-d. Due to current limitations in the implementation leaving the console will also exit the entire client.

Accessing logs

Entering the console redirects the log handler to an in-memory buffer enabling you to work with the console without being overwhelmed by log messages.

To access this buffer you can use the lastlog(n=10, prefix=None, level=None) function that is available in the namespace of the console.

Examples

lastlog()
# prints the last 10 log lines.

lastlog(20)
# prints the last 20 log lines.

lastlog(level="INFO")
# print all INFO log lines

lastlog(prefix="app")
# print all log lines beginning with `app`

# Combine all three
lastlog(n=100, level="DEBUG", prefix="app")

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)>

Retrieving blocks

In [28]: eth.latest
Out[28]: <CachedBlock(#433960 2dccf6e7)>
In [29]: blockhash = eth.latest.hash
In [30]: blockhash == eth.chain.index.get_block_by_number(433960)
Out[30]: True

In [31]: eth.chain.get(blockhash)
Out[31]: <CachedBlock(#433960 2dccf6e7)>

In [32]: raw_rlp_data = eth.chain.db.get(blockhash)

In [36]: eth.latest.get_parent()
Out[36]: <CachedBlock(#433986 ac47d1d1)>

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) >]

Let's check the routing table

In [115]: len(eth.services.discovery.protocol.kademlia.routing)
Out[115]: 77
In [117]: list(eth.services.discovery.protocol.kademlia.routing)[:5]
Out[117]: 
[<Node(7f25d3ea)>,
 <Node(f6ba1f1d)>,
 <Node(67a8b49b)>,
 <Node(6585e5a5)>,
 <Node(980c1003)>]
In [118]: node = list(eth.services.discovery.protocol.kademlia.routing)[0]
In [119]: node.pubkey.encode('hex')
Out[119]: '7f25d3eab333a6b98a8b5ed68d962bb22c876ffcd5561fca54e3c2ef27f754df6f7fd7c9b74cc919067abac154fb8e1f8385505954f161ae440abc355855e034'
In [120]: node.address
Out[120]: Address(54.207.93.166:30303)