From fcc9bbe998e0e2eed074058156168d0a52195c17 Mon Sep 17 00:00:00 2001 From: Heiko Heiko Date: Thu, 21 Aug 2014 17:14:46 +0200 Subject: [PATCH] add: trace tx via the api --- pyethereum/apiserver.py | 60 ++++++++++++++++++++++++++++++++++++++++- pyethereum/ethclient.py | 8 +++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/pyethereum/apiserver.py b/pyethereum/apiserver.py index 29e59599e..6acea0b9c 100644 --- a/pyethereum/apiserver.py +++ b/pyethereum/apiserver.py @@ -7,9 +7,12 @@ from pyethereum.chainmanager import chain_manager from pyethereum.peermanager import peer_manager import pyethereum.dispatch as dispatch -from pyethereum.blocks import block_structure +from pyethereum.blocks import block_structure, Block import pyethereum.signals as signals from pyethereum.transactions import Transaction +import pyethereum.processblock as processblock +import pyethereum.utils as utils +import pyethereum.rlp as rlp logger = logging.getLogger(__name__) base_url = '/api/v02a' @@ -176,6 +179,61 @@ def get_pending(): +# ########### Trace ############ + +class TraceLogHandler(logging.Handler): + def __init__(self): + logging.Handler.__init__(self) + self.buffer = [] + + def emit(self, record): + self.buffer.append(record) + + +@app.get(base_url + '/trace/') +def trace(txhash): + """ + /trace/ return trace for transaction + """ + logger.debug('GET trace/ %s', txhash) + try: # index + tx, blk = chain_manager.index.get_transaction(txhash.decode('hex')) + except (KeyError, TypeError): + return bottle.abort(404, 'Unknown Transaction %s' % txhash) + + # get the state we had before this transaction + test_blk = Block.init_from_parent(blk.get_parent(), + blk.coinbase, + extra_data=blk.extra_data, + timestamp=blk.timestamp, + uncles=blk.uncles) + pre_state = test_blk.state_root + for i in range(blk.transaction_count): + tx_lst_serialized, sr, _ = blk.get_transaction(i) + if utils.sha3(rlp.encode(tx_lst_serialized)) == tx.hash: + break + else: + pre_state = sr + test_blk.state.root_hash = pre_state + + # collect debug output + tl = TraceLogHandler() + tl.setLevel(logging.DEBUG) + processblock.logger.addHandler(tl) + + # apply tx (thread? we don't want logs from other invocations) + processblock.apply_transaction(test_blk, tx) + + # stop collecting debug output + processblock.logger.removeHandler(tl) + + # format + formatter = logging.Formatter('%(name)s:%(message)s') + res = '\n'.join(formatter.format(l) for l in tl.buffer) + return dict(trace=res) + + + # ######## Accounts ############ @app.get(base_url + '/accounts/') def accounts(): diff --git a/pyethereum/ethclient.py b/pyethereum/ethclient.py index c1fd52913..02621698d 100755 --- a/pyethereum/ethclient.py +++ b/pyethereum/ethclient.py @@ -95,6 +95,11 @@ def gettx(self, id): def getpending(self): return self.json_get_request(path='/pending/') + def trace(self, id): + res = self.json_get_request(path='/trace/%s' % id) + if 'trace' in res: + return res['trace'] + return res doc = \ """ethclient @@ -115,7 +120,7 @@ def getpending(self): pyethclient getblock [options] pyethclient gettx [options] pyethclient getpending [options] - + pyethclient trace [options] Options: -h --help Show this screen @@ -155,6 +160,7 @@ def main(): getblock=(api.getblock, arguments['']), gettx=(api.gettx, arguments['']), trace=(api.trace, arguments['']), + getpending=(api.getpending,) ) for k in cmd_map: if arguments.get(k):