diff --git a/docker/docker-compose.dev.stacks-blockchain.yml b/docker/docker-compose.dev.stacks-blockchain.yml index f2a1a69321..59e4e854f5 100644 --- a/docker/docker-compose.dev.stacks-blockchain.yml +++ b/docker/docker-compose.dev.stacks-blockchain.yml @@ -1,7 +1,7 @@ version: '3.7' services: stacks-blockchain: - image: 'hirosystems/stacks-api-e2e:stacks3.0-204ab4c' + image: 'hirosystems/stacks-api-e2e:stacks3.0-1d675fd' restart: on-failure environment: STACKS_EVENT_OBSERVER: host.docker.internal:3700 diff --git a/docker/docker-compose.dev.stacks-krypton.yml b/docker/docker-compose.dev.stacks-krypton.yml index feaf0cf0a3..48dd94f236 100644 --- a/docker/docker-compose.dev.stacks-krypton.yml +++ b/docker/docker-compose.dev.stacks-krypton.yml @@ -1,7 +1,7 @@ version: '3.7' services: stacks-blockchain: - image: 'hirosystems/stacks-api-e2e:stacks3.0-204ab4c' + image: 'hirosystems/stacks-api-e2e:stacks3.0-1d675fd' ports: - '18443:18443' # bitcoin regtest JSON-RPC interface - '18444:18444' # bitcoin regtest p2p diff --git a/src/tests-2.5/env-setup.ts b/src/tests-2.5/env-setup.ts index 34b5c0acee..4d13111546 100644 --- a/src/tests-2.5/env-setup.ts +++ b/src/tests-2.5/env-setup.ts @@ -34,7 +34,7 @@ beforeAll(async () => { user: BTC_RPC_USER, pass: BTC_RPC_PW, timeout: 120000, - wallet: '', + wallet: 'main', }); testEnv = { diff --git a/src/tests-2.5/pox-4-btc-address-formats.ts b/src/tests-2.5/pox-4-btc-address-formats.ts index c55911dd37..01d467eaf3 100644 --- a/src/tests-2.5/pox-4-btc-address-formats.ts +++ b/src/tests-2.5/pox-4-btc-address-formats.ts @@ -26,6 +26,7 @@ import { standByUntilBurnBlock, testEnv, } from '../test-utils/test-helpers'; +import { RPCClient } from 'rpc-bitcoin'; const BTC_PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000002'; @@ -44,35 +45,49 @@ describe.each([P2SH_P2WPKH, P2WPKH, P2WSH, P2TR])( const { btcAddr, btcAddrDecoded, btcAddrRegtest, btcDescriptor } = addressSetup(); + let bitcoinRpcClient: RPCClient; + + test('setup BTC wallet client', async () => { + const { BTC_RPC_PORT, BTC_RPC_HOST, BTC_RPC_PW, BTC_RPC_USER } = process.env; + bitcoinRpcClient = new RPCClient({ + url: BTC_RPC_HOST, + port: Number(BTC_RPC_PORT), + user: BTC_RPC_USER, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + pass: BTC_RPC_PW!, + timeout: 120000, + wallet: btcAddrRegtest, + }); + const createWalletResult = await bitcoinRpcClient.createwallet({ + wallet_name: btcAddrRegtest, + blank: true, + disable_private_keys: true, + descriptors: true, + load_on_startup: false, + } as any); + expect(createWalletResult.name).toBe(btcAddrRegtest); + expect(createWalletResult.warning).toBeFalsy(); + + // descriptor wallets, if legacy wallet import fails + const info = await bitcoinRpcClient.getdescriptorinfo({ + descriptor: btcDescriptor, + }); + const request = { label: btcAddrRegtest, desc: info.descriptor, timestamp: 'now' }; + const importDescriptorRes: { success: boolean }[] = await bitcoinRpcClient.rpc( + 'importdescriptors', + { requests: [request] }, + btcAddrRegtest + ); + expect(importDescriptorRes[0].success).toBe(true); + const btcWalletAddrs = await bitcoinRpcClient.getaddressesbylabel({ + label: btcAddrRegtest, + }); + expect(Object.keys(btcWalletAddrs)).toEqual([btcAddrRegtest]); + }); + test('prepare', async () => { await standByForPoxCycle(); - try { - // legacy wallets - await testEnv.bitcoinRpcClient.importaddress({ - address: btcAddrRegtest, - label: btcAddrRegtest, - }); - const btcWalletAddrs = await testEnv.bitcoinRpcClient.getaddressesbylabel({ - label: btcAddrRegtest, - }); - expect(Object.keys(btcWalletAddrs)).toContain(btcAddrRegtest); - } catch (e) { - // descriptor wallets, if legacy wallet import fails - await withDescriptorWallet(async walletName => { - const info = await testEnv.bitcoinRpcClient.getdescriptorinfo({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - descriptor: btcDescriptor!, - }); - const request = { label: btcAddrRegtest, desc: info.descriptor, timestamp: 'now' }; - await testEnv.bitcoinRpcClient.rpc( - 'importdescriptors', - { requests: [request] }, - walletName - ); - }); - } - poxInfo = await testEnv.client.getPox(); burnBlockHeight = poxInfo.current_burnchain_block_height as number; @@ -172,7 +187,7 @@ describe.each([P2SH_P2WPKH, P2WPKH, P2WSH, P2TR])( const rewards = await fetchGet( `/extended/v1/burnchain/rewards/${btcAddr}` ); - expect(rewards.results).toHaveLength(1); + expect(rewards.results.length).toBeGreaterThan(0); const firstReward = rewards.results.sort( (a, b) => a.burn_block_height - b.burn_block_height @@ -207,7 +222,7 @@ describe.each([P2SH_P2WPKH, P2WPKH, P2WSH, P2TR])( const blockResult: { tx: { vout?: { scriptPubKey: { address?: string }; value?: number }[] }[]; - } = await testEnv.bitcoinRpcClient.getblock({ + } = await bitcoinRpcClient.getblock({ blockhash: hexToBuffer(firstReward.burn_block_hash).toString('hex'), verbosity: 2, }); @@ -231,43 +246,45 @@ describe.each([P2SH_P2WPKH, P2WPKH, P2WSH, P2TR])( (a, b) => a.burn_block_height - b.burn_block_height )[0]; - let txs = await withDescriptorWallet( - async walletName => - (await testEnv.bitcoinRpcClient.listtransactions( - { - label: btcAddrRegtest, - include_watchonly: true, - }, - btcDescriptor ? walletName : undefined - )) as { - address: string; - category: string; - amount: number; - blockhash: string; - blockheight: number; - }[] + let txs: { + address: string; + category: string; + amount: number; + blockhash: string; + blockheight: number; + }[] = await bitcoinRpcClient.listtransactions( + { + label: btcAddrRegtest, + include_watchonly: true, + }, + btcAddrRegtest ); txs = txs.filter(r => r.address === btcAddrRegtest); - expect(txs.length).toBe(1); - expect(txs[0].category).toBe('receive'); - expect(txs[0].blockhash).toBe(hexToBuffer(firstReward.burn_block_hash).toString('hex')); - const sats = new bignumber(txs[0].amount).shiftedBy(8).toString(); + + expect(txs.length).toBeGreaterThan(0); + + const firstTx = txs.sort((a, b) => a.blockheight - b.blockheight)[0]; + expect(firstTx.category).toBe('receive'); + expect(firstTx.blockhash).toBe(hexToBuffer(firstReward.burn_block_hash).toString('hex')); + const sats = new bignumber(firstTx.amount).shiftedBy(8).toString(); expect(sats).toBe(firstReward.reward_amount); }); test('BTC stacking reward received', async () => { - const received = await withDescriptorWallet( - async walletName => - (await testEnv.bitcoinRpcClient.getreceivedbyaddress( - { - address: btcAddrRegtest, - minconf: 0, - }, - btcDescriptor ? walletName : undefined - )) as number + const received: number = await bitcoinRpcClient.getreceivedbyaddress( + { + address: btcAddrRegtest, + minconf: 0, + }, + btcAddrRegtest ); expect(received).toBeGreaterThan(0); }); + + afterAll(async () => { + // after: unload descriptor wallet + await bitcoinRpcClient.unloadwallet({ wallet_name: btcAddrRegtest }); + }); } ); @@ -300,7 +317,7 @@ function P2SH_P2WPKH() { btcAddrDecoded, btcAddrRegtest, btcPubKey, - btcDescriptor: undefined, + btcDescriptor: `sh(wpkh(${btcPubKey}))`, }; } @@ -336,7 +353,7 @@ function P2WSH() { btcAddrDecoded, btcAddrRegtest, btcPubKey, - btcDescriptor: undefined, + btcDescriptor: `wsh(multi(1,${btcPubKey}))`, }; } @@ -369,7 +386,7 @@ function P2WPKH() { btcAddrDecoded, btcAddrRegtest, btcPubKey, - btcDescriptor: undefined, + btcDescriptor: `wpkh(${btcPubKey})`, }; } @@ -408,25 +425,3 @@ function P2TR() { btcDescriptor: `tr(${btcPubKey})`, }; } - -// helper -async function withDescriptorWallet(fn: (walletName: string) => Promise | R): Promise { - // before: load or create descriptor wallet - try { - await testEnv.bitcoinRpcClient.loadwallet({ filename: 'descriptor-wallet' }); - } catch (e) { - await testEnv.bitcoinRpcClient.createwallet({ - wallet_name: 'descriptor-wallet', - disable_private_keys: true, - descriptors: true, - load_on_startup: false, - } as any); - } - - const res = await fn('descriptor-wallet'); - - // after: unload descriptor walletl - await testEnv.bitcoinRpcClient.unloadwallet({ wallet_name: 'descriptor-wallet' }); - - return res; -} diff --git a/src/tests-2.5/pox-4-delegate-aggregation.ts b/src/tests-2.5/pox-4-delegate-aggregation.ts index 6dc5c0de8a..94ad3a8892 100644 --- a/src/tests-2.5/pox-4-delegate-aggregation.ts +++ b/src/tests-2.5/pox-4-delegate-aggregation.ts @@ -58,15 +58,12 @@ describe('PoX-4 - Delegate aggregation increase operations', () => { }); test('Import testing accounts to bitcoind', async () => { - // register delegate accounts to bitcoind wallet - // TODO: only one of these (delegatee ?) should be required.. - for (const account of [delegatorAccount, delegateeAccount]) { - await testEnv.bitcoinRpcClient.importprivkey({ - privkey: account.wif, - label: account.btcAddr, - rescan: false, - }); - } + // register delegatee account to bitcoind wallet + await testEnv.bitcoinRpcClient.importaddress({ + address: delegateeAccount.btcAddr, + label: delegateeAccount.btcAddr, + rescan: false, + }); }); test('Seed delegate accounts', async () => { @@ -446,4 +443,12 @@ describe('PoX-4 - Delegate aggregation increase operations', () => { expect(BigInt(apiBalance.locked)).toBe(BigInt(BigInt(coreBalanceInfo.locked))); expect(apiBalance.burnchain_unlock_height).toBe(coreBalanceInfo.unlock_height); }); + + test('BTC stacking reward received', async () => { + const received: number = await testEnv.bitcoinRpcClient.getreceivedbyaddress({ + address: delegateeAccount.btcAddr, + minconf: 0, + }); + expect(received).toBeGreaterThan(0); + }); }); diff --git a/src/tests-2.5/pox-4-delegate-revoked-stacking.ts b/src/tests-2.5/pox-4-delegate-revoked-stacking.ts index a25cdf23d6..21af86739c 100644 --- a/src/tests-2.5/pox-4-delegate-revoked-stacking.ts +++ b/src/tests-2.5/pox-4-delegate-revoked-stacking.ts @@ -53,16 +53,6 @@ describe('PoX-4 - Delegate Revoked Stacking', () => { STACKER = accountFromKey(delegateeKey); }); - test('Import testing accounts to bitcoind', async () => { - for (const account of [POOL, STACKER]) { - await testEnv.bitcoinRpcClient.importprivkey({ - privkey: account.wif, - label: account.btcAddr, - rescan: false, - }); - } - }); - test('Seed delegate accounts', async () => { poxInfo = await testEnv.client.getPox(); diff --git a/src/tests-2.5/pox-4-delegate-stacking.ts b/src/tests-2.5/pox-4-delegate-stacking.ts index 46de959d5c..9905f40638 100644 --- a/src/tests-2.5/pox-4-delegate-stacking.ts +++ b/src/tests-2.5/pox-4-delegate-stacking.ts @@ -48,15 +48,12 @@ describe('PoX-4 - Delegate Stacking operations', () => { }); test('Import testing accounts to bitcoind', async () => { - // register delegate accounts to bitcoind wallet - // TODO: only one of these (delegatee ?) should be required.. - for (const account of [delegatorAccount, delegateeAccount]) { - await testEnv.bitcoinRpcClient.importprivkey({ - privkey: account.wif, - label: account.btcAddr, - rescan: false, - }); - } + // register delegatee account to bitcoind wallet + await testEnv.bitcoinRpcClient.importaddress({ + address: delegateeAccount.btcAddr, + label: delegateeAccount.btcAddr, + rescan: false, + }); }); test('Seed delegate accounts', async () => { @@ -449,4 +446,12 @@ describe('PoX-4 - Delegate Stacking operations', () => { expect(BigInt(apiBalance.locked)).toBe(BigInt(BigInt(coreBalanceInfo.locked))); expect(apiBalance.burnchain_unlock_height).toBe(coreBalanceInfo.unlock_height); }); + + test('BTC stacking reward received', async () => { + const received: number = await testEnv.bitcoinRpcClient.getreceivedbyaddress({ + address: delegateeAccount.btcAddr, + minconf: 0, + }); + expect(received).toBeGreaterThan(0); + }); }); diff --git a/stacks-blockchain/docker/Dockerfile b/stacks-blockchain/docker/Dockerfile index cf7dc76d0b..44e6658238 100644 --- a/stacks-blockchain/docker/Dockerfile +++ b/stacks-blockchain/docker/Dockerfile @@ -1,5 +1,5 @@ # Pointed to stacks-blockchain `2.1.0.0.0` git tag -FROM --platform=linux/amd64 hirosystems/stacks-api-e2e:stacks3.0-204ab4c as build +FROM --platform=linux/amd64 hirosystems/stacks-api-e2e:stacks3.0-1d675fd as build FROM --platform=linux/amd64 debian:bookworm