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

Commit 3d3fb19

Browse files
committed
Fixed some bugs, added more precompile support
1 parent 990a85d commit 3d3fb19

File tree

11 files changed

+445
-51
lines changed

11 files changed

+445
-51
lines changed

ethereum/config.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from ethereum import utils
44
from ethereum.db import BaseDB, EphemDB
55
from ethereum.child_dao_list import L as child_dao_list
6+
import copy
67

78
default_config = dict(
89
# Genesis block difficulty
@@ -88,3 +89,27 @@ def __init__(self, db=None, config=None, global_config=None):
8889
assert isinstance(self.db, BaseDB)
8990
self.config = config or dict(default_config)
9091
self.global_config = global_config or dict()
92+
93+
config_homestead = copy.copy(default_config)
94+
config_homestead["HOMESTEAD_FORK_BLKNUM"] = 0
95+
config_homestead["ANTI_DOS_FORK_BLKNUM"] = 2**99
96+
config_homestead["CLEARING_FORK_BLKNUM"] = 2**99
97+
config_homestead["METROPOLIS_FORK_BLKNUM"] = 2**99
98+
99+
config_tangerine = copy.copy(default_config)
100+
config_tangerine["HOMESTEAD_FORK_BLKNUM"] = 0
101+
config_tangerine["ANTI_DOS_FORK_BLKNUM"] = 0
102+
config_tangerine["CLEARING_FORK_BLKNUM"] = 2**99
103+
config_tangerine["METROPOLIS_FORK_BLKNUM"] = 2**99
104+
105+
config_spurious = copy.copy(default_config)
106+
config_spurious["HOMESTEAD_FORK_BLKNUM"] = 0
107+
config_spurious["ANTI_DOS_FORK_BLKNUM"] = 0
108+
config_spurious["CLEARING_FORK_BLKNUM"] = 0
109+
config_spurious["METROPOLIS_FORK_BLKNUM"] = 2**99
110+
111+
config_metropolis = copy.copy(default_config)
112+
config_metropolis["HOMESTEAD_FORK_BLKNUM"] = 0
113+
config_metropolis["ANTI_DOS_FORK_BLKNUM"] = 0
114+
config_metropolis["CLEARING_FORK_BLKNUM"] = 0
115+
config_metropolis["METROPOLIS_FORK_BLKNUM"] = 0

ethereum/messages.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ def validate_transaction(state, tx):
157157
if state.gas_used + tx.startgas > state.gas_limit:
158158
raise BlockGasLimitReached(rp(tx, 'gaslimit', state.gas_used + tx.startgas, state.gas_limit))
159159

160+
# EIP86-specific restrictions
161+
if tx.sender == null_address and (tx.value != 0 or tx.gasprice != 0):
162+
raise InvalidTransaction("EIP86 transactions must have 0 value and gasprice")
163+
160164
return True
161165

162166

@@ -184,7 +188,7 @@ def apply_transaction(state, tx):
184188
if tx.startgas < intrinsic_gas:
185189
raise InsufficientStartGas(rp(tx, 'startgas', tx.startgas, intrinsic_gas))
186190

187-
log_tx.debug('TX NEW', txdict=tx.to_dict(), a1=tx.intrinsic_gas_used, a2=intrinsic_gas, to=tx.to, h=state.is_HOMESTEAD())
191+
log_tx.debug('TX NEW', txdict=tx.to_dict())
188192

189193
# start transacting #################
190194
if tx.sender != null_address:
@@ -319,7 +323,8 @@ def _apply_msg(ext, msg, code):
319323
if trace_msg:
320324
log_msg.debug("MSG APPLY", sender=encode_hex(msg.sender), to=encode_hex(msg.to),
321325
gas=msg.gas, value=msg.value,
322-
data=encode_hex(msg.data.extract_all()) if msg.data.size < 2500 else ("data<%d>" % msg.data.size))
326+
data=encode_hex(msg.data.extract_all()) if msg.data.size < 2500 else ("data<%d>" % msg.data.size),
327+
pre_storage=ext.log_storage(msg.to))
323328

324329
# Transfer value, instaquit if not enough
325330
snapshot = ext.snapshot()
@@ -339,7 +344,8 @@ def _apply_msg(ext, msg, code):
339344
if trace_msg:
340345
log_msg.debug('MSG APPLIED', gas_remained=gas,
341346
sender=encode_hex(msg.sender), to=encode_hex(msg.to),
342-
data=dat if len(dat) < 2500 else ("data<%d>" % len(dat)))
347+
data=dat if len(dat) < 2500 else ("data<%d>" % len(dat)),
348+
post_storage=ext.log_storage(msg.to))
343349

344350
if res == 0:
345351
log_msg.debug('REVERTING')
@@ -374,7 +380,8 @@ def create_contract(ext, msg):
374380
# assert not ext.get_code(msg.to)
375381
msg.data = vm.CallData([], 0, 0)
376382
snapshot = ext.snapshot()
377-
# if len(ext.get_code(msg.to)):
383+
if len(ext.get_code(msg.to)):
384+
log_msg.debug('CREATING CONTRACT ON TOP OF EXISTING CONTRACT')
378385
# return 0, 0, b''
379386

380387
ext.set_nonce(msg.to, 1 if ext.post_clearing_hardfork() else 0)

ethereum/opcodes.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,7 @@
134134
CALL_CHILD_LIMIT_DENOM = 64
135135
SUICIDE_SUPPLEMENTAL_GAS = 5000
136136
EXP_SUPPLEMENTAL_GAS = 40
137+
138+
GMODEXPQUADDIVISOR = 20
139+
GECADD = 500
140+
GECMUL = 2000

ethereum/specials.py

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from rlp.utils import ascii_chr
44

55
from ethereum import utils, opcodes
6-
from ethereum.utils import safe_ord, decode_hex
6+
from ethereum.utils import safe_ord, decode_hex, encode_int32
77

88

99
ZERO_PRIVKEY_ADDR = decode_hex('3f17f1962b36e491b30a40b2405849e597ba5fb5')
@@ -71,13 +71,87 @@ def proc_identity(ext, msg):
7171
msg.data.extract_copy(o, 0, 0, len(o))
7272
return 1, msg.gas - gas_cost, o
7373

74+
def proc_modexp(ext, msg):
75+
if not ext.post_metropolis_hardfork():
76+
return 1, msg.gas, []
77+
print('modexp proc', msg.gas)
78+
baselen = msg.data.extract32(0)
79+
explen = msg.data.extract32(32)
80+
modlen = msg.data.extract32(64)
81+
gas_cost = (max(modlen, baselen) ** 2 * max(explen, 1)) // opcodes.GMODEXPQUADDIVISOR
82+
print(baselen, explen, modlen, 'expected gas cost', gas_cost)
83+
if msg.gas < gas_cost:
84+
return 0, 0, []
85+
base = bytearray(baselen)
86+
msg.data.extract_copy(base, 0, 96, baselen)
87+
exp = bytearray(explen)
88+
msg.data.extract_copy(exp, 0, 96 + baselen, explen)
89+
mod = bytearray(modlen)
90+
msg.data.extract_copy(mod, 0, 96 + baselen + explen, modlen)
91+
if utils.big_endian_to_int(mod) == 0:
92+
return 1, msg.gas - gas_cost, [0] * modlen
93+
o = pow(utils.big_endian_to_int(base), utils.big_endian_to_int(exp), utils.big_endian_to_int(mod))
94+
return 1, msg.gas - gas_cost, [safe_ord(x) for x in utils.zpad(utils.int_to_big_endian(o), modlen)]
95+
96+
def validate_point(x, y):
97+
import py_pairing
98+
FQ = py_pairing.FQ
99+
if x >= py_pairing.field_modulus or y >= py_pairing.field_modulus:
100+
return False
101+
if (x, y) != (0, 0):
102+
p1 = (FQ(x), FQ(y), FQ(1))
103+
if not py_pairing.is_on_curve(p1, py_pairing.b):
104+
return False
105+
else:
106+
p1 = (FQ(1), FQ(1), FQ(0))
107+
return p1
108+
109+
def proc_ecadd(ext, msg):
110+
if not ext.post_metropolis_hardfork():
111+
return 1, msg.gas, []
112+
import py_pairing
113+
FQ = py_pairing.FQ
114+
print('ecadd proc', msg.gas)
115+
if msg.gas < opcodes.GECADD:
116+
return 0, 0, []
117+
x1 = msg.data.extract32(0)
118+
y1 = msg.data.extract32(32)
119+
x2 = msg.data.extract32(64)
120+
y2 = msg.data.extract32(96)
121+
p1 = validate_point(x1, y1)
122+
p2 = validate_point(x2, y2)
123+
if p1 is False or p2 is False:
124+
return 0, 0, []
125+
o = py_pairing.normalize(py_pairing.add(p1, p2))
126+
return 1, msg.gas - opcodes.GECADD, [safe_ord(x) for x in (encode_int32(o[0].n) + encode_int32(o[1].n))]
127+
128+
def proc_ecmul(ext, msg):
129+
if not ext.post_metropolis_hardfork():
130+
return 1, msg.gas, []
131+
import py_pairing
132+
FQ = py_pairing.FQ
133+
print('ecmul proc', msg.gas)
134+
if msg.gas < opcodes.GECMUL:
135+
return 0, 0, []
136+
x = msg.data.extract32(0)
137+
y = msg.data.extract32(32)
138+
m = msg.data.extract32(64)
139+
p = validate_point(x, y)
140+
if p is False:
141+
return 0, 0, []
142+
o = py_pairing.normalize(py_pairing.multiply(p, m))
143+
return 1, msg.gas - opcodes.GECMUL, [safe_ord(x) for x in (encode_int32(o[0].n) + encode_int32(o[1].n))]
144+
74145
specials = {
75146
decode_hex(k): v for k, v in
76147
{
77148
b'0000000000000000000000000000000000000001': proc_ecrecover,
78149
b'0000000000000000000000000000000000000002': proc_sha256,
79150
b'0000000000000000000000000000000000000003': proc_ripemd160,
80151
b'0000000000000000000000000000000000000004': proc_identity,
152+
b'0000000000000000000000000000000000000005': proc_modexp,
153+
b'0000000000000000000000000000000000000006': proc_ecadd,
154+
b'0000000000000000000000000000000000000007': proc_ecmul,
81155
}.items()
82156
}
83157

ethereum/tools/new_statetest_utils.py

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from ethereum.block import FakeHeader, Block
33
from ethereum.utils import decode_hex, parse_int_or_hex, sha3, to_string, \
44
remove_0x_head, encode_hex, big_endian_to_int
5-
from ethereum.config import default_config, Env
5+
from ethereum.config import default_config, config_homestead, config_tangerine, config_spurious, config_metropolis, Env
66
from ethereum.exceptions import InvalidTransaction
77
import ethereum.transactions as transactions
88
from ethereum.messages import apply_transaction
@@ -13,6 +13,8 @@
1313
from ethereum.slogging import LogRecorder, configure_logging, set_level
1414
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'
1515

16+
konfig=copy.copy(default_config)
17+
1618
# configure_logging(config_string=config_string)
1719

1820
fixture_path = os.path.join(os.path.dirname(__file__), '../..', 'fixtures')
@@ -25,45 +27,20 @@ def mk_fake_header(blknum):
2527
return fake_headers[blknum]
2628

2729
basic_env = {
28-
"currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
29-
"currentDifficulty": "256",
30-
"currentGasLimit": "1000000000",
31-
"currentNumber": "257",
32-
"currentTimestamp": "1",
33-
"previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
30+
"currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
31+
"currentDifficulty": "0x020000",
32+
"currentGasLimit": "0x7fffffffffffffff",
33+
"currentNumber": "0x01",
34+
"currentTimestamp": "0x03e8",
35+
"previousHash": "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
3436
}
3537

36-
konfig = copy.copy(default_config)
37-
38-
konfig_homestead = copy.copy(konfig)
39-
konfig_homestead["HOMESTEAD_FORK_BLKNUM"] = 0
40-
konfig_homestead["ANTI_DOS_FORK_BLKNUM"] = 2**99
41-
konfig_homestead["CLEARING_FORK_BLKNUM"] = 2**99
42-
konfig_homestead["METROPOLIS_FORK_BLKNUM"] = 2**99
43-
44-
konfig_tangerine = copy.copy(konfig)
45-
konfig_tangerine["HOMESTEAD_FORK_BLKNUM"] = 0
46-
konfig_tangerine["ANTI_DOS_FORK_BLKNUM"] = 0
47-
konfig_tangerine["CLEARING_FORK_BLKNUM"] = 2**99
48-
konfig_tangerine["METROPOLIS_FORK_BLKNUM"] = 2**99
49-
50-
konfig_spurious = copy.copy(konfig)
51-
konfig_spurious["HOMESTEAD_FORK_BLKNUM"] = 0
52-
konfig_spurious["ANTI_DOS_FORK_BLKNUM"] = 0
53-
konfig_spurious["CLEARING_FORK_BLKNUM"] = 0
54-
konfig_spurious["METROPOLIS_FORK_BLKNUM"] = 2**99
55-
56-
konfig_metropolis = copy.copy(konfig)
57-
konfig_metropolis["HOMESTEAD_FORK_BLKNUM"] = 0
58-
konfig_metropolis["ANTI_DOS_FORK_BLKNUM"] = 0
59-
konfig_metropolis["CLEARING_FORK_BLKNUM"] = 0
60-
konfig_metropolis["METROPOLIS_FORK_BLKNUM"] = 0
6138

6239
configs = {
63-
#"Homestead": konfig_homestead,
64-
#"EIP150": konfig_tangerine,
65-
"EIP158": konfig_spurious,
66-
"Metropolis": konfig_metropolis
40+
#"Homestead": config_homestead,
41+
#"EIP150": config_tangerine,
42+
"EIP158": config_spurious,
43+
"Metropolis": config_metropolis
6744
}
6845

6946
def mk_state_diff(prev, post):
@@ -178,3 +155,4 @@ def verify_state_test(test):
178155
raise Exception("Hash mismatch, computed: %s, supplied: %s" % (computed["hash"], result["hash"]))
179156
else:
180157
print("Hash matched!: %s" % computed["hash"])
158+
return True

ethereum/tools/tester2.py

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
from ethereum.utils import sha3, privtoaddr, int_to_addr, to_string, big_endian_to_int
1+
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
33
from ethereum.pow import chain
44
from ethereum.transactions import Transaction
55
from ethereum.consensus_strategy import get_consensus_strategy
6-
from ethereum.config import Env
6+
from ethereum.config import config_homestead, config_tangerine, config_spurious, config_metropolis, default_config, Env
77
from ethereum.pow.ethpow import Miner
88
from ethereum.messages import apply_transaction
99
from ethereum.common import verify_execution_results, mk_block_from_prevstate, set_execution_results
@@ -99,25 +99,35 @@ def kall(self, *args, **kwargs):
9999
return o[0] if len(o) == 1 else o
100100
return kall
101101

102+
def get_env(env):
103+
d = {
104+
None: config_spurious,
105+
'mainnet': default_config,
106+
'homestead': config_homestead,
107+
'tangerine': config_tangerine,
108+
'spurious': config_spurious,
109+
'metropolis': config_metropolis,
110+
}
111+
return env if isinstance(env, Env) else Env(config=d[env])
112+
102113

103114
class Chain(object):
104115
def __init__(self, alloc=None, env=None):
105116
self.chain = chain.Chain(mk_basic_state(base_alloc if alloc is None else alloc,
106117
None,
107-
Env() if env is None else env))
118+
get_env(env)))
108119
self.cs = get_consensus_strategy(self.chain.env.config)
109120
self.block = mk_block_from_prevstate(self.chain, timestamp=self.chain.state.timestamp + 1)
110121
self.head_state = self.chain.state.ephemeral_clone()
111122
self.cs.initialize(self.head_state, self.block)
112-
113-
@property
114-
def last_tx(self):
115-
return self.block.transactions[-1] if self.block.transactions else None
123+
self.last_sender = None
124+
self.last_tx = None
116125

117126
def tx(self, sender=k0, to=b'\x00' * 20, value=0, data=b'', startgas=STARTGAS, gasprice=GASPRICE):
118127
sender_addr = privtoaddr(sender)
119128
transaction = Transaction(self.head_state.get_nonce(sender_addr), gasprice, startgas,
120129
to, value, data).sign(sender)
130+
self.last_tx, self.last_sender = transaction, sender
121131
success, output = apply_transaction(self.head_state, transaction)
122132
self.block.transactions.append(transaction)
123133
if not success:
@@ -159,3 +169,53 @@ def revert(self, snapshot):
159169
assert blknum == self.block.number
160170
self.block.transactions = self.block.transactions[:txcount]
161171
self.head_state.revert(state_snapshot)
172+
173+
def int_to_0x_hex(v):
174+
o = encode_hex(int_to_big_endian(v))
175+
if o and o[0] == '0':
176+
return '0x' + o[1:]
177+
else:
178+
return '0x' + o
179+
180+
181+
def mk_state_test_prefill(c):
182+
env = {
183+
"currentCoinbase": checksum_encode(c.head_state.block_coinbase),
184+
"currentDifficulty": int_to_0x_hex(c.head_state.block_difficulty),
185+
"currentGasLimit": int_to_0x_hex(c.head_state.gas_limit),
186+
"currentNumber": int_to_0x_hex(c.head_state.block_number),
187+
"currentTimestamp": int_to_0x_hex(c.head_state.timestamp),
188+
"previousHash": "0x"+encode_hex(c.head_state.prev_headers[0].hash),
189+
}
190+
pre = c.head_state.to_dict()
191+
return {"env": env, "pre": pre}
192+
193+
def mk_state_test_postfill(c, prefill):
194+
txdata = c.last_tx.to_dict()
195+
modified_tx_data = {
196+
"data": [ txdata["data"] ],
197+
"gasLimit": [ int_to_0x_hex(txdata["startgas"]) ],
198+
"gasPrice": int_to_0x_hex(txdata["gasprice"]),
199+
"nonce": int_to_0x_hex(txdata["nonce"]),
200+
"secretKey": '0x' + encode_hex(c.last_sender),
201+
"to": txdata["to"],
202+
"value": [ int_to_0x_hex(txdata["value"]) ],
203+
}
204+
c.head_state.commit()
205+
postStateHash = '0x' + encode_hex(c.head_state.trie.root_hash)
206+
if c.chain.config == config_homestead:
207+
config = 'Homestead'
208+
elif c.chain.config == config_tangerine:
209+
config = 'EIP150'
210+
elif c.chain.config == config_spurious:
211+
config = 'EIP158'
212+
elif c.chain.config == config_metropolis:
213+
config = 'Metropolis'
214+
else:
215+
raise Exception("Cannot get config")
216+
return {
217+
"env": prefill["env"],
218+
"pre": prefill["pre"],
219+
"transaction": modified_tx_data,
220+
"post": {config: [ { "hash": postStateHash, "indexes": {"data": 0, "gas": 0, "value": 0} } ] }
221+
}

ethereum/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def checksum_encode(addr): # Takes a 20-byte binary address as input
182182
addr = normalize_address(addr)
183183
o = ''
184184
v = big_endian_to_int(sha3(encode_hex(addr)))
185-
for i, c in enumerate(addr.hex()):
185+
for i, c in enumerate(encode_hex(addr)):
186186
if c in '0123456789':
187187
o += c
188188
else:

0 commit comments

Comments
 (0)