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

Commit a8545a2

Browse files
committed
Add State to tester & add change_head to Chain
1 parent 4877553 commit a8545a2

File tree

2 files changed

+62
-21
lines changed

2 files changed

+62
-21
lines changed

ethereum/tests/test_tester.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def test_abicontract_interface():
3434
abi_json = json.dumps(simple_data['abi']).encode('utf-8')
3535

3636
abi = ABIContract(
37-
_chain=tester_state,
37+
_tester=tester_state,
3838
_abi=abi_json,
3939
address=simple_address,
4040
)

ethereum/tools/tester.py

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from ethereum.utils import sha3, privtoaddr, int_to_addr, to_string, big_endian_to_int, checksum_encode, int_to_big_endian, encode_hex
22
from ethereum.genesis_helpers import mk_basic_state
3-
from ethereum.pow import chain
3+
from ethereum.pow import chain as pow_chain
44
from ethereum.transactions import Transaction
55
from ethereum.consensus_strategy import get_consensus_strategy
66
from ethereum.config import config_homestead, config_tangerine, config_spurious, config_metropolis, default_config, Env
@@ -63,9 +63,10 @@ class TransactionFailed(Exception):
6363
config_string = ':info'
6464
# configure_logging(config_string=config_string)
6565

66+
6667
class ABIContract(object): # pylint: disable=too-few-public-methods
6768

68-
def __init__(self, _chain, _abi, address):
69+
def __init__(self, _tester, _abi, address):
6970
self.address = address
7071

7172
if isinstance(_abi, ContractTranslator):
@@ -76,25 +77,29 @@ def __init__(self, _chain, _abi, address):
7677
self.translator = abi_translator
7778

7879
for function_name in self.translator.function_data:
79-
function = self.method_factory(_chain, function_name)
80+
if self.translator.function_data[function_name]['is_constant']:
81+
function = self.method_factory(_tester.call, function_name)
82+
else:
83+
function = self.method_factory(_tester.tx, function_name)
8084
method = types.MethodType(function, self)
8185
setattr(self, function_name, method)
8286

8387
@staticmethod
84-
def method_factory(test_chain, function_name):
88+
def method_factory(tx_or_call, function_name):
8589
""" Return a proxy for calling a contract method with automatic encoding of
8690
argument and decoding of results.
8791
"""
8892

8993
def kall(self, *args, **kwargs):
9094
key = kwargs.get('sender', k0)
9195

92-
result = test_chain.tx( # pylint: disable=protected-access
96+
result = tx_or_call( # pylint: disable=protected-access
9397
sender=key,
9498
to=self.address,
9599
value=kwargs.get('value', 0),
96100
data=self.translator.encode(function_name, args),
97-
startgas=kwargs.get('startgas', STARTGAS)
101+
startgas=kwargs.get('startgas', STARTGAS),
102+
gasprice=kwargs.get('gasprice', GASPRICE)
98103
)
99104

100105
if result is False:
@@ -117,14 +122,36 @@ def get_env(env):
117122
return env if isinstance(env, Env) else Env(config=d[env])
118123

119124

125+
class State(object):
126+
def __init__(self, genesis):
127+
self.state = genesis
128+
129+
def tx(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, gasprice=GASPRICE):
130+
sender_addr = privtoaddr(sender)
131+
transaction = Transaction(self.state.get_nonce(sender_addr), gasprice, startgas,
132+
to, value, data).sign(sender)
133+
success, output = apply_transaction(self.state, transaction)
134+
if not success:
135+
raise TransactionFailed()
136+
return output
137+
138+
def call(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, gasprice=GASPRICE):
139+
state = self.state
140+
self.state = self.state.ephemeral_clone()
141+
try:
142+
output = self.tx(sender, to, value, data, startgas, gasprice)
143+
self.state = state
144+
return output
145+
except Exception as e:
146+
self.state = state
147+
raise e
148+
120149
class Chain(object):
121-
def __init__(self, alloc=None, env=None):
122-
self.chain = chain.Chain(
123-
genesis=mk_basic_state(base_alloc if alloc is None else alloc,
124-
None,
125-
get_env(env)),
126-
reset_genesis=True
127-
)
150+
def __init__(self, alloc=base_alloc, env=None, genesis=None):
151+
if genesis:
152+
self.chain = pow_chain.Chain(genesis, reset_genesis=True)
153+
else:
154+
self.chain = pow_chain.Chain(mk_basic_state(alloc, None, get_env(env)), reset_genesis=True)
128155
self.cs = get_consensus_strategy(self.chain.env.config)
129156
self.block = mk_block_from_prevstate(self.chain, timestamp=self.chain.state.timestamp + 1)
130157
self.head_state = self.chain.state.ephemeral_clone()
@@ -144,9 +171,19 @@ def tx(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, g
144171
sender_addr = privtoaddr(sender)
145172
transaction = Transaction(self.head_state.get_nonce(sender_addr), gasprice, startgas,
146173
to, value, data).sign(sender)
147-
o = self.direct_tx(transaction)
174+
output = self.direct_tx(transaction)
148175
self.last_sender = sender
149-
return o
176+
return output
177+
178+
def call(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, gasprice=GASPRICE):
179+
snapshot = self.snapshot()
180+
try:
181+
output = self.tx(sender, to, value, data, startgas, gasprice)
182+
self.revert(snapshot)
183+
return output
184+
except Exception as e:
185+
self.revert(snapshot)
186+
raise e
150187

151188
def contract(self, sourcecode, args=[], sender=k0, value=0, language='evm', startgas=STARTGAS, gasprice=GASPRICE):
152189
if language == 'evm':
@@ -165,13 +202,17 @@ def mine(self, number_of_blocks=1, coinbase=a0):
165202
set_execution_results(self.head_state, self.block)
166203
self.block = Miner(self.block).mine(rounds=100, start_nonce=0)
167204
assert self.chain.add_block(self.block)
168-
assert self.head_state.trie.root_hash == self.chain.state.trie.root_hash
205+
b = self.block
169206
for i in range(1, number_of_blocks):
170-
b, _ = make_head_candidate(self.chain, timestamp=self.chain.state.timestamp + 14)
207+
b, _ = make_head_candidate(self.chain, parent=b, timestamp=self.chain.state.timestamp + 14, coinbase=coinbase)
171208
b = Miner(b).mine(rounds=100, start_nonce=0)
172209
assert self.chain.add_block(b)
173-
self.block = mk_block_from_prevstate(self.chain, timestamp=self.chain.state.timestamp + 14)
174-
self.head_state = self.chain.state.ephemeral_clone()
210+
self.change_head(b.header.hash, coinbase)
211+
return b
212+
213+
def change_head(self, parent, coinbase=a0):
214+
self.head_state = self.chain.mk_poststate_of_blockhash(parent).ephemeral_clone()
215+
self.block = mk_block_from_prevstate(self.chain, self.head_state, timestamp=self.chain.state.timestamp, coinbase=coinbase)
175216
self.cs.initialize(self.head_state, self.block)
176217

177218
def snapshot(self):
@@ -190,7 +231,7 @@ def int_to_0x_hex(v):
190231
return '0x' + o[1:]
191232
else:
192233
return '0x' + o
193-
234+
194235

195236
def mk_state_test_prefill(c):
196237
env = {

0 commit comments

Comments
 (0)