From d4cfc79db1913d2ddb0909b56c01488596c06167 Mon Sep 17 00:00:00 2001 From: Hank Stoever Date: Tue, 16 Apr 2024 11:47:10 -0700 Subject: [PATCH] feat: improve flooder to support more accounts --- README.md | 84 ++++++++++++++++++++++--------------- docker-compose.yml | 2 +- stacking/flood.ts | 45 ++++++++++++-------- stacking/tx-broadcaster.env | 4 +- 4 files changed, 80 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 2e34b9d..ecee32d 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,10 @@ Add `-f` to automatically follow new logs. The service names can be found in [./ This repo publishes a Docker image that contains a Stacks 2.1 node running in Krypton mode (local testnet). It bundles a `bitcoind` regtest instance and an auto-mining script. The image can be ran as a drop-in replacement for a Stacks node running in `mocknet` mode, but with the benefits of full burnchain and miner capabilities such as: - * PoX reward slot registration and payout events - * Mempool events - * Microblock events + +- PoX reward slot registration and payout events +- Mempool events +- Microblock events #### Usage examples @@ -44,32 +45,34 @@ docker run -p "20443:20443" -e "MINE_INTERVAL=2.5s" hirosystems/stacks-api-e2e ``` An event observer can be registered using the `STACKS_EVENT_OBSERVER` environnment variable. For example, assuming the observer is running on the host machine on port 3700: + ```shell docker run -p "20443:20443" -e "MINE_INTERVAL=2.5s" -e "STACKS_EVENT_OBSERVER=host.docker.internal:3700" hirosystems/stacks-api-e2e ``` - -A Stacks 2.1 `coinbase-alt-recipient` reward address can be configured using the `REWARD_RECIPIENT` environment variable. -This configures the Stacks node `[miner.block_reward_recipient]` toml config value. -If not specified, regular `coinbase` transactions will be mined. -Note that the address will receive STX rewards 100 blocks _after_ Epoch 2.1 is activated. +A Stacks 2.1 `coinbase-alt-recipient` reward address can be configured using the `REWARD_RECIPIENT` environment variable. +This configures the Stacks node `[miner.block_reward_recipient]` toml config value. +If not specified, regular `coinbase` transactions will be mined. +Note that the address will receive STX rewards 100 blocks _after_ Epoch 2.1 is activated. Usage example: + ```shell docker run -p "20443:20443" -e "REWARD_RECIPIENT=STQM73RQC4EX0A07KWG1J5ECZJYBZS4SJ4ERC6WN" hirosystems/stacks-api-e2e ``` - In addition, the image has several tags providing different Stacks bootstrapping sequence configs: - * The default tag `latest` starts directly in epoche 2.1 with PoX-2 activated - * Tag `stacks2.1-transition` starts in epoche 2.0, then transitions to epoche 2.1 after ~15 blocks, then activates PoX-2 after another ~15 blocks +- The default tag `latest` starts directly in epoche 2.1 with PoX-2 activated +- Tag `stacks2.1-transition` starts in epoche 2.0, then transitions to epoche 2.1 after ~15 blocks, then activates PoX-2 after another ~15 blocks It's possible to build images with custom bootstrapping sequences by specifying the build args: -* `STACKS_21_HEIGHT` - the burnblock height at which epoch 2.1 is activated -* `STACKS_POX2_HEIGHT` - the burnblock height at which PoX-2 is activated -Note that the first Stacks block will be mined at burnblock height 104. +- `STACKS_21_HEIGHT` - the burnblock height at which epoch 2.1 is activated +- `STACKS_POX2_HEIGHT` - the burnblock height at which PoX-2 is activated + +Note that the first Stacks block will be mined at burnblock height 104. So, for example, if you want epoch 2.1 to activate at Stacks block 10, and PoX-2 at Stacks block 20, then specify `STACKS_21_HEIGHT=114` and `STACKS_POX2_HEIGHT=124`: + ```shell # clone repo git clone https://github.com/hirosystems/stacks-regtest-env.git @@ -83,27 +86,32 @@ docker run -p "20443:20443" -e "MINE_INTERVAL=5s" my_image ## Run with Docker Compose Clone this repo and change to its directory: + ```shell git clone https://github.com/hirosystems/stacks-regtest-env.git cd stacks-regtest-env ``` Run the command to start the network: + ```shell docker compose -f docker-compose-miner.yml -f docker-compose-follower.yml up --build -d ``` + The initial [101 blocks on bitcoind](https://developer.bitcoin.org/examples/testing.html#regtest-mode) (required to have any spendable tBTC in regtest) are mined immediately, after which Stacks blocks will be mined for every new bitcoin block. The block mining interval defaults to 500ms. This can be configured with the `MINE_INTERVAL` environment variable, for example: + ```shell MINE_INTERVAL=2.5s docker compose -f docker-compose-miner.yml -f docker-compose-follower.yml up --build -d ``` -The Stacks 2.1 `coinbase-alt-recipient` reward address can be configured using the `REWARD_RECIPIENT` environment variable. -This configures the Stacks node `[miner.block_reward_recipient]` toml config value. -If not specified, regular `coinbase` transactions will be mined. -Note that the address will receive STX rewards 100 blocks _after_ Epoch 2.1 is activated. +The Stacks 2.1 `coinbase-alt-recipient` reward address can be configured using the `REWARD_RECIPIENT` environment variable. +This configures the Stacks node `[miner.block_reward_recipient]` toml config value. +If not specified, regular `coinbase` transactions will be mined. +Note that the address will receive STX rewards 100 blocks _after_ Epoch 2.1 is activated. Usage example: + ```shell REWARD_RECIPIENT=STQM73RQC4EX0A07KWG1J5ECZJYBZS4SJ4ERC6WN MINE_INTERVAL=2.5s docker compose -f docker-compose-miner.yml -f docker-compose-follower.yml up --build -d ``` @@ -111,27 +119,35 @@ REWARD_RECIPIENT=STQM73RQC4EX0A07KWG1J5ECZJYBZS4SJ4ERC6WN MINE_INTERVAL=2.5s doc #### The following services are created ###### Bitcoind node in regtest mode - * JSON-RPC interface available at http://localhost:18443 - * RPC auth username and password are both `btc` - * tBTC is available from the miner account: - * Address: `miEJtNKa3ASpA19v5ZhvbKTEieYjLpzCYT` - * Private key: `9e446f6b0c6a96cf2190e54bcd5a8569c3e386f091605499464389b8d4e0bfc201` - * Private key (WIF format): `cStMQXkK5yTFGP3KbNXYQ3sJf2qwQiKrZwR9QJnksp32eKzef1za` + +- JSON-RPC interface available at http://localhost:18443 +- RPC auth username and password are both `btc` +- tBTC is available from the miner account: + - Address: `miEJtNKa3ASpA19v5ZhvbKTEieYjLpzCYT` + - Private key: `9e446f6b0c6a96cf2190e54bcd5a8569c3e386f091605499464389b8d4e0bfc201` + - Private key (WIF format): `cStMQXkK5yTFGP3KbNXYQ3sJf2qwQiKrZwR9QJnksp32eKzef1za` + ###### Mining script that automatically triggers bitcoind to mine new Bitcoin blocks - * Block mining interval defaults to 500ms, configure using the `MINE_INTERVAL` environment variable + +- Block mining interval defaults to 500ms, configure using the `MINE_INTERVAL` environment variable + ###### Stacks-node in kypton mode (i.e. a regtest-like local testnet) - * RPC available at http://localhost:20443/v2/info - * STX are preseeded to several accounts listed in [`stacks-krypton-miner.toml`](stacks-krypton-miner.toml), first account: - * Address: `STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6` - * Key: `cb3df38053d132895220b9ce471f6b676db5b9bf0b4adefb55f2118ece2478df01` + +- RPC available at http://localhost:20443/v2/info +- STX are preseeded to several accounts listed in [`stacks-krypton-miner.toml`](stacks-krypton-miner.toml), first account: + - Address: `STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6` + - Key: `cb3df38053d132895220b9ce471f6b676db5b9bf0b4adefb55f2118ece2478df01` + ###### Stacks API instance - * API available at http://localhost:3999/extended/v1/block - * Playground/debug webpages listed at http://localhost:3999/extended/v1/debug/broadcast + +- API available at http://localhost:3999/extended/v1/block +- Playground/debug webpages listed at http://localhost:3999/extended/v1/debug/broadcast + ###### PostgreSQL database required by the Stacks API - * PG port is available at 5490 - * Both username and password are `postgres` - * Database name: `stacks_blockchain_api` +- PG port is available at 5490 +- Both username and password are `postgres` +- Database name: `stacks_blockchain_api` _Note:_ The chainstate is reset every time docker compose `up` is run. diff --git a/docker-compose.yml b/docker-compose.yml index 283febe..e11096e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ x-common-vars: - &BITCOIN_RPC_PASS btc - &MINE_INTERVAL ${MINE_INTERVAL:-1s} - &MINE_INTERVAL_EPOCH25 ${MINE_INTERVAL_EPOCH25:-10s} # 10 second bitcoin block times in epoch 2.5 - - &MINE_INTERVAL_EPOCH3 ${MINE_INTERVAL_EPOCH3:-600s} # 10 minute bitcoin block times in epoch 3 + - &MINE_INTERVAL_EPOCH3 ${MINE_INTERVAL_EPOCH3:-30s} # 10 minute bitcoin block times in epoch 3 - &NAKAMOTO_BLOCK_INTERVAL 2 # seconds to wait between issuing stx-transfer transactions (which triggers Nakamoto block production) - &STACKS_20_HEIGHT ${STACKS_20_HEIGHT:-0} - &STACKS_2_05_HEIGHT ${STACKS_2_05_HEIGHT:-102} diff --git a/stacking/flood.ts b/stacking/flood.ts index d2ee25b..c2fc5aa 100644 --- a/stacking/flood.ts +++ b/stacking/flood.ts @@ -12,6 +12,8 @@ import { makeContractCall, tupleCV, uintCV, + AnchorMode, + PostConditionMode, } from '@stacks/transactions'; import { readFileSync } from 'fs'; import { config } from 'dotenv'; @@ -61,23 +63,29 @@ async function bootstrapFlooders() { // sync iterate let i = 0n; let allWorked = true; - for (const flooder of flooders) { - const tx = await makeSTXTokenTransfer({ - recipient: flooder.stxAddress, - amount: 1000000 * 10_000, // 10k STX - senderKey: bootstrapper.privKey, - network, - nonce: nonce + i, - fee: 300, - anchorMode: 'any', - }); - i++; - const ok = await broadcast(tx, bootstrapper.stxAddress); - if (!ok) { - allWorked = false; - break; - } - } + const amount = 1000000 * 10_000; // 10k STX + const transfersClarity = flooders.map(flooder => { + return `(try! (stx-transfer? u${amount} tx-sender '${flooder.stxAddress}))`; + }); + const contractBody = ` + (begin + ${transfersClarity.join('\n')} + (ok true) + ) + `; + const bootstrapTx = await makeContractDeploy({ + contractName: `bootstrap-${new Date().getTime().toString().slice(-4)}`, + postConditionMode: PostConditionMode.Allow, + fee: 3000000, + network, + nonce: nonce + i, + senderKey: bootstrapper.privKey, + anchorMode: AnchorMode.Any, + codeBody: contractBody, + }); + await broadcast(bootstrapTx, bootstrapper.stxAddress); + i++; + // console.log(contractBody); if (!(await isContractDeployed(floodContractDeployer))) { const ok = await broadcast( await makeContractDeploy({ @@ -85,9 +93,10 @@ async function bootstrapFlooders() { nonce: nonce + i, contractName: 'flood', codeBody: floodContract, - fee: 3000, + fee: 3000000, anchorMode: 'any', network, + postConditionMode: PostConditionMode.Allow, }), bootstrapper.stxAddress ); diff --git a/stacking/tx-broadcaster.env b/stacking/tx-broadcaster.env index e45335b..da62c9d 100644 --- a/stacking/tx-broadcaster.env +++ b/stacking/tx-broadcaster.env @@ -3,8 +3,8 @@ STACKS_CORE_RPC_PORT=3999 NAKAMOTO_BLOCK_INTERVAL=2 STACKS_30_HEIGHT=131 ACCOUNT_KEYS=0d2f965b472a82efd5a96e6513c8b9f7edc725d5c96c7d35d6c722cedeb80d1b01,975b251dd7809469ef0c26ec3917971b75c51cd73a022024df4bf3b232cc2dc001,c71700b07d520a8c9731e4d0f095aa6efb91e16e25fb27ce2b72e7b698f8127a01 -NUM_FLOODERS=15 -TX_PER_FLOOD=15 +NUM_FLOODERS=100 +TX_PER_FLOOD=5 STACKS_25_HEIGHT=108 STACKING_KEYS: 6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01,b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401,7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01 POX_PREPARE_LENGTH=5