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

Commit 01e3fd4

Browse files
author
Jan Xie
committed
fix EIP155 transaction signature
1 parent 99110e9 commit 01e3fd4

File tree

3 files changed

+74
-19
lines changed

3 files changed

+74
-19
lines changed

ethereum/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
DAO_WITHDRAWER = utils.normalize_address('0xbf4ed7b27f1d666546e30d74d50d173d20bca754'),
6464
# Anti-DoS fork
6565
ANTI_DOS_FORK_BLKNUM = 2463000,
66-
CLEARING_FORK_BLKNUM = 3500000,
66+
SPURIOUS_DRAGON_FORK_BLKNUM = 2675000,
6767
# Default consensus strategy: ethash, poa, casper, pbft
6868
CONSENSUS_STRATEGY = 'ethash',
6969
# Serenity fork

ethereum/tests/test_transactions.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@ def test_transaction(filename, testname, testdata):
2323
try:
2424
rlpdata = decode_hex(testdata["rlp"][2:])
2525
o = {}
26-
tx = rlp.decode(rlpdata, transactions.Transaction)
26+
2727
blknum = int(testdata["blocknumber"])
28-
if blknum >= 1000000: # config.default_config["HOMESTEAD_FORK_BLKNUM"]:
28+
if blknum >= config.default_config["SPURIOUS_DRAGON_FORK_BLKNUM"]:
29+
tx_sedes = transactions.EIP155Transaction
30+
else:
31+
tx_sedes = transactions.Transaction
32+
tx = rlp.decode(rlpdata, tx_sedes)
33+
34+
if blknum >= config.default_config["HOMESTEAD_FORK_BLKNUM"]:
2935
tx.check_low_s_homestead()
3036
o["sender"] = tx.sender
3137
o["transaction"] = {

ethereum/transactions.py

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717
# in the yellow paper it is specified that s should be smaller than secpk1n (eq.205)
1818
secpk1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337
1919

20+
# EIP155 parameters
21+
v_offset = 27
22+
v_zero = v_offset
23+
v_one = v_zero + 1
24+
chain_id = 1
25+
eip155_v_offset = 35
26+
eip155_v_zero = eip155_v_offset + 2 * chain_id
27+
eip155_v_one = eip155_v_zero + 1
2028

2129
class Transaction(rlp.Serializable):
2230

@@ -70,27 +78,16 @@ def __init__(self, nonce, gasprice, startgas, to, value, data, v=0, r=0, s=0):
7078

7179
@property
7280
def sender(self):
73-
7481
if not self._sender:
75-
# Determine sender
7682
if self.v:
77-
if self.r >= N or self.s >= N or self.v not in (27, 28, 37, 38) \
78-
or self.r == 0 or self.s == 0:
83+
v = self.decode_v(self.v)
84+
if self.r >= N or self.s >= N or v > 1 or self.r == 0 or self.s == 0:
7985
raise InvalidTransaction("Invalid signature values!")
80-
log.debug('reco< 27 or self.v > 28 \vering sender')
81-
if self.v in (27, 28):
82-
rlpdata = rlp.encode(self, UnsignedTransaction)
83-
rawhash = utils.sha3(rlpdata)
84-
v = self.v
85-
elif self.v in (37, 38):
86-
rlpdata = rlp.encode(rlp.infer_sedes(self).serialize(self)[:-3] + ['\x01', '', ''])
87-
rawhash = utils.sha3(rlpdata)
88-
v = self.v - 10
89-
pub = ecrecover_to_pub(rawhash, v, self.r, self.s)
86+
rawhash = utils.sha3(self.signing_data('verify'))
87+
pub = ecrecover_to_pub(rawhash, v+27, self.r, self.s)
9088
if pub == b"\x00" * 64:
9189
raise InvalidTransaction("Invalid signature (zero privkey cannot sign)")
9290
self._sender = utils.sha3(pub)[-20:]
93-
assert self.sender == self._sender
9491
else:
9592
self._sender = 0
9693
return self._sender
@@ -112,7 +109,8 @@ def sign(self, key):
112109
# we need a binary key
113110
key = encode_privkey(key, 'bin')
114111

115-
self.v, self.r, self.s = ecsign(rawhash, key)
112+
v, self.r, self.s = ecsign(rawhash, key)
113+
self.v = self.encode_v(v)
116114

117115
self.sender = utils.privtoaddr(key)
118116
return self
@@ -185,6 +183,57 @@ def check_low_s_homestead(self):
185183
if self.s > N // 2 or self.s == 0:
186184
raise InvalidTransaction("Invalid signature S value!")
187185

186+
def encode_v(self, v):
187+
return v + v_zero
188+
189+
def decode_v(self, v):
190+
if not v:
191+
return
192+
if v in (v_zero, v_one):
193+
return v - v_zero
194+
else:
195+
raise InvalidTransaction("invalid signature")
196+
197+
def signing_data(self, mode):
198+
if mode == 'verify':
199+
if self.v in (v_zero, v_one):
200+
return rlp.encode(self, sedes=UnsignedTransaction)
201+
elif mode == 'sign':
202+
return rlp.encode(self, sedes=UnsignedTransaction)
203+
else:
204+
raise ValueError("invalid mode")
205+
206+
207+
class EIP155Transaction(Transaction):
208+
209+
def decode_chain_id(self, v):
210+
if v < eip155_v_offset+2:
211+
raise InvalidTransaction("invalid chain id")
212+
return (v - eip155_v_offset) / 2
213+
214+
def decode_v(self, v):
215+
if not v:
216+
return
217+
if v in (eip155_v_zero, eip155_v_one):
218+
return v - eip155_v_zero
219+
else:
220+
return super(EIP155Transaction, self).decode_v(v)
221+
222+
def signing_data(self, mode):
223+
if mode == 'verify':
224+
if self.v >= eip155_v_zero:
225+
v = big_endian_int.serialize(self.decode_chain_id(self.v))
226+
return rlp.encode(rlp.infer_sedes(self).serialize(self)[:-3] + [v, '', ''])
227+
else:
228+
return super(EIP155Transaction, self).signing_data(mode)
229+
elif mode == 'sign':
230+
if self.v > 0 and self.r == 0 and self.s == 0:
231+
return rlp.encode(self, sedes=Transaction)
232+
else:
233+
return super(EIP155Transaction, self).signing_data(mode)
234+
else:
235+
raise ValueError("invalid mode")
236+
188237

189238
UnsignedTransaction = Transaction.exclude(['v', 'r', 's'])
190239

0 commit comments

Comments
 (0)