15
15
from eth .chains .base import (
16
16
MiningChain ,
17
17
)
18
+ from eth .db .atomic import AtomicDB
18
19
from eth .db .chain import (
19
20
ChainDB ,
20
21
)
@@ -149,30 +150,45 @@ def test_chaindb_get_canonical_block_hash(chaindb, block):
149
150
assert block_hash == block .hash
150
151
151
152
152
- def test_chaindb_get_receipt_by_index (
153
- chain ,
154
- funded_address ,
155
- funded_address_private_key ):
156
- NUMBER_BLOCKS_IN_CHAIN = 5
157
- TRANSACTIONS_IN_BLOCK = 10
158
- REQUIRED_BLOCK_NUMBER = 2
159
- REQUIRED_RECEIPT_INDEX = 3
153
+ def mine_blocks_with_receipts (chain ,
154
+ num_blocks ,
155
+ num_tx_per_block ,
156
+ funded_address ,
157
+ funded_address_private_key ):
160
158
161
- for block_number in range (NUMBER_BLOCKS_IN_CHAIN ):
162
- for tx_index in range (TRANSACTIONS_IN_BLOCK ):
159
+ for _ in range (num_blocks ):
160
+ block_receipts = []
161
+ for _ in range (num_tx_per_block ):
163
162
tx = new_transaction (
164
163
chain .get_vm (),
165
164
from_ = funded_address ,
166
165
to = force_bytes_to_address (b'\x10 \x10 ' ),
167
166
private_key = funded_address_private_key ,
168
167
)
169
168
new_block , tx_receipt , computation = chain .apply_transaction (tx )
169
+ block_receipts .append (tx_receipt )
170
170
computation .raise_if_error ()
171
171
172
- if ( block_number + 1 ) == REQUIRED_BLOCK_NUMBER and tx_index == REQUIRED_RECEIPT_INDEX :
173
- actual_receipt = tx_receipt
172
+ yield chain . mine_block (), block_receipts
173
+
174
174
175
- chain .mine_block ()
175
+ def test_chaindb_get_receipt_and_tx_by_index (chain , funded_address , funded_address_private_key ):
176
+ NUMBER_BLOCKS_IN_CHAIN = 5
177
+ TRANSACTIONS_IN_BLOCK = 10
178
+ REQUIRED_BLOCK_NUMBER = 2
179
+ REQUIRED_RECEIPT_INDEX = 3
180
+
181
+ for (block , receipts ) in mine_blocks_with_receipts (
182
+ chain ,
183
+ NUMBER_BLOCKS_IN_CHAIN ,
184
+ TRANSACTIONS_IN_BLOCK ,
185
+ funded_address ,
186
+ funded_address_private_key ,
187
+ ):
188
+ if block .header .block_number == REQUIRED_BLOCK_NUMBER :
189
+ actual_receipt = receipts [REQUIRED_RECEIPT_INDEX ]
190
+ actual_tx = block .transactions [REQUIRED_RECEIPT_INDEX ]
191
+ tx_class = block .transaction_class
176
192
177
193
# Check that the receipt retrieved is indeed the actual one
178
194
chaindb_retrieved_receipt = chain .chaindb .get_receipt_by_index (
@@ -181,6 +197,10 @@ def test_chaindb_get_receipt_by_index(
181
197
)
182
198
assert chaindb_retrieved_receipt == actual_receipt
183
199
200
+ chaindb_retrieved_tx = chain .chaindb .get_transaction_by_index (
201
+ REQUIRED_BLOCK_NUMBER , REQUIRED_RECEIPT_INDEX , tx_class )
202
+ assert chaindb_retrieved_tx == actual_tx
203
+
184
204
# Raise error if block number is not found
185
205
with pytest .raises (ReceiptNotFound ):
186
206
chain .chaindb .get_receipt_by_index (
@@ -194,3 +214,80 @@ def test_chaindb_get_receipt_by_index(
194
214
NUMBER_BLOCKS_IN_CHAIN ,
195
215
TRANSACTIONS_IN_BLOCK + 1 ,
196
216
)
217
+
218
+
219
+ @pytest .mark .parametrize (
220
+ "use_persist_unexecuted_block" ,
221
+ (
222
+ True ,
223
+ pytest .param (
224
+ False ,
225
+ marks = pytest .mark .xfail (
226
+ reason = (
227
+ "The `persist_block` API relies on block execution to persist"
228
+ "transactions and receipts. It is expected to fail this test."
229
+ )
230
+ ),
231
+ ),
232
+ )
233
+ )
234
+ def test_chaindb_persist_unexecuted_block (chain ,
235
+ chain_without_block_validation_factory ,
236
+ funded_address ,
237
+ funded_address_private_key ,
238
+ use_persist_unexecuted_block ):
239
+
240
+ # We need one chain to create blocks and a second one with a pristine database to test
241
+ # persisting blocks that have not been executed.
242
+ second_chain = chain_without_block_validation_factory (AtomicDB ())
243
+ assert chain .get_canonical_head () == second_chain .get_canonical_head ()
244
+ assert chain != second_chain
245
+
246
+ NUMBER_BLOCKS_IN_CHAIN = 5
247
+ TRANSACTIONS_IN_BLOCK = 10
248
+ REQUIRED_BLOCK_NUMBER = 2
249
+ REQUIRED_RECEIPT_INDEX = 3
250
+
251
+ for (block , receipts ) in mine_blocks_with_receipts (
252
+ chain ,
253
+ NUMBER_BLOCKS_IN_CHAIN ,
254
+ TRANSACTIONS_IN_BLOCK ,
255
+ funded_address ,
256
+ funded_address_private_key ,
257
+ ):
258
+ if block .header .block_number == REQUIRED_BLOCK_NUMBER :
259
+ actual_receipt = receipts [REQUIRED_RECEIPT_INDEX ]
260
+ actual_tx = block .transactions [REQUIRED_RECEIPT_INDEX ]
261
+ tx_class = block .transaction_class
262
+
263
+ if use_persist_unexecuted_block :
264
+ second_chain .chaindb .persist_unexecuted_block (block , receipts )
265
+ else :
266
+ # We just use this for an XFAIL to prove `persist_block` does not properly
267
+ # persist blocks that were not executed.
268
+ second_chain .chaindb .persist_block (block )
269
+
270
+ chaindb_retrieved_tx = second_chain .chaindb .get_transaction_by_index (
271
+ REQUIRED_BLOCK_NUMBER , REQUIRED_RECEIPT_INDEX , tx_class )
272
+ assert chaindb_retrieved_tx == actual_tx
273
+
274
+ # Check that the receipt retrieved is indeed the actual one
275
+ chaindb_retrieved_receipt = second_chain .chaindb .get_receipt_by_index (
276
+ REQUIRED_BLOCK_NUMBER ,
277
+ REQUIRED_RECEIPT_INDEX ,
278
+ )
279
+ assert chaindb_retrieved_receipt == actual_receipt
280
+
281
+ # Raise error if block number is not found
282
+ with pytest .raises (ReceiptNotFound ):
283
+ second_chain .chaindb .get_receipt_by_index (
284
+ NUMBER_BLOCKS_IN_CHAIN + 1 ,
285
+ REQUIRED_RECEIPT_INDEX ,
286
+ )
287
+
288
+ # Raise error if receipt index is out of range
289
+ with pytest .raises (ReceiptNotFound ):
290
+ second_chain .chaindb .get_receipt_by_index (
291
+ NUMBER_BLOCKS_IN_CHAIN ,
292
+ TRANSACTIONS_IN_BLOCK + 1 ,
293
+ )
0 commit comments