Skip to content

Commit 912b2f3

Browse files
committed
Less broken things
All tests pass at the expense of cardboarded and duck-taped code. This needs some serious refactoring, perhaps more tests, then squashing all these WIP commits.
1 parent 0bc979b commit 912b2f3

File tree

11 files changed

+485
-260
lines changed

11 files changed

+485
-260
lines changed

README.md

+74-50
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,69 @@ pip install eth-tester
2121
>>> from eth_tester import EthereumTester
2222
>>> t = EthereumTester()
2323
>>> t.get_accounts()
24-
('0x82A978B3f5962A5b0957d9ee9eEf472EE55B42F1',
25-
'0x7d577a597B2742b498Cb5Cf0C26cDCD726d39E6e',
26-
'0xDCEceAF3fc5C0a63d195d69b1A90011B7B19650D',
27-
'0x598443F1880Ef585B21f1d7585Bd0577402861E5',
28-
'0x13cBB8D99C6C4e0f2728C7d72606e78A29C4E224',
29-
'0x77dB2BEBBA79Db42a978F896968f4afCE746ea1F',
30-
'0x24143873e0E0815fdCBcfFDbe09C979CbF9Ad013',
31-
'0x10A1c1CB95c92EC31D3f22C66Eef1d9f3F258c6B',
32-
'0xe0FC04FA2d34a66B779fd5CEe748268032a146c0',
33-
'0x90F0B1EBbbA1C1936aFF7AAf20a7878FF9e04B6c')
34-
>>> t.get_balance('0x82A978B3f5962A5b0957d9ee9eEf472EE55B42F1')
24+
('0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',
25+
'0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',
26+
'0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69',
27+
'0x1efF47bc3a10a45D4B230B5d10E37751FE6AA718',
28+
'0xe1AB8145F7E55DC933d51a18c793F901A3A0b276',
29+
'0xE57bFE9F44b819898F47BF37E5AF72a0783e1141',
30+
'0xd41c057fd1c78805AAC12B0A94a405c0461A6FBb',
31+
'0xF1F6619B38A98d6De0800F1DefC0a6399eB6d30C',
32+
'0xF7Edc8FA1eCc32967F827C9043FcAe6ba73afA5c',
33+
'0x4CCeBa2d7D2B4fdcE4304d3e09a1fea9fbEb1528')
34+
35+
>>> t.get_balance('0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf')
3536
1000000000000000000000000
36-
>>> t.send_transaction({'from': '0x82A978B3f5962A5b0957d9ee9eEf472EE55B42F1', 'to': '0x7d577a597B2742b498Cb5Cf0C26cDCD726d39E6e', 'gas': 21000, 'value': 1})
37-
'0x140c1da1370a908e4c0f7c6e33bb97182011707c6a9aff954bef1084c8a48b25'
38-
>>> t.get_transaction_by_hash('0x140c1da1370a908e4c0f7c6e33bb97182011707c6a9aff954bef1084c8a48b25')
39-
{'block_hash': '0x89c03ecb6bbf3ff533b04a663fa98d59c9d985de806d1a9dcafaad7c993ee6e8',
40-
'block_number': 0,
41-
'data': '0x',
42-
'from': '0x82A978B3f5962A5b0957d9ee9eEf472EE55B42F1',
43-
'gas': 21000,
44-
'gas_price': 1,
45-
'hash': '0x140c1da1370a908e4c0f7c6e33bb97182011707c6a9aff954bef1084c8a48b25',
37+
38+
>>> t.send_transaction({
39+
... 'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',
40+
... 'to': '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',
41+
... 'gas': 30000,,
42+
... 'value': 1,
43+
... 'max_fee_per_gas': 1000000000,
44+
... 'max_priority_fee_per_gas': 1000000000,
45+
... 'chain_id': 131277322940537,
46+
... 'access_list': ( # access_list is optional and takes address as bytes and storage keys as integers
47+
... (
48+
... b'+Z\xd5\xc4y\\\x02e\x14\xf81|z!^!\x8d\xcc\xd6\xcf',
49+
... (0, 2)
50+
... ),
51+
... )
52+
... })
53+
'0xfd138a344f6bf33367b45e39c6af1c5032268a37cc7eb2736e08a876aa3edeb2'
54+
55+
>>> t.get_transaction_by_hash('0xfd138a344f6bf33367b45e39c6af1c5032268a37cc7eb2736e08a876aa3edeb2')
56+
{'hash': '0xfd138a344f6bf33367b45e39c6af1c5032268a37cc7eb2736e08a876aa3edeb2',
4657
'nonce': 0,
47-
'r': 114833774457827084417823702749930473879683934597320921824765632039428214735160,
48-
's': 52192522150044217242428968890330558187037131043598164958282684822175843828481,
49-
'to': '0x7d577a597B2742b498Cb5Cf0C26cDCD726d39E6e',
58+
'block_hash': '0x72bd3de88c7f11a496fe47de2b1efa51311f3b276420ecadb4dbb090ea61b217',
59+
'block_number': 1,
5060
'transaction_index': 0,
51-
'v': 27,
52-
'value': 1}
53-
54-
>>> t.get_transaction_receipt('0x140c1da1370a908e4c0f7c6e33bb97182011707c6a9aff954bef1084c8a48b25')
55-
{'block_hash': '0x89c03ecb6bbf3ff533b04a663fa98d59c9d985de806d1a9dcafaad7c993ee6e8',
56-
'block_number': 0,
61+
'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',
62+
'to': '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',
63+
'value': 1,
64+
'gas': 30000,
65+
'data': '0x',
66+
'r': 88767874425115037435552797857068981850542604805496334073531728907656577758826,
67+
's': 24696248707889349325417290631838009592163569252708852321923311080609868619225,
68+
'chain_id': 131277322940537,
69+
'max_fee_per_gas': 1000000000,
70+
'max_priority_fee_per_gas': 1000000000,
71+
'access_list': (('0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',
72+
('0x0000000000000000000000000000000000000000000000000000000000000000',
73+
'0x0000000000000000000000000000000000000000000000000000000000000002')),),
74+
'y_parity': 0}
75+
76+
77+
>>> t.get_transaction_receipt('0x86acbf39865cd2fe86db7203742d2652bc1b58b10a3996befe1ee81738f1f58e')
78+
{'transaction_hash': '0xfd138a344f6bf33367b45e39c6af1c5032268a37cc7eb2736e08a876aa3edeb2',
79+
'transaction_index': 0,
80+
'block_number': 1,
81+
'block_hash': '0x72bd3de88c7f11a496fe47de2b1efa51311f3b276420ecadb4dbb090ea61b217',
82+
'cumulative_gas_used': 27200,
83+
'gas_used': 27200,
5784
'contract_address': None,
58-
'cumulative_gas_used': 21000,
59-
'gas_used': 21000,
6085
'logs': (),
61-
'transaction_hash': '0x140c1da1370a908e4c0f7c6e33bb97182011707c6a9aff954bef1084c8a48b25',
62-
'transaction_index': 0}
86+
'status': 1}
6387
```
6488

6589

@@ -130,13 +154,13 @@ types.
130154

131155
* Hexidecimal values **must** be text (not byte) strings. The `0x` prefix is optional.
132156
* Any address which contains mixed-case alpha characters will be validated as a checksummed address as specified by [EIP-55](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md)
133-
* 32-byte hashes **must** be hexidecimal encoded.
157+
* 32-byte hashes **must** be hexadecimal encoded.
134158
* Numeric values **must** be in their integer representation.
135159

136160
Similarly, ethereum tester ensures that return values conform to similar rules.
137161

138-
* 32-byte hashes will be returned in their hexidecimal encoded representation.
139-
* Addresses will be returned in their hexidecimal representation and EIP55 checksummed.
162+
* 32-byte hashes will be returned in their hexadecimal encoded representation.
163+
* Addresses will be returned in their hexadecimal representation and EIP55 checksummed.
140164
* Numeric values will be returned as integers.
141165

142166

@@ -164,8 +188,8 @@ The `EthereumTester` object is the sole API entrypoint. Instantiation of this
164188
object accepts the following parameters.
165189

166190
- `backend`: The chain backend being used. See the [chain backends](#backends)
167-
- `validator`: The validator to used. See the [validators](#validation)
168-
- `normalizer`: The normalizer to used. See the [normalizers](#normalization)
191+
- `validator`: The validator being used. See the [validators](#validation)
192+
- `normalizer`: The normalizer being used. See the [normalizers](#normalization)
169193
- `auto_mine_transactions`: If *truthy* transactions will be automatically mined at the time they are submitted. See [`enable_auto_mine_transactions`](#api-enable_auto_mine_transactions) and [`disable_auto_mine_transactions`](#api-disable_auto_mine_transactions).
170194
- `fork_blocks`: configures which block numbers the various network hard fork rules will be activated. See [fork-rules](#fork-rules)
171195

@@ -181,7 +205,7 @@ object accepts the following parameters.
181205
### Fork Rules
182206
<a id="fork-rules"></a>
183207

184-
Ethereum tester uses the Byzantium rules, starting at block 0.
208+
Ethereum tester uses the London fork rules, starting at block 0.
185209

186210
### Time Travel
187211
<a id="time-travel"></a>
@@ -201,7 +225,7 @@ of the latest block.
201225
### Mining
202226

203227
Manually mining blocks can be done with the following API. The `coinbase`
204-
parameter of these methods **must** be a hexidecimal encoded address.
228+
parameter of these methods **must** be a hexadecimal encoded address.
205229

206230
<a id="api-mine_blocks"></a>
207231

@@ -221,7 +245,7 @@ Mines a single new block, returning the mined block's hash.
221245

222246
#### Auto-mining transactions
223247

224-
By default all transactions are mined immediately. This means that each transaction you send will result in a new block being mined, and that all blocks will only ever have at most a single transaction. This behavior can be controlled with the following methods.
248+
By default, all transactions are mined immediately. This means that each transaction you send will result in a new block being mined, and that all blocks will only ever have at most a single transaction. This behavior can be controlled with the following methods.
225249

226250
<a id="api-enable_auto_mine_transactions"></a>
227251

@@ -239,7 +263,7 @@ Turns **off** auto-mining of transactions.
239263
### Accounts
240264

241265
The following API can be used to interact with account data. The `account`
242-
parameter in these methods **must** be a hexidecimal encode address.
266+
parameter in these methods **must** be a hexadecimal encode address.
243267

244268
<a id="api-get_accounts"></a>
245269
`EthereumTester.get_accounts()`
@@ -449,7 +473,7 @@ cannot be found.
449473
'transactions': (),
450474
'transactions_root': '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
451475
'uncles': (),
452-
'base_fee_per_gas': 1000000000}
476+
'base_fee_per_gas': 875000000}
453477
```
454478

455479
<a id="api-get_transaction_receipt"></a>
@@ -492,12 +516,12 @@ found for the given hash.
492516
A transaction is a formatted as a dictionary with the following keys and
493517
values.
494518

495-
* `from`: The address of the account sending the transaction (hexidecimal string).
496-
* `to`: The address of the account the transaction is being sent to. Empty string should be used to trigger contract creation (hexidecimal string).
519+
* `from`: The address of the account sending the transaction (hexadecimal string).
520+
* `to`: The address of the account the transaction is being sent to. Empty string should be used to trigger contract creation (hexadecimal string).
497521
* `gas`: Sets the gas limit for transaction execution (integer).
498522
* `gas_price`: Sets the price per unit of gas in wei that will be paid for transaction execution (integer).
499523
* `value`: The amount of ether in wei that should be sent with the transaction (integer).
500-
* `data`: The data for the transaction (hexidecimal string).
524+
* `data`: The data for the transaction (hexadecimal string).
501525

502526

503527
#### Methods
@@ -884,9 +908,9 @@ The canonical format is intended for low level handling by backends.
884908

885909
The normal format is intended for use by end users.
886910

887-
* 32 byte hashes: `0x` prefixed hexidecimal encoded text strings (not byte strings)
888-
* Arbitrary length strings: `0x` prefixed hexidecimal encoded text strings (not byte strings)
889-
* Addresses: `0x` prefixed and EIP55 checksummed hexidecimal encoded text strings (not byte strings)
911+
* 32 byte hashes: `0x` prefixed hexadecimal encoded text strings (not byte strings)
912+
* Arbitrary length strings: `0x` prefixed hexadecimal encoded text strings (not byte strings)
913+
* Addresses: `0x` prefixed and EIP55 checksummed hexadecimal encoded text strings (not byte strings)
890914
* Integers: `int`
891915
* Array Types: `tuple`
892916

eth_tester/backends/pyevm/main.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from eth_abi.exceptions import (
99
DecodingError
1010
)
11-
from toolz import dissoc
1211

1312
from eth_utils import (
1413
encode_hex,
@@ -451,6 +450,11 @@ def _normalize_transaction(self, transaction, block_number='latest'):
451450
yield 'value', 0
452451
if 'to' not in transaction:
453452
yield 'to', b''
453+
if (
454+
all(_ in transaction for _ in ('max_fee_per_gas', 'max_priority_fee_per_gas')) and
455+
'access_list' not in transaction
456+
):
457+
yield 'access_list', []
454458

455459
def _get_normalized_and_unsigned_evm_transaction(self, transaction, block_number='latest'):
456460
normalized_transaction = self._normalize_transaction(transaction, block_number)
@@ -470,14 +474,10 @@ def _get_normalized_and_signed_evm_transaction(self, transaction, block_number='
470474

471475
def _create_type_aware_unsigned_transaction(self, normalized_txn):
472476
if all(_ in normalized_txn for _ in ("access_list", "gas_price")):
473-
# validated type='0x1' so can pop it back out since type is signed separate from txn
474-
normalized_txn = dissoc(normalized_txn, 'type')
475477
return self.chain.get_transaction_builder().new_unsigned_access_list_transaction(
476478
**normalized_txn
477479
)
478480
elif all(_ in normalized_txn for _ in ("max_fee_per_gas", "max_priority_fee_per_gas")):
479-
# validated type='0x2' so can pop it back out since type is signed separate from txn
480-
normalized_txn = dissoc(normalized_txn, 'type')
481481
return self.chain.get_transaction_builder().new_unsigned_dynamic_fee_transaction(
482482
**normalized_txn
483483
)

eth_tester/backends/pyevm/serializers.py

+51-33
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import rlp
2-
from toolz import dissoc, merge
32

3+
from toolz import (
4+
merge,
5+
)
6+
7+
from eth_tester.exceptions import ValidationError
48
from eth_tester.utils.address import (
59
generate_contract_address,
610
)
@@ -48,6 +52,7 @@ def serialize_block(block, full_transaction, is_pending):
4852
"timestamp": block.header.timestamp,
4953
"transactions": transactions,
5054
"uncles": [uncle.hash for uncle in block.uncles],
55+
"base_fee_per_gas": block.header.base_fee_per_gas,
5156
}
5257

5358

@@ -67,44 +72,57 @@ def serialize_transaction(block, transaction, transaction_index, is_pending):
6772
"value": transaction.value,
6873
"gas": transaction.gas,
6974
"data": transaction.data,
75+
"r": transaction.r,
76+
"s": transaction.s,
7077
}
71-
if hasattr(transaction, 'gas_price'):
72-
if hasattr(transaction, 'access_list'):
78+
if _field_in_transaction(transaction, 'gas_price'):
79+
if _field_in_transaction(transaction, 'access_list'):
7380
# access list transaction
74-
serialized_transaction = merge(
75-
common_transaction_params,
76-
{
77-
'gas_price': transaction.gas_price,
78-
'access_list': transaction.access_list,
79-
}
80-
)
81+
type_specific_params = {
82+
'chain_id': transaction.chain_id,
83+
'gas_price': transaction.gas_price,
84+
'access_list': transaction.access_list or [],
85+
'y_parity': transaction.y_parity,
86+
}
8187
else:
8288
# legacy transaction
83-
serialized_transaction = merge(
84-
common_transaction_params,
85-
{
86-
"gas_price": transaction.gas_price,
87-
"v": transaction.v,
88-
"r": transaction.r,
89-
"s": transaction.s,
90-
}
91-
)
92-
elif (
93-
hasattr(transaction, 'max_fee_per_gas') and
94-
hasattr(transaction, 'max_priority_fee_per_gas')
95-
):
96-
# dynamic fee transaction
97-
serialized_transaction = merge(
98-
common_transaction_params,
99-
{
100-
'max_fee_per_gas': transaction.max_fee_per_gas,
101-
'max_priority_fee_per_gas': transaction.max_priority_fee_per_gas,
102-
'access_list': transaction.access_list or None,
89+
type_specific_params = {
90+
'gas_price': transaction.gas_price,
91+
'v': transaction.v
10392
}
104-
)
93+
elif (_field_in_transaction(transaction, _) for _ in (
94+
'max_fee_per_gas' and 'max_priority_fee_per_gas'
95+
)):
96+
# dynamic fee transaction
97+
type_specific_params = {
98+
'chain_id': transaction.chain_id,
99+
'max_fee_per_gas': transaction.max_fee_per_gas,
100+
'max_priority_fee_per_gas': transaction.max_priority_fee_per_gas,
101+
'access_list': transaction.access_list or [],
102+
'y_parity': transaction.y_parity,
103+
}
105104
else:
106-
raise NotImplementedError('transaction type not recognized for serialization')
107-
return serialized_transaction
105+
raise ValidationError('Transaction serialization error')
106+
return merge(common_transaction_params, type_specific_params)
107+
108+
109+
def _field_in_transaction(transaction, field):
110+
"""
111+
There are many different classes of transactions, we have to be able to search for a
112+
particular field depending on the type of transaction - from a dict, to *LegacyTransaction to
113+
*TypedTransaction.
114+
"""
115+
if not isinstance(transaction, dict):
116+
try:
117+
txn_dict = transaction.as_dict()
118+
if not isinstance(txn_dict, dict):
119+
txn_dict = txn_dict.dictionary
120+
except AttributeError:
121+
pass
122+
try:
123+
return field in txn_dict
124+
except (NameError, TypeError):
125+
return hasattr(transaction, field)
108126

109127

110128
def serialize_transaction_receipt(

0 commit comments

Comments
 (0)