-
Notifications
You must be signed in to change notification settings - Fork 25
feat(functional-tests): migrate btcio tests to new framework (STR-2090) #1451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
f126a3e
feat(functional-tests): migrate portable btcio tests to new framework…
voidash eb243a8
fix(functional-tests): bump btcio test timeouts and fix ruff formatting
voidash a6ad430
refactor(functional-tests): extract wait_for_l1_commitment helper
voidash ce0a18d
style: fix ruff lint and format issues
voidash 3ce4b69
fix(functional-tests): fix btcio tests and disable pending ASM race fix
voidash f21100d
fix(functional-tests): address btcio review feedback
voidash 0ced17d
fix(asm-worker): retry get_l1_block on transient MissingL1Block errors
voidash File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
|
voidash marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| """Test that strata is connected to Bitcoin and tracking L1 blocks.""" | ||
|
|
||
| import logging | ||
|
|
||
| import flexitest | ||
|
|
||
| from common.base_test import StrataNodeTest | ||
| from common.config import ServiceType | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @flexitest.register | ||
| class TestL1Connected(StrataNodeTest): | ||
| """Verify strata can see L1 blocks. | ||
|
|
||
| The basic env pre-generates 110 Bitcoin blocks before starting strata. | ||
| After strata starts, it should have L1 header commitments for those | ||
| blocks. We check that the genesis L1 height has a commitment, which | ||
| proves the L1 reader is connected and processing blocks. | ||
|
|
||
| Replaces old: btcio_connect.py (strata_l1connected) | ||
| """ | ||
|
|
||
| def __init__(self, ctx: flexitest.InitContext): | ||
| ctx.set_env("basic") | ||
|
|
||
| def main(self, ctx): | ||
| strata = self.get_service(ServiceType.Strata) | ||
| bitcoin = self.get_service(ServiceType.Bitcoin) | ||
|
|
||
| rpc = strata.wait_for_rpc_ready(timeout=30) | ||
| btc_rpc = bitcoin.create_rpc() | ||
|
|
||
| # The basic env pre-generates 110 blocks. The genesis L1 height | ||
| # equals the Bitcoin tip at the time strata started (~110). | ||
| # The ASM only creates manifests for heights >= genesis, so we | ||
| # check the genesis height itself. | ||
| chain_info = btc_rpc.proxy.getblockchaininfo() | ||
| tip_height = chain_info["blocks"] | ||
| logger.info(f"Bitcoin tip (genesis L1 height): {tip_height}") | ||
|
|
||
| commitment = strata.wait_for_l1_commitment_at(tip_height, rpc=rpc, timeout=60) | ||
|
|
||
| logger.info(f"L1 header commitment at {tip_height}: {commitment}") | ||
| return True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| """Test that strata handles Bitcoin L1 chain reorganizations.""" | ||
|
|
||
| import logging | ||
|
|
||
| import flexitest | ||
|
|
||
| from common.base_test import StrataNodeTest | ||
| from common.config import ServiceType | ||
| from envconfigs.strata import StrataEnvConfig | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| # How many blocks above genesis to mine before triggering reorg. | ||
| EXTRA_BLOCKS = 6 | ||
| # How many of those extra blocks to invalidate. | ||
| REORG_DEPTH = 3 | ||
|
|
||
|
|
||
| @flexitest.register | ||
| class TestL1Reorg(StrataNodeTest): | ||
| """Verify strata detects and handles L1 block reorganizations. | ||
|
|
||
| Mines blocks above genesis so the ASM has manifests to compare, | ||
| then invalidates some of those blocks, mines replacements, and | ||
| checks that strata updates its L1 header commitments. | ||
|
|
||
| Replaces old: btcio_read_reorg.py (L1ReadReorgTest) | ||
| """ | ||
|
|
||
| def __init__(self, ctx: flexitest.InitContext): | ||
| # standalone env: this test mutates the bitcoin chain via invalidateblock | ||
| ctx.set_env(StrataEnvConfig(pre_generate_blocks=110)) | ||
|
|
||
| def main(self, ctx): | ||
| strata = self.get_service(ServiceType.Strata) | ||
| bitcoin = self.get_service(ServiceType.Bitcoin) | ||
|
|
||
| rpc = strata.wait_for_rpc_ready(timeout=30) | ||
| btc_rpc = bitcoin.create_rpc() | ||
|
|
||
| # Genesis L1 height = current bitcoin tip (set during env init). | ||
| # The ASM only creates manifests for heights >= genesis, so we must | ||
| # mine additional blocks and reorg within *those*, not below genesis. | ||
| genesis_tip = btc_rpc.proxy.getblockchaininfo()["blocks"] | ||
| logger.info(f"Genesis L1 tip: {genesis_tip}") | ||
|
|
||
| # Mine blocks above genesis one at a time so the ASM processes each | ||
| # before the next arrives (avoids L1 reader / ASM notification race). | ||
| addr = btc_rpc.proxy.getnewaddress() | ||
| for _ in range(EXTRA_BLOCKS): | ||
| btc_rpc.proxy.generatetoaddress(1, addr) | ||
| tip_height = btc_rpc.proxy.getblockchaininfo()["blocks"] | ||
| logger.info(f"Bitcoin tip after extra mining: {tip_height}") | ||
|
|
||
| # Pick a height to invalidate — must be above genesis. | ||
| invalidate_height = tip_height - REORG_DEPTH | ||
| assert invalidate_height > genesis_tip, ( | ||
| f"invalidate_height {invalidate_height} must be above genesis {genesis_tip}" | ||
| ) | ||
| logger.info(f"Will invalidate from height {invalidate_height}") | ||
|
|
||
| # Wait for strata to have processed the block at this height. | ||
| pre_reorg_commitment = strata.wait_for_l1_commitment_at( | ||
| invalidate_height, rpc=rpc, timeout=120 | ||
| ) | ||
| logger.info(f"Pre-reorg commitment at {invalidate_height}: {pre_reorg_commitment}") | ||
|
|
||
| # Invalidate the block (and all descendants). | ||
| block_hash = btc_rpc.proxy.getblockhash(invalidate_height) | ||
| logger.info(f"Invalidating block {block_hash}") | ||
| btc_rpc.proxy.invalidateblock(block_hash) | ||
|
|
||
| # Sanity check: bitcoin tip should have regressed. | ||
| regressed_tip = btc_rpc.proxy.getblockchaininfo()["blocks"] | ||
| if regressed_tip >= invalidate_height: | ||
| raise AssertionError( | ||
| f"Expected tip below {invalidate_height} after invalidation, got {regressed_tip}" | ||
| ) | ||
| logger.info(f"Bitcoin tip regressed to {regressed_tip}") | ||
|
|
||
| # Mine replacement blocks past the old invalidation point one at a time. | ||
| # Use a fresh address to avoid duplicate-invalid coinbase collisions. | ||
| reorg_addr = btc_rpc.proxy.getnewaddress() | ||
| blocks_to_mine = REORG_DEPTH + 2 | ||
| for _ in range(blocks_to_mine): | ||
| btc_rpc.proxy.generatetoaddress(1, reorg_addr) | ||
| post_tip = btc_rpc.proxy.getblockchaininfo()["blocks"] | ||
| logger.info(f"Post-reorg Bitcoin tip: {post_tip}") | ||
|
|
||
| # Wait for strata to pick up the new chain; the commitment | ||
| # at invalidate_height must differ from the pre-reorg value. | ||
| post_reorg_commitment = strata.wait_for_l1_commitment_at( | ||
| invalidate_height, | ||
| rpc=rpc, | ||
| timeout=120, | ||
| differs_from=pre_reorg_commitment, | ||
| ) | ||
| logger.info(f"Post-reorg commitment at {invalidate_height}: {post_reorg_commitment}") | ||
|
|
||
| logger.info( | ||
| "Strata detected L1 reorg: commitment changed at height %d", | ||
| invalidate_height, | ||
| ) | ||
| return True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| """Test that strata tracks new L1 blocks as they are mined.""" | ||
|
|
||
| import logging | ||
|
|
||
| import flexitest | ||
|
|
||
| from common.base_test import StrataNodeTest | ||
| from common.config import ServiceType | ||
| from envconfigs.strata import StrataEnvConfig | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @flexitest.register | ||
| class TestL1Tracking(StrataNodeTest): | ||
| """Verify strata's L1 reader picks up newly mined Bitcoin blocks. | ||
|
|
||
| Mines additional Bitcoin blocks after strata is running and verifies | ||
| that strata_getL1HeaderCommitment returns data for the new heights. | ||
|
|
||
| Uses a standalone env to avoid interference from other tests that | ||
| may restart the sequencer. | ||
|
|
||
| Replaces old: btcio_read.py (strata_l1status) | ||
| """ | ||
|
|
||
| EXTRA_BLOCKS = 5 | ||
|
|
||
| def __init__(self, ctx: flexitest.InitContext): | ||
| ctx.set_env(StrataEnvConfig(pre_generate_blocks=110)) | ||
|
|
||
| def main(self, ctx): | ||
| strata = self.get_service(ServiceType.Strata) | ||
| bitcoin = self.get_service(ServiceType.Bitcoin) | ||
|
|
||
| rpc = strata.wait_for_rpc_ready(timeout=30) | ||
| btc_rpc = bitcoin.create_rpc() | ||
|
|
||
| # Record the current Bitcoin tip | ||
| pre_tip = btc_rpc.proxy.getblockchaininfo()["blocks"] | ||
| logger.info(f"Bitcoin tip before mining: {pre_tip}") | ||
|
|
||
| # Wait for strata to have caught up to pre_tip | ||
| strata.wait_for_l1_commitment_at(pre_tip, rpc=rpc, timeout=120) | ||
|
|
||
| # Mine additional blocks one at a time. Mining in a single batch can | ||
| # trigger a race in the L1 reader / ASM pipeline where the ASM is | ||
| # notified about a block before the full block data is persisted. | ||
| addr = btc_rpc.proxy.getnewaddress() | ||
| for _ in range(self.EXTRA_BLOCKS): | ||
| btc_rpc.proxy.generatetoaddress(1, addr) | ||
| post_tip = btc_rpc.proxy.getblockchaininfo()["blocks"] | ||
| logger.info(f"Bitcoin tip after mining {self.EXTRA_BLOCKS} blocks: {post_tip}") | ||
|
|
||
| if post_tip != pre_tip + self.EXTRA_BLOCKS: | ||
| raise AssertionError(f"Expected tip {pre_tip + self.EXTRA_BLOCKS}, got {post_tip}") | ||
|
|
||
| # Wait for strata to pick up the new blocks | ||
| commitment = strata.wait_for_l1_commitment_at(post_tip, rpc=rpc, timeout=120) | ||
| logger.info(f"L1 header commitment at new tip {post_tip}: {commitment}") | ||
|
|
||
| # Verify intermediate heights also have commitments. | ||
| # The tip is already confirmed, so intermediate heights should be | ||
| # available immediately — use a short timeout. | ||
| for h in range(pre_tip + 1, post_tip + 1): | ||
| strata.wait_for_l1_commitment_at(h, rpc=rpc, timeout=5) | ||
|
|
||
| logger.info( | ||
| "Strata tracked all %d new L1 blocks (%d -> %d)", | ||
| self.EXTRA_BLOCKS, | ||
| pre_tip, | ||
| post_tip, | ||
| ) | ||
| return True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.