1- import logging
21import pathlib
32from typing import (
43 Tuple ,
1514from eth_utils import (
1615 encode_hex ,
1716 decode_hex ,
18- to_int ,
1917)
2018
2119from eth .constants import (
6159
6260class BaseERC20Benchmark (BaseBenchmark ):
6361
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 :
6563 super ().__init__ ()
6664
6765 self .num_blocks = num_blocks
@@ -82,7 +80,7 @@ def _setup_benchmark(self, chain: MiningChain) -> None:
8280 pass
8381
8482 @abstractmethod
85- def _apply_transaction (self , chain : MiningChain ) -> None :
83+ def _next_transaction (self , chain : MiningChain ) -> None :
8684 raise NotImplementedError (
8785 "Must be implemented by subclasses"
8886 )
@@ -114,7 +112,8 @@ def mine_blocks(self, chain: MiningChain, num_blocks: int, num_tx: int) -> Tuple
114112 total_gas_used = 0
115113 total_num_tx = 0
116114 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
118117 total_gas_used = total_gas_used + block .header .gas_used
119118 total_num_tx = total_num_tx + len (block .transactions )
120119 return total_gas_used , total_num_tx
@@ -123,11 +122,19 @@ def mine_block(self,
123122 chain : MiningChain ,
124123 block_number : int ,
125124 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+ ))
129129
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 :
131138 # Instantiate the contract
132139 SimpleToken = self .w3 .eth .contract (
133140 abi = self .contract_interface ['abi' ],
@@ -143,21 +150,24 @@ def _deploy_simple_token(self, chain: MiningChain) -> None:
143150 amount = 0 ,
144151 gas = FIRST_TX_GAS_LIMIT ,
145152 data = decode_hex (w3_tx ['data' ]),
153+ nonce = nonce ,
146154 )
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
151155
152- computation .raise_if_error ()
156+ def callback (receipt , computation ) -> None :
157+ computation .raise_if_error ()
153158
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
159169
160- def _erc_transfer (self , addr : str , chain : MiningChain ) -> None :
170+ def _erc_transfer (self , addr : str , chain : MiningChain , nonce : int = None ) -> None :
161171 w3_tx = self .simple_token .functions .transfer (
162172 addr ,
163173 TRANSFER_AMOUNT
@@ -171,15 +181,15 @@ def _erc_transfer(self, addr: str, chain: MiningChain) -> None:
171181 amount = 0 ,
172182 gas = SECOND_TX_GAS_LIMIT ,
173183 data = decode_hex (w3_tx ['data' ]),
184+ nonce = nonce ,
174185 )
175186
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
177191
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 :
183193 w3_tx = self .simple_token .functions .approve (
184194 addr2 ,
185195 TRANSFER_AMOUNT
@@ -193,15 +203,21 @@ def _erc_approve(self, addr2: str, chain: MiningChain) -> None:
193203 amount = 0 ,
194204 gas = SECOND_TX_GAS_LIMIT ,
195205 data = decode_hex (w3_tx ['data' ]),
206+ nonce = nonce ,
196207 )
197208
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
199212
200- computation . raise_if_error ()
213+ return tx , callback
201214
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 :
205221
206222 w3_tx = self .simple_token .functions .transferFrom (
207223 addr1 ,
@@ -217,41 +233,59 @@ def _erc_transfer_from(self, addr1: str, addr2: str, chain: MiningChain) -> None
217233 amount = 0 ,
218234 gas = SECOND_TX_GAS_LIMIT ,
219235 data = decode_hex (w3_tx ['data' ]),
236+ nonce = nonce ,
220237 )
221238
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
225242
226- assert to_int ( computation . output ) == 1
243+ return tx , callback
227244
228245
229246class ERC20DeployBenchmark (BaseERC20Benchmark ):
230247 def __init__ (self ) -> None :
231248 super ().__init__ ()
249+ # Can only fit 2 deployments in a block
250+ self .num_tx = 2
232251
233252 @property
234253 def name (self ) -> str :
235254 return 'ERC20 deployment'
236255
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
239264
240265
241266class ERC20TransferBenchmark (BaseERC20Benchmark ):
242267 def __init__ (self ) -> None :
243268 super ().__init__ ()
269+ self ._next_nonce = None
244270
245271 @property
246272 def name (self ) -> str :
247273 return 'ERC20 Transfer'
248274
249275 def _setup_benchmark (self , chain : MiningChain ) -> None :
250- self ._deploy_simple_token (chain )
251- chain .mine_block ()
276+ self ._next_nonce = None
252277
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
255289
256290
257291class ERC20ApproveBenchmark (BaseERC20Benchmark ):
@@ -263,11 +297,18 @@ def name(self) -> str:
263297 return 'ERC20 Approve'
264298
265299 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 ])
268306
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
271312
272313
273314class ERC20TransferFromBenchmark (BaseERC20Benchmark ):
@@ -279,10 +320,25 @@ def name(self) -> str:
279320 return 'ERC20 TransferFrom'
280321
281322 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