Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

debug_traceTransaction support #445

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion ethereum/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# Genesis block difficulty
GENESIS_DIFFICULTY=131072,
# Genesis block gas limit
GENESIS_GAS_LIMIT=3141592,
GENESIS_GAS_LIMIT=8000000, #4712388,
# Genesis block prevhash, coinbase, nonce
GENESIS_PREVHASH=b'\x00' * 32,
GENESIS_COINBASE=b'\x00' * 20,
Expand Down Expand Up @@ -66,6 +66,8 @@
# Anti-DoS fork
ANTI_DOS_FORK_BLKNUM=2457000,
CLEARING_FORK_BLKNUM=2 ** 98,
# Trace
TRACE_TRANSACTIONS=True
)
assert default_config['NEPHEW_REWARD'] == \
default_config['BLOCK_REWARD'] // 32
Expand Down
32 changes: 22 additions & 10 deletions ethereum/processblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ethereum import specials
from ethereum import bloom
from ethereum import vm as vm
from ethereum.trace import Trace
from ethereum.exceptions import InvalidNonce, InsufficientStartGas, UnsignedTransaction, \
BlockGasLimitReached, InsufficientBalance, VerificationFailed
from ethereum.utils import safe_ord, normalize_address, mk_contract_address, \
Expand All @@ -22,6 +23,7 @@
log_msg = get_logger('eth.pb.msg')
log_state = get_logger('eth.pb.msg.state')


TT255 = 2 ** 255
TT256 = 2 ** 256
TT256M1 = 2 ** 256 - 1
Expand Down Expand Up @@ -167,11 +169,16 @@ def rp(what, actual, target):

# MESSAGE
ext = VMExt(block, tx)
tr = Trace()
if tr.enabled:
oldStorage = ext.get_storage(tx.to)
if tx.to and tx.to != CREATE_CONTRACT_ADDRESS:
result, gas_remained, data = apply_msg(ext, message)
result, gas_remained, data, trc = apply_msg(ext, message)
#We receive bytesarray for data
log_tx.debug('_res_', result=result, gas_remained=gas_remained, data=lazy_safe_encode(data))
else: # CREATE
result, gas_remained, data = create_contract(ext, message)
result, gas_remained, data, trc = create_contract(ext, message)
#We receive address for data
assert utils.is_numeric(gas_remained)
log_tx.debug('_create_', result=result, gas_remained=gas_remained, data=lazy_safe_encode(data))

Expand All @@ -184,6 +191,7 @@ def rp(what, actual, target):
log_tx.debug('TX FAILED', reason='out of gas',
startgas=tx.startgas, gas_remained=gas_remained)
block.gas_used += tx.startgas
gas_used = tx.startgas
block.delta_balance(block.coinbase, tx.gasprice * tx.startgas)
output = b''
success = 0
Expand Down Expand Up @@ -214,6 +222,9 @@ def rp(what, actual, target):
block.del_account(s)
block.add_transaction_to_list(tx)
block.logs = []
if trc and tr.enabled:
tr.addTrace(tx.hash.encode('hex'), { "returnValue":output, "gas":gas_used, "structLogs":trc })
tr.addStorage(ext.block_number, tx.hash.encode('hex'), oldStorage);
return success, output


Expand All @@ -230,6 +241,7 @@ def __init__(self, block, tx):
self.get_nonce = block.get_nonce
self.set_nonce = block.set_nonce
self.set_storage_data = block.set_storage_data
self.get_storage = block.get_storage
self.get_storage_data = block.get_storage_data
self.log_storage = lambda x: block.account_to_dict(x)['storage']
self.add_suicide = lambda x: block.suicides.append(x)
Expand Down Expand Up @@ -282,7 +294,7 @@ def _apply_msg(ext, msg, code):
if msg.code_address in specials.specials:
res, gas, dat = specials.specials[msg.code_address](ext, msg)
else:
res, gas, dat = vm.vm_execute(ext, msg, code)
res, gas, dat, trc = vm.vm_execute(ext, msg, code)
# gas = int(gas)
# assert utils.is_numeric(gas)
if trace_msg:
Expand All @@ -299,8 +311,8 @@ def _apply_msg(ext, msg, code):
if res == 0:
log_msg.debug('REVERTING')
ext._block.revert(snapshot)

return res, gas, dat
return res, gas, dat, trc


def create_contract(ext, msg):
Expand Down Expand Up @@ -332,12 +344,12 @@ def create_contract(ext, msg):
# assert not ext.get_code(msg.to)
msg.data = vm.CallData([], 0, 0)
snapshot = ext._block.snapshot()
res, gas, dat = _apply_msg(ext, msg, code)
res, gas, dat, trc = _apply_msg(ext, msg, code)
assert utils.is_numeric(gas)

if res:
if not len(dat):
return 1, gas, msg.to
return 1, gas, msg.to, trc
gcost = len(dat) * opcodes.GCONTRACTBYTE
if gas >= gcost:
gas -= gcost
Expand All @@ -346,8 +358,8 @@ def create_contract(ext, msg):
log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost, block_number=ext._block.number)
if ext._block.number >= ext._block.config['HOMESTEAD_FORK_BLKNUM']:
ext._block.revert(snapshot)
return 0, 0, b''
return 0, 0, b'', trc
ext._block.set_code(msg.to, b''.join(map(ascii_chr, dat)))
return 1, gas, msg.to
return 1, gas, msg.to, trc
else:
return 0, gas, b''
return 0, gas, b'', trc
51 changes: 40 additions & 11 deletions ethereum/tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
import rlp
from rlp.utils import ascii_chr

from ethereum import blocks, db, opcodes, processblock, transactions
from ethereum import blocks, db, opcodes, transactions, processblock
from ethereum.abi import ContractTranslator
from ethereum.config import Env
from ethereum.slogging import LogRecorder
from ethereum._solidity import get_solidity
from ethereum.utils import to_string, sha3, privtoaddr, int_to_addr
from ethereum.trace import Trace

TRACE_LVL_MAP = [
':info',
Expand All @@ -24,21 +25,50 @@
'eth.vm.storage:trace,eth.vm.memory:trace'
]

GAS_LIMIT = 3141592
GAS_PRICE = 1
GAS_LIMIT = 8000000
GAS_PRICE = 20000000000

# pylint: disable=invalid-name

gas_limit = GAS_LIMIT
gas_price = GAS_PRICE

accounts = []
keys = []
accounts = [
u"ac7bebd558c734fe105d09167860b230fb0a218d".decode('hex'),
u"6e5fd1741e45c966a76a077af9132627c07b0dc1".decode('hex'),
u"ef057953c56855f16e658bf8fd0d2e300961fc1f".decode('hex'),
u"2c284ef5a0d50dda177bd8c9fdf20610f6fdac09".decode('hex'),
u"bd3c601b59f46cc59be3446ba29c66b9182a70b6".decode('hex'),
u"e6e6033428cfc58af1585c26a823916c8120ca73".decode('hex'),
u"e2c628c146a9d40c9ed4c5c3e29cd0a609f7c6f1".decode('hex'),
u"3e2ff0583a5dec1bd3ac0f7b8d26fa96b759fe92".decode('hex'),
u"2827a89f78d70c422452528634cfe522b5c668c6".decode('hex'),
u"f56ae85523c6f4773954fe0b25ba1f52e1183689".decode('hex'),
u"7703aCa0f4ee937C3073ec80c7608B6f7cE2426B".decode('hex'),
u"153ee6aD2e7e665b8a07ff37d93271d6E5FDc6d4".decode('hex'),
u"4fe1ead95d882580561b704938ecbd5cb9450ab6".decode('hex'),
]
keys = [
u"43df74be7858da13bb08c1289fe488b9843c555538dd1638203725b18a19863e".decode('hex'),
u"0af37c53fdc5b97bf1f84d30e84f09c84f733e467a3b26c1ce6c5d448f9d7cec".decode('hex'),
u"0d5c1bd818a4086f28314415cb375a937593efab66f8f7d2903bf2a13ed35070".decode('hex'),
u"17029bda254fdf118125741e80d2d43e8ac1ffa8cca20c51683bc0735c802e5b".decode('hex'),
u"8d2fd08f91550712ec0db96bdbb849ec88a560e200c58f05954827b2593cf9e7".decode('hex'),
u"803ae2f3b0030390092910e0f1e8ec15dbc975d6422ab2274b175c74eed589fb".decode('hex'),
u"0c71a0e6e4bf22677a5750c123aaf988270e1c4025f80d82b7a18f2efe295cbf".decode('hex'),
u"9ca1d29731e6302e3e7d7f0ebaf2b4fa48d7b7fd4f5c82f59b3983b0a2160d7e".decode('hex'),
u"e2631c2443b12abdfc5e70e3b7643f2d340eb49c6102c66835d0c7286903b009".decode('hex'),
u"f7a590340d042a107ec3c9e82f81d2301ecc5b79f959f7a09d3c7fb7ab7f1024".decode('hex'),
u"9e256901c752616c231904281333e5dd11fa48fdfd7ffac3515923b1fe60a28e".decode('hex'),
u"b10ec925fccdaf155fa0b56bd55cf6ce3cc8927b304c0a563476529d925755d5".decode('hex'),
u"71c52b034f6405fbabb6ad5e91997dd2ea1f43d48502e10dd47d5a4a8a02cbdf".decode('hex'),
]

languages = {}

for account_number in range(10):
keys.append(sha3(to_string(account_number)))
accounts.append(privtoaddr(keys[-1]))
#for account_number in range(10):
# keys.append(sha3(to_string(account_number)))
# accounts.append(privtoaddr(keys[-1]))

k0, k1, k2, k3, k4, k5, k6, k7, k8, k9 = keys[:10]
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = accounts[:10]
Expand Down Expand Up @@ -157,13 +187,12 @@ def kall(self, *args, **kwargs):


class state(object):

def __init__(self, num_accounts=len(keys)):
self.temp_data_dir = tempfile.mkdtemp()
self.db = db.EphemDB()
self.env = Env(self.db)
self.last_tx = None

initial_balances = {}

for i in range(num_accounts):
Expand Down Expand Up @@ -293,7 +322,7 @@ def _send(self, sender, to, value, evmdata='', funid=None, abi=None, # pylint:
(success, output) = processblock.apply_transaction(self.block, transaction)

if not success:
raise TransactionFailed()
raise TransactionFailed(transaction.hash.encode('hex'))

out = {
'output': output,
Expand Down
2 changes: 1 addition & 1 deletion ethereum/testutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def blkhash(n):
time_pre = time.time()
if profiler:
profiler.enable()
success, gas_remained, output = vm.vm_execute(ext, msg, code)
success, gas_remained, output, trc = vm.vm_execute(ext, msg, code)
if profiler:
profiler.disable()
pb.apply_msg = orig_apply_msg
Expand Down
53 changes: 53 additions & 0 deletions ethereum/trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
from ethereum.config import Env
from ethereum import config

class Trace(object):
storages = {}
transactions = {}
enabled = None
def __init__(self):
self.enabled = config.default_config['TRACE_TRANSACTIONS']

def getTrace(self, tx_hash):
if not self.enabled: raise Exception('Trace transaction is disabled!')
if tx_hash in self.transactions:
return self.transactions[tx_hash]
else:
raise Exception('Transaction not found!')

def addTrace(self, tx_hash, tx_trace):
if self.enabled:
if tx_hash.lower()[:2] != "0x": tx_hash = "0x"+tx_hash
if tx_hash in self.transactions:
# extend!
self.transactions[tx_hash]["structLogs"].extend(tx_trace["structLogs"])
self.transactions[tx_hash]["returnValue"] = tx_trace["returnValue"]
self.transactions[tx_hash]["gas"] = tx_trace["gas"]
else:
self.transactions[tx_hash] = tx_trace
return True
return False

def addStorage(self, block_num, tx_hash, storage):
if self.enabled:
str = {}
storage = storage.to_dict()
for a in storage:
str[a.encode('hex')] = storage[a].encode('hex')
if not block_num in self.storages: self.storages[block_num] = []
tmp = [tx_hash in i for i in self.storages[block_num]]
if (True in tmp):
self.storages[block_num][tmp.index(True)] = str
else:
self.storages[block_num].append({ tx_hash:str })
return True
return False

def getStorage(self, block_num, tx_num, contract_address, stor_start, stor_end, limit):
# stor_start, stor_end, limit not yet implemented
if self.enabled:
if not block_num in self.storages: raise Exception('Block not found!')
if tx_num >= len(self.storages[block_num]): raise Exception('TX not found!')
return { "complete": True, "storage": self.storages[block_num][tx_num] }
raise Exception('Trace is disabled!')