-
Notifications
You must be signed in to change notification settings - Fork 604
The_Console
PyEthApp contains an embedded IPython console that you can use to interact with the running client.
-
From within the running client:
Press
Ctrl-C
, followed by theReturn
key. -
From the command line:
Add the option
--console
to the end of therun
subcommand.For example
pyethapp run
becomespyethapp 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.
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.
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")
An object called eth
is in the globals of the ipython session you entered.
Type help(eth)
for more info.
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}
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
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'
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)]
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)