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

Commit bc59edb

Browse files
vubvub
authored andcommitted
Fixed homestead changes
1 parent 06e3c81 commit bc59edb

File tree

11 files changed

+140
-37
lines changed

11 files changed

+140
-37
lines changed

ethereum/fast_rlp.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sys
22
import rlp
3-
from utils import int_to_big_endian
3+
from utils import int_to_big_endian, big_endian_to_int, safe_ord
44
import db
55

66

@@ -29,11 +29,51 @@ def length_prefix(length, offset):
2929
length_string = int_to_big_endian(length)
3030
return chr(offset + 56 - 1 + len(length_string)) + length_string
3131

32+
def _decode_optimized(rlp):
33+
o = []
34+
pos = 0
35+
_typ, _len, pos = consume_length_prefix(rlp, pos)
36+
if _typ != list:
37+
return rlp[pos: pos + _len]
38+
while pos < len(rlp):
39+
_, _l, _p = consume_length_prefix(rlp, pos)
40+
o.append(_decode_optimized(rlp[pos: _l + _p]))
41+
pos = _l + _p
42+
return o
43+
44+
def consume_length_prefix(rlp, start):
45+
"""Read a length prefix from an RLP string.
46+
47+
:param rlp: the rlp string to read from
48+
:param start: the position at which to start reading
49+
:returns: a tuple ``(type, length, end)``, where ``type`` is either ``str``
50+
or ``list`` depending on the type of the following payload,
51+
``length`` is the length of the payload in bytes, and ``end`` is
52+
the position of the first payload byte in the rlp string
53+
"""
54+
b0 = safe_ord(rlp[start])
55+
if b0 < 128: # single byte
56+
return (str, 1, start)
57+
elif b0 < 128 + 56: # short string
58+
return (str, b0 - 128, start + 1)
59+
elif b0 < 192: # long string
60+
ll = b0 - 128 - 56 + 1
61+
l = big_endian_to_int(rlp[start + 1:start + 1 + ll])
62+
return (str, l, start + 1 + ll)
63+
elif b0 < 192 + 56: # short list
64+
return (list, b0 - 192, start + 1)
65+
else: # long list
66+
ll = b0 - 192 - 56 + 1
67+
l = big_endian_to_int(rlp[start + 1:start + 1 + ll])
68+
return (list, l, start + 1 + ll)
69+
3270
#
3371
if sys.version_info.major == 2:
3472
encode_optimized = _encode_optimized
73+
decode_optimized = _decode_optimized
3574
else:
3675
encode_optimized = rlp.codec.encode_raw
76+
decode_optimized = rlp.codec.decode_raw
3777

3878

3979
def main():

ethereum/opcodes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
0xf1: ['CALL', 7, 1, 40],
6666
0xf2: ['CALLCODE', 7, 1, 40],
6767
0xf3: ['RETURN', 2, 0, 0],
68-
0xf4: ['DELEGATECALL', 2, 0, 0],
68+
0xf4: ['DELEGATECALL', 6, 0, 40],
6969
0xff: ['SUICIDE', 1, 0, 0],
7070
}
7171

ethereum/processblock.py

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from ethereum import bloom
99
from ethereum import vm as vm
1010
from ethereum.exceptions import *
11-
from ethereum.utils import safe_ord, normalize_address
11+
from ethereum.utils import safe_ord, normalize_address, mk_contract_address
12+
from ethereum import transactions
1213

1314
sys.setrecursionlimit(100000)
1415

@@ -27,10 +28,6 @@
2728
CREATE_CONTRACT_ADDRESS = b''
2829

2930

30-
def mk_contract_address(sender, nonce):
31-
return utils.sha3(rlp.encode([normalize_address(sender), nonce]))[12:]
32-
33-
3431
def verify(block, parent):
3532
from ethereum import blocks
3633
try:
@@ -75,14 +72,6 @@ def __repr__(self):
7572
(encode_hex(self.address), self.topics, self.data)
7673

7774

78-
def intrinsic_gas_used(tx):
79-
num_zero_bytes = str_to_bytes(tx.data).count(ascii_chr(0))
80-
num_non_zero_bytes = len(tx.data) - num_zero_bytes
81-
return (opcodes.GTXCOST
82-
+ opcodes.GTXDATAZERO * num_zero_bytes
83-
+ opcodes.GTXDATANONZERO * num_non_zero_bytes)
84-
85-
8675
def validate_transaction(block, tx):
8776

8877
def rp(what, actual, target):
@@ -100,8 +89,8 @@ def rp(what, actual, target):
10089

10190
# (3) the gas limit is no smaller than the intrinsic gas,
10291
# g0, used by the transaction;
103-
if tx.startgas < intrinsic_gas_used(tx):
104-
raise InsufficientStartGas(rp('startgas', tx.startgas, intrinsic_gas_used))
92+
if tx.startgas < tx.intrinsic_gas_used:
93+
raise InsufficientStartGas(rp('startgas', tx.startgas, tx.intrinsic_gas_used))
10594

10695
# (4) the sender account balance contains at least the
10796
# cost, v0, required in up-front payment.
@@ -119,18 +108,22 @@ def rp(what, actual, target):
119108
def apply_transaction(block, tx):
120109
validate_transaction(block, tx)
121110

122-
log_tx.debug('TX NEW', tx_dict=tx.log_dict())
123-
# start transacting #################
124-
block.increment_nonce(tx.sender)
125111
# print block.get_nonce(tx.sender), '@@@'
126112

127-
intrinsic_gas = intrinsic_gas_used(tx)
113+
def rp(what, actual, target):
114+
return '%r: %r actual:%r target:%r' % (tx, what, actual, target)
115+
116+
intrinsic_gas = tx.intrinsic_gas_used
128117
if block.number >= block.config['HOMESTEAD_FORK_BLKNUM']:
129118
assert tx.s * 2 < transactions.secpk1n
130119
if not tx.to or tx.to == CREATE_CONTRACT_ADDRESS:
131120
intrinsic_gas += opcodes.CREATE[3]
132121
if tx.startgas < intrinsic_gas:
133122
raise InsufficientStartGas(rp('startgas', tx.startgas, intrinsic_gas))
123+
124+
log_tx.debug('TX NEW', tx_dict=tx.log_dict())
125+
# start transacting #################
126+
block.increment_nonce(tx.sender)
134127

135128
# buy startgas
136129
assert block.get_balance(tx.sender) >= tx.startgas * tx.gasprice
@@ -290,6 +283,7 @@ def create_contract(ext, msg):
290283
# assert not ext.get_code(msg.to)
291284
code = msg.data.extract_all()
292285
msg.data = vm.CallData([], 0, 0)
286+
snapshot = ext._block.snapshot()
293287
res, gas, dat = _apply_msg(ext, msg, code)
294288
assert utils.is_numeric(gas)
295289

@@ -301,10 +295,10 @@ def create_contract(ext, msg):
301295
gas -= gcost
302296
else:
303297
dat = []
304-
#print('CONTRACT CREATION OOG', 'have', gas, 'want', gcost)
298+
log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost)
305299
if ext._block.number >= ext._block.config['HOMESTEAD_FORK_BLKNUM']:
300+
ext._block.revert(snapshot)
306301
return 0, 0, b''
307-
log_msg.debug('CONTRACT CREATION OOG', have=gas, want=gcost)
308302
ext._block.set_code(msg.to, b''.join(map(ascii_chr, dat)))
309303
return 1, gas, msg.to
310304
else:

ethereum/slogging.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
known_loggers = set()
1717

1818
log_listeners = []
19+
print_logs=True
1920

2021

2122
# add level trace into logging
@@ -38,12 +39,17 @@ class LogRecorder(object):
3839
def __init__(self):
3940
self._records = []
4041
log_listeners.append(self._add_log_record)
42+
global print_logs
43+
self.prev_print_logs = print_logs
44+
print_logs = False
4145

4246
def pop_records(self):
4347
# can only be called once
4448
r = self._records[:]
4549
self._records = None
4650
log_listeners.remove(self._add_log_record)
51+
global print_logs
52+
print_logs = self.prev_print_logs
4753
return r
4854

4955
def _add_log_record(self, msg):
@@ -126,13 +132,17 @@ def bind(self, **kwargs):
126132
return BoundLogger(self, kwargs)
127133

128134
def _log(self, level, msg, args, **kwargs):
135+
for listener in log_listeners:
136+
kwargs['event'] = msg
137+
listener(kwargs)
129138
exc_info = kwargs.pop('exc_info', None)
130139
extra = kwargs.pop('extra', {})
131140
highlight = kwargs.pop('highlight', False)
132141
extra['kwargs'] = kwargs
133142
extra['original_msg'] = msg
134143
msg = self.format_message(msg, kwargs, highlight)
135-
super(SLogger, self)._log(level, msg, args, exc_info, extra)
144+
if print_logs:
145+
super(SLogger, self)._log(level, msg, args, exc_info, extra)
136146

137147
def DEV(self, msg, *args, **kwargs):
138148
"""Shortcut to output highlighted log text"""

ethereum/tester.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ def abi_contract(self, code, sender=k0, endowment=0, language='serpent', contrac
167167
_abi = language.mk_full_signature(code, **cn_args)
168168
return ABIContract(self, _abi, address, listen=listen, log_listener=log_listener)
169169

170+
def clear_listeners(self):
171+
while len(self.block.log_listeners):
172+
self.block.log_listeners.pop()
173+
170174
def evm(self, evm, sender=k0, endowment=0, gas=None):
171175
sendnonce = self.block.get_nonce(u.privtoaddr(sender))
172176
tx = t.contract(sendnonce, gas_price, gas_limit, endowment, evm)
@@ -195,21 +199,25 @@ def _send(self, sender, to, value, evmdata='', output=None,
195199
tx = t.Transaction(sendnonce, gas_price, gas_limit, to, value, evmdata)
196200
self.last_tx = tx
197201
tx.sign(sender)
198-
recorder = LogRecorder() if profiling > 1 else None
202+
if profiling > 1:
203+
set_logging_level(3)
204+
recorder = LogRecorder()
199205
(s, o) = pb.apply_transaction(self.block, tx)
200206
if not s:
201207
raise TransactionFailed()
202208
out = {"output": o}
203209
if profiling > 0:
204210
zero_bytes = tx.data.count(ascii_chr(0))
205211
non_zero_bytes = len(tx.data) - zero_bytes
206-
intrinsic_gas_used = opcodes.GTXDATAZERO * zero_bytes + \
212+
intrinsic_gas_used = opcodes.GTXCOST + \
213+
opcodes.GTXDATAZERO * zero_bytes + \
207214
opcodes.GTXDATANONZERO * non_zero_bytes
208215
ntm, ng = time.time(), self.block.gas_used
209216
out["time"] = ntm - tm
210217
out["gas"] = ng - g - intrinsic_gas_used
211218
if profiling > 1:
212219
trace = recorder.pop_records()
220+
set_logging_level(0)
213221
ops = [x['op'] for x in trace if x['event'] == 'vm']
214222
opdict = {}
215223
for op in ops:

ethereum/tests/test_contracts.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,34 @@ def test_params_contract():
16321632
c = s.abi_contract(params_code, FOO=4, BAR='horse')
16331633
assert c.garble() == 4
16341634
assert c.marble() == 'horse'
1635+
1636+
prefix_types_in_functions_code = """
1637+
type fixedp: fp_
1638+
1639+
macro fixedp($x) * fixedp($y):
1640+
fixedp($x * $y / 2^64)
1641+
1642+
macro fixedp($x) / fixedp($y):
1643+
fixedp($x * 2^64 / $y)
1644+
1645+
macro raw_unfixedp(fixedp($x)):
1646+
$x / 2^64
1647+
1648+
macro set(fixedp($x), $y):
1649+
$x = 2^64 * $y
1650+
1651+
macro fixedp($x) = fixedp($y):
1652+
$x = $y
1653+
1654+
def sqrdiv(fp_a, fp_b):
1655+
return(raw_unfixedp((fp_a / fp_b) * (fp_a / fp_b)))
1656+
"""
1657+
1658+
1659+
def test_prefix_types_in_functions():
1660+
s = tester.state()
1661+
c = s.abi_contract(prefix_types_in_functions_code)
1662+
assert c.sqrdiv(25, 2) == 156
16351663

16361664

16371665

@@ -1684,3 +1712,4 @@ def test_params_contract():
16841712
# test_abi_address_output = None
16851713
# test_string_logging = None
16861714
# test_params_contract = None
1715+
# test_prefix_types_in_functions = None

ethereum/testutils.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import copy
88
from ethereum.db import EphemDB
99
from ethereum.utils import to_string, safe_ord, parse_int_or_hex
10-
from ethereum.utils import remove_0x_head, int_to_hex
10+
from ethereum.utils import remove_0x_head, int_to_hex, normalize_address
1111
from ethereum.config import Env
1212
import json
1313
import os
@@ -27,6 +27,10 @@
2727
"previousHash": b"5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
2828
}
2929

30+
# from ethereum.slogging import LogRecorder, configure_logging, set_level
31+
# config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace'
32+
# configure_logging(config_string=config_string)
33+
3034
FILL = 1
3135
VERIFY = 2
3236
TIME = 3
@@ -332,7 +336,7 @@ def blkhash(n):
332336
nonce=parse_int_or_hex(exek['nonce'] or b"0"),
333337
gasprice=parse_int_or_hex(exek['gasPrice'] or b"0"),
334338
startgas=parse_int_or_hex(exek['gasLimit'] or b"0"),
335-
to=decode_hex(exek['to'][2:] if exek['to'][:2] == b'0x' else exek['to']),
339+
to=normalize_address(exek['to'], allow_blank=True),
336340
value=parse_int_or_hex(exek['value'] or b"0"),
337341
data=decode_hex(remove_0x_head(exek['data'])))
338342
except InvalidTransaction:
@@ -352,8 +356,10 @@ def blkhash(n):
352356

353357
time_pre = time.time()
354358
try:
359+
print 'trying'
355360
success, output = pb.apply_transaction(blk, tx)
356361
blk.commit_state()
362+
print 'success', blk.get_receipts()[-1].gas_used
357363
except pb.InvalidTransaction:
358364
success, output = False, b''
359365
blk.commit_state()
@@ -372,7 +378,6 @@ def blkhash(n):
372378
params2['out'] = b'0x' + encode_hex(output)
373379
params2['post'] = copy.deepcopy(blk.to_dict(True)['state'])
374380
params2['postStateRoot'] = encode_hex(blk.state.root_hash)
375-
assert 'post' in params # we always have a post state in the tests
376381

377382
if mode == FILL:
378383
return params2

ethereum/transactions.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
from bitcoin import ecdsa_raw_sign, ecdsa_raw_recover
66
import rlp
77
from rlp.sedes import big_endian_int, binary
8-
from rlp.utils import decode_hex, encode_hex
8+
from rlp.utils import decode_hex, encode_hex, str_to_bytes, ascii_chr
99
from ethereum import bloom
1010
from ethereum import utils
11-
from ethereum.processblock import mk_contract_address, intrinsic_gas_used
12-
from ethereum.utils import TT256
11+
from ethereum.utils import TT256, mk_contract_address
1312
from ethereum.exceptions import InvalidTransaction
1413
from ethereum.slogging import get_logger
14+
from ethereum import opcodes
1515
log = get_logger('eth.chain.tx')
1616

1717
# in the yellow paper it is specified that s should be smaller than secpk1n (eq.205)
@@ -61,7 +61,7 @@ def __init__(self, nonce, gasprice, startgas, to, value, data, v=0, r=0, s=0):
6161
if self.gasprice >= TT256 or self.startgas >= TT256 or \
6262
self.value >= TT256 or self.nonce >= TT256:
6363
raise InvalidTransaction("Values way too high!")
64-
if self.startgas < intrinsic_gas_used(self):
64+
if self.startgas < self.intrinsic_gas_used:
6565
raise InvalidTransaction("Startgas too low")
6666

6767
log.debug('deserialized tx', tx=encode_hex(self.hash)[:8])
@@ -133,6 +133,14 @@ def log_dict(self):
133133
d['to'] = encode_hex(d['to'])
134134
return d
135135

136+
@property
137+
def intrinsic_gas_used(self):
138+
num_zero_bytes = str_to_bytes(self.data).count(ascii_chr(0))
139+
num_non_zero_bytes = len(self.data) - num_zero_bytes
140+
return (opcodes.GTXCOST
141+
+ opcodes.GTXDATAZERO * num_zero_bytes
142+
+ opcodes.GTXDATANONZERO * num_non_zero_bytes)
143+
136144
@property
137145
def creates(self):
138146
"returns the address of a contract created by this tx"

ethereum/utils.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ def to_string_for_regexp(value):
5858
isnumeric = is_numeric
5959

6060

61+
def mk_contract_address(sender, nonce):
62+
return sha3(rlp.encode([normalize_address(sender), nonce]))[12:]
63+
64+
6165
def safe_ord(value):
6266
if isinstance(value, int):
6367
return value
@@ -139,7 +143,7 @@ def normalize_address(x, allow_blank=False):
139143
assert len(x) == 24 and sha3(x[:20])[:4] == x[-4:]
140144
x = x[:20]
141145
if len(x) != 20:
142-
raise Exception("Invalid address format!")
146+
raise Exception("Invalid address format: %r" % x)
143147
return x
144148

145149

0 commit comments

Comments
 (0)