1
- import logging
2
1
import pathlib
3
2
from typing import (
4
3
Tuple ,
15
14
from eth_utils import (
16
15
encode_hex ,
17
16
decode_hex ,
18
- to_int ,
19
17
)
20
18
21
19
from eth .constants import (
61
59
62
60
class BaseERC20Benchmark (BaseBenchmark ):
63
61
64
- def __init__ (self , num_blocks : int = 10 , num_tx : int = 2 ) -> None :
62
+ def __init__ (self , num_blocks : int = 2 , num_tx : int = 50 ) -> None :
65
63
super ().__init__ ()
66
64
67
65
self .num_blocks = num_blocks
@@ -82,7 +80,7 @@ def _setup_benchmark(self, chain: MiningChain) -> None:
82
80
pass
83
81
84
82
@abstractmethod
85
- def _apply_transaction (self , chain : MiningChain ) -> None :
83
+ def _next_transaction (self , chain : MiningChain ) -> None :
86
84
raise NotImplementedError (
87
85
"Must be implemented by subclasses"
88
86
)
@@ -114,7 +112,8 @@ def mine_blocks(self, chain: MiningChain, num_blocks: int, num_tx: int) -> Tuple
114
112
total_gas_used = 0
115
113
total_num_tx = 0
116
114
for i in range (1 , num_blocks + 1 ):
117
- block = self .mine_block (chain , i , num_tx )
115
+ import_result = self .mine_block (chain , i , num_tx )
116
+ block = import_result .imported_block
118
117
total_gas_used = total_gas_used + block .header .gas_used
119
118
total_num_tx = total_num_tx + len (block .transactions )
120
119
return total_gas_used , total_num_tx
@@ -123,11 +122,19 @@ def mine_block(self,
123
122
chain : MiningChain ,
124
123
block_number : int ,
125
124
num_tx : int ) -> BaseBlock :
126
- for _ in range (1 , num_tx + 1 ):
127
- self ._apply_transaction (chain )
128
- return chain .mine_block ()
125
+ transactions , callbacks = zip (* (
126
+ self ._next_transaction (chain )
127
+ for _ in range (num_tx )
128
+ ))
129
129
130
- def _deploy_simple_token (self , chain : MiningChain ) -> None :
130
+ mining_result , receipts , computations = chain .mine_all (transactions )
131
+
132
+ for callback , receipt , computation in zip (callbacks , receipts , computations ):
133
+ callback (receipt , computation )
134
+
135
+ return mining_result
136
+
137
+ def _deploy_simple_token (self , chain : MiningChain , nonce : int = None ) -> None :
131
138
# Instantiate the contract
132
139
SimpleToken = self .w3 .eth .contract (
133
140
abi = self .contract_interface ['abi' ],
@@ -143,21 +150,24 @@ def _deploy_simple_token(self, chain: MiningChain) -> None:
143
150
amount = 0 ,
144
151
gas = FIRST_TX_GAS_LIMIT ,
145
152
data = decode_hex (w3_tx ['data' ]),
153
+ nonce = nonce ,
146
154
)
147
- logging .debug (f'Applying Transaction { tx } ' )
148
- block , receipt , computation = chain .apply_transaction (tx )
149
- # Keep track of deployed contract address
150
- self .deployed_contract_address = computation .msg .storage_address
151
155
152
- computation .raise_if_error ()
156
+ def callback (receipt , computation ) -> None :
157
+ computation .raise_if_error ()
153
158
154
- # Keep track of simple_token object
155
- self .simple_token = self .w3 .eth .contract (
156
- address = Web3 .toChecksumAddress (encode_hex (self .deployed_contract_address )),
157
- abi = self .contract_interface ['abi' ],
158
- )
159
+ # Keep track of deployed contract address
160
+ self .deployed_contract_address = computation .msg .storage_address
161
+
162
+ # Keep track of simple_token object
163
+ self .simple_token = self .w3 .eth .contract (
164
+ address = Web3 .toChecksumAddress (encode_hex (self .deployed_contract_address )),
165
+ abi = self .contract_interface ['abi' ],
166
+ )
167
+
168
+ return tx , callback
159
169
160
- def _erc_transfer (self , addr : str , chain : MiningChain ) -> None :
170
+ def _erc_transfer (self , addr : str , chain : MiningChain , nonce : int = None ) -> None :
161
171
w3_tx = self .simple_token .functions .transfer (
162
172
addr ,
163
173
TRANSFER_AMOUNT
@@ -171,15 +181,15 @@ def _erc_transfer(self, addr: str, chain: MiningChain) -> None:
171
181
amount = 0 ,
172
182
gas = SECOND_TX_GAS_LIMIT ,
173
183
data = decode_hex (w3_tx ['data' ]),
184
+ nonce = nonce ,
174
185
)
175
186
176
- block , receipt , computation = chain .apply_transaction (tx )
187
+ def callback (receipt , computation ) -> None :
188
+ computation .raise_if_error ()
189
+ assert computation .output == b'\0 ' * 31 + b'\x01 ' , computation .output
190
+ return tx , callback
177
191
178
- computation .raise_if_error ()
179
-
180
- assert to_int (computation .output ) == 1
181
-
182
- def _erc_approve (self , addr2 : str , chain : MiningChain ) -> None :
192
+ def _erc_approve (self , addr2 : str , chain : MiningChain , nonce : int = None ) -> None :
183
193
w3_tx = self .simple_token .functions .approve (
184
194
addr2 ,
185
195
TRANSFER_AMOUNT
@@ -193,15 +203,21 @@ def _erc_approve(self, addr2: str, chain: MiningChain) -> None:
193
203
amount = 0 ,
194
204
gas = SECOND_TX_GAS_LIMIT ,
195
205
data = decode_hex (w3_tx ['data' ]),
206
+ nonce = nonce ,
196
207
)
197
208
198
- block , receipt , computation = chain .apply_transaction (tx )
209
+ def callback (receipt , computation ) -> None :
210
+ computation .raise_if_error ()
211
+ assert computation .output == b'\0 ' * 31 + b'\x01 ' , computation .output
199
212
200
- computation . raise_if_error ()
213
+ return tx , callback
201
214
202
- assert to_int (computation .output ) == 1
203
-
204
- def _erc_transfer_from (self , addr1 : str , addr2 : str , chain : MiningChain ) -> None :
215
+ def _erc_transfer_from (
216
+ self ,
217
+ addr1 : str ,
218
+ addr2 : str ,
219
+ chain : MiningChain ,
220
+ nonce : int = None ) -> None :
205
221
206
222
w3_tx = self .simple_token .functions .transferFrom (
207
223
addr1 ,
@@ -217,41 +233,59 @@ def _erc_transfer_from(self, addr1: str, addr2: str, chain: MiningChain) -> None
217
233
amount = 0 ,
218
234
gas = SECOND_TX_GAS_LIMIT ,
219
235
data = decode_hex (w3_tx ['data' ]),
236
+ nonce = nonce ,
220
237
)
221
238
222
- block , receipt , computation = chain . apply_transaction ( tx )
223
-
224
- computation .raise_if_error ()
239
+ def callback ( receipt , computation ) -> None :
240
+ computation . raise_if_error ()
241
+ assert computation .output == b' \0 ' * 31 + b' \x01 ' , computation . output
225
242
226
- assert to_int ( computation . output ) == 1
243
+ return tx , callback
227
244
228
245
229
246
class ERC20DeployBenchmark (BaseERC20Benchmark ):
230
247
def __init__ (self ) -> None :
231
248
super ().__init__ ()
249
+ # Can only fit 2 deployments in a block
250
+ self .num_tx = 2
232
251
233
252
@property
234
253
def name (self ) -> str :
235
254
return 'ERC20 deployment'
236
255
237
- def _apply_transaction (self , chain : MiningChain ) -> None :
238
- self ._deploy_simple_token (chain )
256
+ def _setup_benchmark (self , chain : MiningChain ) -> None :
257
+ self ._next_nonce = None
258
+
259
+ def _next_transaction (self , chain : MiningChain ) -> None :
260
+ txn_info = self ._deploy_simple_token (chain , self ._next_nonce )
261
+ txn = txn_info [0 ]
262
+ self ._next_nonce = txn .nonce + 1
263
+ return txn_info
239
264
240
265
241
266
class ERC20TransferBenchmark (BaseERC20Benchmark ):
242
267
def __init__ (self ) -> None :
243
268
super ().__init__ ()
269
+ self ._next_nonce = None
244
270
245
271
@property
246
272
def name (self ) -> str :
247
273
return 'ERC20 Transfer'
248
274
249
275
def _setup_benchmark (self , chain : MiningChain ) -> None :
250
- self ._deploy_simple_token (chain )
251
- chain .mine_block ()
276
+ self ._next_nonce = None
252
277
253
- def _apply_transaction (self , chain : MiningChain ) -> None :
254
- self ._erc_transfer (self .addr1 , chain )
278
+ txn , callback = self ._deploy_simple_token (chain )
279
+ _ , receipts , computations = chain .mine_all ([txn ])
280
+ assert len (receipts ) == 1
281
+ assert len (computations ) == 1
282
+ callback (receipts [0 ], computations [0 ])
283
+
284
+ def _next_transaction (self , chain : MiningChain ) -> None :
285
+ txn_info = self ._erc_transfer (self .addr1 , chain , self ._next_nonce )
286
+ txn = txn_info [0 ]
287
+ self ._next_nonce = txn .nonce + 1
288
+ return txn_info
255
289
256
290
257
291
class ERC20ApproveBenchmark (BaseERC20Benchmark ):
@@ -263,11 +297,18 @@ def name(self) -> str:
263
297
return 'ERC20 Approve'
264
298
265
299
def _setup_benchmark (self , chain : MiningChain ) -> None :
266
- self ._deploy_simple_token (chain )
267
- chain .mine_block ()
300
+ self ._next_nonce = None
301
+ txn , callback = self ._deploy_simple_token (chain )
302
+ _ , receipts , computations = chain .mine_all ([txn ])
303
+ assert len (receipts ) == 1
304
+ assert len (computations ) == 1
305
+ callback (receipts [0 ], computations [0 ])
268
306
269
- def _apply_transaction (self , chain : MiningChain ) -> None :
270
- self ._erc_approve (self .addr2 , chain )
307
+ def _next_transaction (self , chain : MiningChain ) -> None :
308
+ txn_info = self ._erc_approve (self .addr2 , chain , self ._next_nonce )
309
+ txn = txn_info [0 ]
310
+ self ._next_nonce = txn .nonce + 1
311
+ return txn_info
271
312
272
313
273
314
class ERC20TransferFromBenchmark (BaseERC20Benchmark ):
@@ -279,10 +320,25 @@ def name(self) -> str:
279
320
return 'ERC20 TransferFrom'
280
321
281
322
def _setup_benchmark (self , chain : MiningChain ) -> None :
282
- self ._deploy_simple_token (chain )
283
- self ._erc_transfer (self .addr1 , chain )
284
- self ._erc_approve (self .addr2 , chain )
285
- chain .mine_block ()
286
-
287
- def _apply_transaction (self , chain : MiningChain ) -> None :
288
- self ._erc_transfer_from (self .addr1 , self .addr2 , chain )
323
+ self ._next_nonce = None
324
+ txn , callback = self ._deploy_simple_token (chain )
325
+ _ , receipts , computations = chain .mine_all ([txn ])
326
+ assert len (receipts ) == 1
327
+ assert len (computations ) == 1
328
+ callback (receipts [0 ], computations [0 ])
329
+
330
+ actions = [
331
+ self ._erc_transfer (self .addr1 , chain , nonce = 1 ),
332
+ self ._erc_approve (self .addr2 , chain , nonce = 2 ),
333
+ ]
334
+ transactions , callbacks = zip (* actions )
335
+ _ , receipts , computations = chain .mine_all (transactions )
336
+
337
+ for callback , receipt , computation in zip (callbacks , receipts , computations ):
338
+ callback (receipt , computation )
339
+
340
+ def _next_transaction (self , chain : MiningChain ) -> None :
341
+ txn_info = self ._erc_transfer_from (self .addr1 , self .addr2 , chain , self ._next_nonce )
342
+ txn = txn_info [0 ]
343
+ self ._next_nonce = txn .nonce + 1
344
+ return txn_info
0 commit comments