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

Commit b4dcb30

Browse files
author
Jan Xie
committed
Merge commit '6658f70dfffc86149764d3b04f335ec09a74ee24' into develop_with_state_revamp
2 parents 827b118 + 6658f70 commit b4dcb30

20 files changed

+407
-260
lines changed

ethereum/abi.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-m
259259
if not -2 ** bits <= i < 2 ** bits:
260260
raise ValueOutOfBounds(repr(arg))
261261

262-
value = i % 2 ** sub # convert negative to "equivalent" positive
262+
value = i % 2 ** 256 # convert negative to "equivalent" positive
263263
value_encoded = int_to_big_endian(value)
264264
return zpad(value_encoded, 32)
265265

@@ -309,6 +309,11 @@ def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-m
309309
value = fixed_point % 2 ** 256
310310
return zpad(int_to_big_endian(value), 32)
311311

312+
# Decimals
313+
if base == 'decimal':
314+
val_to_encode = int(arg * 10**int(sub))
315+
return zpad(encode_int(val_to_encode % 2**256), 32)
316+
312317
if base == 'string':
313318
if isinstance(arg, utils.unicode):
314319
arg = arg.encode('utf8')
@@ -724,7 +729,7 @@ def encode_abi(types, args):
724729
def decode_single(typ, data):
725730
base, sub, _ = typ
726731
if base == 'address':
727-
return encode_hex(data[12:])
732+
return '0x' + encode_hex(data[12:])
728733
elif base == 'hash':
729734
return data[32 - int(sub):]
730735
elif base == 'string' or base == 'bytes':
@@ -746,8 +751,14 @@ def decode_single(typ, data):
746751
o = big_endian_to_int(data)
747752
i = (o - 2 ** (high + low)) if o >= 2 ** (high + low - 1) else o
748753
return (i * 1.0 // 2 ** low)
754+
elif base == 'decimal':
755+
o = big_endian_to_int(data)
756+
i = (o - 2 ** 256 if o > 2 ** 255 else o)
757+
return i / 10 ** int(sub)
749758
elif base == 'bool':
750759
return bool(int(encode_hex(data), 16))
760+
else:
761+
raise EncodingError("Unhandled type: %r %r" % (base, sub))
751762

752763

753764
# Decodes multiple arguments using the head/tail mechanism
@@ -799,7 +810,7 @@ def dec(typ, arg):
799810
# Dynamic-sized strings are encoded as <len(str)> + <str>
800811
if base in ('string', 'bytes') and not sub:
801812
L = big_endian_to_int(arg[:32])
802-
assert len(arg[32:]) == ceil32(L), "Wrong data size for string/bytes object"
813+
assert len(arg[32:]) == ceil32(L), "Wrong data size for string/bytes object: expected %d actual %d" % (ceil32(L), len(arg[32:]))
803814
return arg[32:][:L]
804815
# Dynamic-sized arrays
805816
elif sz is None:

ethereum/chain.py

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import random
33
import time
4+
import itertools
45

56
import rlp
67

@@ -10,7 +11,9 @@
1011
from ethereum.slogging import get_logger
1112
from ethereum.state import State
1213
from ethereum.state_transition import apply_block, initialize, \
13-
update_block_env_variables
14+
pre_seal_finalize, post_seal_finalize, apply_transaction, mk_receipt_sha, \
15+
mk_transaction_sha, calc_difficulty, Receipt, mk_receipt, \
16+
update_block_env_variables, validate_uncles, validate_block_header
1417
from ethereum.utils import encode_hex, parse_as_bin, big_endian_to_int
1518

1619
log = get_logger('eth.chain')
@@ -70,9 +73,9 @@ def __init__(self, genesis=None, env=None, coinbase=b'\x00' * 20, \
7073
self.db.put('GENESIS_HASH', str(self.genesis.header.hash))
7174
self.db.put('GENESIS_STATE', json.dumps(self.state.to_snapshot()))
7275
self.db.put('GENESIS_RLP', rlp.encode(self.genesis))
73-
self.db.put('score:' + self.genesis.header.hash, "0")
74-
self.db.put('state:' + self.genesis.header.hash, self.state.trie.root_hash)
75-
self.db.put('block:0', self.genesis.header.hash)
76+
self.db.put(b'score:' + self.genesis.header.hash, "0")
77+
self.db.put(b'state:' + self.genesis.header.hash, self.state.trie.root_hash)
78+
self.db.put(b'block:0', self.genesis.header.hash)
7679
self.db.put(self.head_hash, 'GENESIS')
7780
self.db.commit()
7881
else:
@@ -105,7 +108,7 @@ def mk_poststate_of_blockhash(self, blockhash, convert=False):
105108
block = rlp.decode(block_rlp, Block)
106109

107110
state = State(env=self.env)
108-
state.trie.root_hash = block.header.state_root if convert else self.db.get('state:'+blockhash)
111+
state.trie.root_hash = block.header.state_root if convert else self.db.get(b'state:'+blockhash)
109112
update_block_env_variables(state, block)
110113
state.gas_used = block.header.gas_used
111114
state.txindex = len(block.transactions)
@@ -158,18 +161,18 @@ def get_block(self, blockhash):
158161
# parent hash and see that it is one of its children
159162
def add_child(self, child):
160163
try:
161-
existing = self.db.get('ci:' + child.header.prevhash)
164+
existing = self.db.get(b'child:' + child.header.prevhash)
162165
except:
163-
existing = ''
166+
existing = b''
164167
existing_hashes = []
165168
for i in range(0, len(existing), 32):
166169
existing_hashes.append(existing[i: i+32])
167170
if child.header.hash not in existing_hashes:
168-
self.db.put('ci:' + child.header.prevhash, existing + child.header.hash)
171+
self.db.put(b'child:' + child.header.prevhash, existing + child.header.hash)
169172

170173
def get_blockhash_by_number(self, number):
171174
try:
172-
return self.db.get('block:' + str(number))
175+
return self.db.get(b'block:' + str(number))
173176
except:
174177
return None
175178

@@ -180,7 +183,7 @@ def get_block_by_number(self, number):
180183
def get_child_hashes(self, blockhash):
181184
o = []
182185
try:
183-
data = self.db.get('child:' + blockhash)
186+
data = self.db.get(b'child:' + blockhash)
184187
for i in range(0, len(data), 32):
185188
o.append(data[i:i + 32])
186189
return o
@@ -198,16 +201,16 @@ def get_children(self, block):
198201
def get_score(self, block):
199202
if not block:
200203
return 0
201-
key = 'score:' + block.header.hash
204+
key = b'score:' + block.header.hash
202205

203206
fills = []
204207
while key not in self.db:
205208
fills.insert(0, (block.header.hash, block.difficulty))
206-
key = 'score:' + block.header.prevhash
209+
key = b'score:' + block.header.prevhash
207210
block = self.get_parent(block)
208211
score = int(self.db.get(key))
209212
for h,d in fills:
210-
key = 'score:' + h
213+
key = b'score:' + h
211214
score = score + d + random.randrange(d // 10**6 + 1)
212215
self.db.put(key, str(score))
213216

@@ -255,52 +258,52 @@ def add_block(self, block):
255258
except (KeyError, ValueError) as e: # FIXME add relevant exceptions here
256259
log.info('Block %s with parent %s invalid, reason: %s' % (encode_hex(block.header.hash), encode_hex(block.header.prevhash), e))
257260
return False
258-
self.db.put('block:' + str(block.header.number), block.header.hash)
259-
self.db.put('state:' + block.header.hash, self.state.trie.root_hash)
261+
self.db.put(b'block:' + str(block.header.number), block.header.hash)
262+
self.db.put(b'state:' + block.header.hash, self.state.trie.root_hash)
260263
block_score = self.get_score(block) # side effect: put 'score:' cache in db
261264
self.head_hash = block.header.hash
262265
for i, tx in enumerate(block.transactions):
263-
self.db.put('txindex:' + tx.hash, rlp.encode([block.number, i]))
266+
self.db.put(b'txindex:' + tx.hash, rlp.encode([block.number, i]))
264267
elif block.header.prevhash in self.env.db:
265268
log.info('Receiving block not on head, adding to secondary post state',
266269
prevhash=encode_hex(block.header.prevhash))
267270
temp_state = self.mk_poststate_of_blockhash(block.header.prevhash)
268271
try:
269272
apply_block(temp_state, block)
270-
except (KeyError, ValueError), e: # FIXME add relevant exceptions here
273+
except (KeyError, ValueError) as e: # FIXME add relevant exceptions here
271274
log.info('Block %s with parent %s invalid, reason: %s' % (encode_hex(block.header.hash), encode_hex(block.header.prevhash), e))
272275
return False
273-
self.db.put('state:' + block.header.hash, temp_state.trie.root_hash)
276+
self.db.put(b'state:' + block.header.hash, temp_state.trie.root_hash)
274277
block_score = self.get_score(block)
275278
# Replace the head
276279
if block_score > self.get_score(self.head):
277280
b = block
278281
new_chain = {}
279282
while b.header.number >= int(self.db.get('GENESIS_NUMBER')):
280283
new_chain[b.header.number] = b
281-
key = 'block:' + str(b.header.number)
284+
key = b'block:' + str(b.header.number)
282285
orig_at_height = self.db.get(key) if key in self.db else None
283286
if orig_at_height == b.header.hash:
284287
break
285288
if b.prevhash not in self.db or self.db.get(b.prevhash) == 'GENESIS':
286289
break
287290
b = self.get_parent(b)
288291
replace_from = b.header.number
289-
for i in xrange(replace_from, 2**63 - 1):
292+
for i in itertools.count(replace_from):
290293
log.info('Rewriting height %d' % i)
291-
key = 'block:' + str(i)
294+
key = b'block:' + str(i)
292295
orig_at_height = self.db.get(key) if key in self.db else None
293296
if orig_at_height:
294297
self.db.delete(key)
295298
orig_block_at_height = self.get_block(orig_at_height)
296299
for tx in orig_block_at_height.transactions:
297-
if 'txindex:' + tx.hash in self.db:
298-
self.db.delete('txindex:' + tx.hash)
300+
if b'txindex:' + tx.hash in self.db:
301+
self.db.delete(b'txindex:' + tx.hash)
299302
if i in new_chain:
300303
new_block_at_height = new_chain[i]
301304
self.db.put(key, new_block_at_height.header.hash)
302305
for i, tx in enumerate(new_block_at_height.transactions):
303-
self.db.put('txindex:' + tx.hash,
306+
self.db.put(b'txindex:' + tx.hash,
304307
rlp.encode([new_block_at_height.number, i]))
305308
if i not in new_chain and not orig_at_height:
306309
break
@@ -346,7 +349,7 @@ def get_chain(self, frm=None, to=2**63 - 1):
346349
if frm is None:
347350
frm = int(self.db.get('GENESIS_NUMBER')) + 1
348351
chain = []
349-
for i in xrange(frm, to):
352+
for i in itertools.islice(itertools.count(), frm, to):
350353
h = self.get_blockhash_by_number(i)
351354
if not h:
352355
return chain
@@ -356,8 +359,8 @@ def get_chain(self, frm=None, to=2**63 - 1):
356359
def get_transaction(self, tx):
357360
if not isinstance(tx, (str, bytes)):
358361
tx = tx.hash
359-
if 'txindex:' + tx in self.db:
360-
data = rlp.decode(self.db.get('txindex:' + tx))
362+
if b'txindex:' + tx in self.db:
363+
data = rlp.decode(self.db.get(b'txindex:' + tx))
361364
blk, index = self.get_block_by_number(
362365
big_endian_to_int(data[0])), big_endian_to_int(data[1])
363366
tx = blk.transactions[index]

ethereum/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
GASLIMIT_ADJMAX_FACTOR=1024,
2929
BLKLIM_FACTOR_NOM=3,
3030
BLKLIM_FACTOR_DEN=2,
31+
# Network ID
32+
NETWORK_ID=1,
3133
# Block reward
3234
BLOCK_REWARD=5000 * utils.denoms.finney,
3335
NEPHEW_REWARD=5000 * utils.denoms.finney // 32, # BLOCK_REWARD / 32

ethereum/consensus_strategy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def __init__(self, header_check, header_validate, uncle_validate, block_setup, b
1010

1111
def get_consensus_strategy(config):
1212
if config['CONSENSUS_STRATEGY'] in ('pow', 'ethpow', 'ethash', 'ethereum1'):
13-
from ethpow_utils import ethereum1_check_header, ethereum1_validate_header, \
13+
from ethereum.ethpow_utils import ethereum1_check_header, ethereum1_validate_header, \
1414
ethereum1_validate_uncle, ethereum1_pre_finalize_block, \
1515
ethereum1_post_finalize_block, ethereum1_setup_block
1616
return ConsensusStrategy(
@@ -23,7 +23,7 @@ def get_consensus_strategy(config):
2323
state_initialize=None
2424
)
2525
elif config['CONSENSUS_STRATEGY'] == 'casper':
26-
from casper_utils import casper_validate_header, casper_state_initialize, casper_post_finalize_block, casper_setup_block
26+
from ethereum.casper_utils import casper_validate_header, casper_state_initialize, casper_post_finalize_block, casper_setup_block
2727
return ConsensusStrategy(
2828
header_check=None,
2929
header_validate=casper_validate_header,

ethereum/new_statetest_utils.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
from ethereum.state import State
2+
from ethereum.block import FakeHeader, Block
3+
from ethereum.utils import decode_hex, parse_int_or_hex, sha3, to_string, \
4+
remove_0x_head, encode_hex, big_endian_to_int
5+
from ethereum.config import default_config, Env
6+
from ethereum.exceptions import InvalidTransaction
7+
import ethereum.transactions as transactions
8+
import ethereum.state_transition as state_transition
9+
import copy
10+
11+
from ethereum.slogging import LogRecorder, configure_logging, set_level
12+
config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug'
13+
14+
configure_logging(config_string=config_string)
15+
16+
fake_headers = {}
17+
18+
def mk_fake_header(blknum):
19+
if blknum not in fake_headers:
20+
fake_headers[blknum] = FakeHeader(sha3(to_string(blknum)))
21+
return fake_headers[blknum]
22+
23+
basic_env = {
24+
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
25+
"currentDifficulty": "256",
26+
"currentGasLimit": "1000000000",
27+
"currentNumber": "257",
28+
"currentTimestamp": "1",
29+
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
30+
}
31+
32+
konfig = copy.copy(default_config)
33+
34+
konfig_homestead = copy.copy(konfig)
35+
konfig_homestead["HOMESTEAD_FORK_BLKNUM"] = 0
36+
konfig_homestead["ANTI_DOS_FORK_BLKNUM"] = 2**99
37+
konfig_homestead["SPURIOUS_DRAGON_FORK_BLKNUM"] = 2**99
38+
konfig_homestead["METROPOLIS_FORK_BLKNUM"] = 2**99
39+
40+
konfig_tangerine = copy.copy(konfig)
41+
konfig_tangerine["HOMESTEAD_FORK_BLKNUM"] = 0
42+
konfig_tangerine["ANTI_DOS_FORK_BLKNUM"] = 0
43+
konfig_tangerine["SPURIOUS_DRAGON_FORK_BLKNUM"] = 2**99
44+
konfig_tangerine["METROPOLIS_FORK_BLKNUM"] = 2**99
45+
46+
konfig_spurious = copy.copy(konfig)
47+
konfig_spurious["HOMESTEAD_FORK_BLKNUM"] = 0
48+
konfig_spurious["ANTI_DOS_FORK_BLKNUM"] = 0
49+
konfig_spurious["SPURIOUS_DRAGON_FORK_BLKNUM"] = 0
50+
konfig_spurious["METROPOLIS_FORK_BLKNUM"] = 2**99
51+
52+
konfig_metropolis = copy.copy(konfig)
53+
konfig_metropolis["HOMESTEAD_FORK_BLKNUM"] = 0
54+
konfig_metropolis["ANTI_DOS_FORK_BLKNUM"] = 0
55+
konfig_metropolis["SPURIOUS_DRAGON_FORK_BLKNUM"] = 0
56+
konfig_metropolis["METROPOLIS_FORK_BLKNUM"] = 0
57+
58+
configs = {
59+
#"Homestead": konfig_homestead,
60+
"EIP150": konfig_tangerine,
61+
"EIP158": konfig_spurious,
62+
"Metropolis": konfig_metropolis
63+
}
64+
65+
def compute_state_test_unit(state, txdata, indices, konfig):
66+
state.env.config = konfig
67+
s = state.snapshot()
68+
try:
69+
# Create the transaction
70+
tx = transactions.Transaction(
71+
nonce=parse_int_or_hex(txdata['nonce'] or b"0"),
72+
gasprice=parse_int_or_hex(txdata['gasPrice'] or b"0"),
73+
startgas=parse_int_or_hex(txdata['gasLimit'][indices["gas"]] or b"0"),
74+
to=decode_hex(txdata['to']),
75+
value=parse_int_or_hex(txdata['value'][indices["value"]] or b"0"),
76+
data=decode_hex(remove_0x_head(txdata['data'][indices["data"]])))
77+
tx.sign(decode_hex(txdata['secretKey']))
78+
# Run it
79+
success, output = state_transition.apply_transaction(state, tx)
80+
print("Applied tx")
81+
except InvalidTransaction as e:
82+
print("Exception: %r" % e)
83+
success, output = False, b''
84+
state.commit()
85+
output_decl = {
86+
"hash": encode_hex(state.trie.root_hash),
87+
"indexes": indices
88+
}
89+
state.revert(s)
90+
return output_decl
91+
92+
93+
def init_state(env, pre):
94+
# Setup env
95+
state = State(
96+
env=Env(config=konfig),
97+
block_prevhash=decode_hex(env['previousHash']),
98+
prev_headers=[mk_fake_header(i) for i in range(parse_int_or_hex(env['currentNumber']) -1,
99+
max(-1, parse_int_or_hex(env['currentNumber']) -257), -1)],
100+
block_number=parse_int_or_hex(env['currentNumber']),
101+
block_coinbase=decode_hex(env['currentCoinbase']),
102+
block_difficulty=parse_int_or_hex(env['currentDifficulty']),
103+
gas_limit=parse_int_or_hex(env['currentGasLimit']),
104+
timestamp=parse_int_or_hex(env['currentTimestamp']))
105+
106+
# Fill up pre
107+
for address, h in list(pre.items()):
108+
assert len(address) == 40
109+
address = decode_hex(address)
110+
assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage'])
111+
state.set_nonce(address, parse_int_or_hex(h['nonce']))
112+
state.set_balance(address, parse_int_or_hex(h['balance']))
113+
state.set_code(address, decode_hex(h['code'][2:]))
114+
for k, v in h['storage'].items():
115+
state.set_storage_data(address,
116+
big_endian_to_int(decode_hex(k[2:])),
117+
decode_hex(v[2:]))
118+
119+
state.commit()
120+
return state
121+
122+
def verify_state_test(test):
123+
print("Verifying state test")
124+
_state = init_state(test["env"], test["pre"])
125+
for config_name, results in test["post"].items():
126+
# Old protocol versions may not be supported
127+
if config_name not in configs:
128+
continue
129+
print("Testing for %s" % config_name)
130+
for result in results:
131+
print("Checking for values: g %d v %d d %s" % (
132+
parse_int_or_hex(test["transaction"]['gasLimit'][result["indexes"]["gas"]]),
133+
parse_int_or_hex(test["transaction"]['value'][result["indexes"]["value"]]),
134+
test["transaction"]['data'][result["indexes"]["data"]]))
135+
computed = compute_state_test_unit(_state, test["transaction"], result["indexes"], configs[config_name])
136+
if computed["hash"] != result["hash"]:
137+
raise Exception("Hash mismatch, computed: %s, supplied: %s" % (computed["hash"], result["hash"]))
138+
else:
139+
print("Hash matched!: %s" % computed["hash"])

0 commit comments

Comments
 (0)