Skip to content

Commit

Permalink
test: added test for scan() and getBalance()
Browse files Browse the repository at this point in the history
Signed-off-by: Anmol Sharma <[email protected]>
  • Loading branch information
theanmolsharma committed Jan 21, 2024
1 parent e472d68 commit c0f8e3a
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ jobs:
command: curl --fail -X GET http://localhost:8094/regtest/api/blocks/tip/height
- name: Run unit tests
run: npm run test
env:
BITCOIN_RPC_USER: alice
BITCOIN_RPC_PASSWORD: password
BITCOIN_RPC_HOST: localhost:18443
- name: Fetch esplora logs
if: always()
run: docker-compose -f "./test/helpers/docker-compose.yaml" logs esplora
Expand Down
134 changes: 134 additions & 0 deletions test/helpers/bitcoin-rpc-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import axios, { AxiosError, AxiosRequestConfig } from 'axios';

export class BitcoinRpcClient {
url: string;
config: AxiosRequestConfig;

constructor() {
const user = process.env.BITCOIN_RPC_USER;
const password = process.env.BITCOIN_RPC_PASSWORD;
const host = process.env.BITCOIN_RPC_HOST;
this.url = `http://${user}:${password}@${host}`;
this.config = {
method: 'POST',
headers: {
'content-type': 'application/json',
},
};
}

async init() {
let loadWallet = false;
try {
await this.createWallet('default');
} catch (e) {
if (
e instanceof AxiosError &&
e.response?.data.error.message.includes(
'Database already exists.',
)
) {
loadWallet = true;
} else {
throw e;
}
}
try {
const result = await this.getWalletInfo();
if (result['walletname'] === 'default') {
loadWallet = false;
}
} catch (e) {
if (
e instanceof AxiosError &&
!e.response?.data.error.message.includes('No wallet is loaded.')
) {
throw e;
}
}
try {
if (loadWallet) {
await this.loadWallet('default');
const address = await this.getNewAddress();
await this.mineToAddress(150, address);
}
} catch (e) {
if (
e instanceof AxiosError &&
!e.response?.data.error.message.includes(
'Unable to obtain an exclusive lock on the database',
)
) {
throw e;
}
}
}

private async request(config: AxiosRequestConfig) {
const response = await axios.request({
...this.config,
...config,
});
return response.data?.result;
}

async createWallet(walletName: string) {
return await this.request({
url: this.url,
data: {
method: 'createwallet',
params: [walletName],
},
});
}

async getWalletInfo() {
return await this.request({
url: this.url,
data: {
method: 'getwalletinfo',
params: [],
},
});
}

async loadWallet(walletName: string) {
return await this.request({
url: this.url,
data: {
method: 'loadwallet',
params: [walletName],
},
});
}

async getNewAddress() {
return await this.request({
url: this.url,
data: {
method: 'getnewaddress',
params: [],
},
});
}

async mineToAddress(numBlocks: number, address: string) {
return await this.request({
url: this.url,
data: {
method: 'generatetoaddress',
params: [numBlocks, address],
},
});
}

async sendToAddress(address: string, amount: number) {
return await this.request({
url: this.url,
data: {
method: 'sendtoaddress',
params: [address, amount],
},
});
}
}
33 changes: 32 additions & 1 deletion test/wallet.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { EsploraClient, Wallet, WalletDB } from '../src/wallet';
import * as fs from 'fs';
import { BitcoinRpcClient } from './helpers/bitcoin-rpc-client';

describe('Wallet', () => {
let wallet: Wallet;
let address: string;
let bitcoinRpcClient: BitcoinRpcClient;

beforeAll(async () => {
const walletDB = new WalletDB({
Expand All @@ -17,6 +20,9 @@ describe('Wallet', () => {
network: 'regtest',
}),
});

bitcoinRpcClient = new BitcoinRpcClient();
await bitcoinRpcClient.init();
});

it('should initialise the wallet', async () => {
Expand All @@ -26,7 +32,7 @@ describe('Wallet', () => {
});

it('should derive first receive address', async () => {
const address = await wallet.deriveReceiveAddress();
address = await wallet.deriveReceiveAddress();
expect(address).toBe('bcrt1qcr8te4kr609gcawutmrza0j4xv80jy8zeqchgx');
});

Expand All @@ -40,6 +46,31 @@ describe('Wallet', () => {
expect(address).toBe('bcrt1q8c6fshw2dlwun7ekn9qwf37cu2rn755ufhry49');
});

it('should rescan all addresses', async () => {
await bitcoinRpcClient.sendToAddress(address, 0.1);
await bitcoinRpcClient.mineToAddress(
3,
await bitcoinRpcClient.getNewAddress(),
);

await wallet.scan();
});

it('should get balance', async () => {
// we have to do this because esplora is not always in sync with the node
let retryCount = 5;
while (retryCount > 0) {
const balance = await wallet.getBalance();
if (balance === 0) {
await new Promise((resolve) => setTimeout(resolve, 1000));
await wallet.scan();
}
retryCount--;
}

expect(await wallet.getBalance()).toBe(10000000);
});

afterAll(async () => {
await wallet.close();
fs.rmSync('./test/wallet', { recursive: true, force: true });
Expand Down

0 comments on commit c0f8e3a

Please sign in to comment.