Skip to content

Commit c77b8a6

Browse files
author
Hack.bg R&D
committed
fix(test): troubleshoot sendSigned
1 parent 036ec2f commit c77b8a6

File tree

3 files changed

+57
-26
lines changed

3 files changed

+57
-26
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ The tests run on an automatically managed ephemeral Elements localnet in `elemen
259259
* `bad-txns-in-ne-out` when inputs/outputs do seem to add up
260260
* -> `VerifyAmounts` in Elements `confidential_validation.cpp` -> oh my...
261261
* Use `rpc.listunspent(0, 9999999, [sender])` to get a valid UTXO
262-
* `min-relay-fee` -> ?
262+
* Make sure not to mess up the decimals. **Pass satoshis as String and BigInt, Bitcoins as Number**
263+
* `min-relay-fee` -> ? the fee output is misconfigured
263264

264265
## Acknowledgments, References, Attribution
265266

src/sdk.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type Bitcoin from '../../Bitcoin/Bitcoin.ts';
1+
import type Bitcoin from '../../Bitcoin/index.ts';
22
import Fn from '../../../library/Fn.ts';
33
import { Log } from '../../../library/Log.ts';
44
import { Num, Base16 } from '../../../library/Number.ts';
@@ -65,7 +65,7 @@ export async function Wasm ({
6565
}
6666

6767
/** Load [Wasm] with default settings and create a [WasmKeypair]. */
68-
export async function Keypair (secret: Uint8Array): Promise<Keypair> {
68+
export async function Keypair (secret: Uint8Array) {
6969
const { keypair } = await Wasm();
7070
return keypair(secret)
7171
}
@@ -143,7 +143,9 @@ export async function Program (source: string, {
143143
}
144144

145145
/** Format a `{ type, value }` pair as used to pass `param` and `witness` values. */
146-
export function Arg (type: string, value?: unknown) { return { type, value } }
146+
export function Arg (type: string, value?: unknown) {
147+
return { type, value }
148+
}
147149

148150
/** SimplicityHL program argument constructors.
149151
*

src/test.ts

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#!/usr/bin/env -S deno run --allow-read --allow-env --allow-run --allow-write=/tmp/fadroma --allow-import=cdn.skypack.dev:443,deno.land:443 --allow-net=127.0.0.1:8941,liquidtestnet.com:443,blockstream.info:443
22
import { deepStrictEqual as equal, rejects, throws, ok } from 'node:assert';
33
import { Base16, Fn, Test, Run, sleep } from '../../../library/index.ts';
4-
import { pubECDSA } from 'npm:@scure/btc-signer/utils.js';
5-
import Btc, { BtcRpc, Esplora, LiquidTestnet, ElementsRegtest } from '../../Bitcoin/index.ts';
4+
import Btc, { BtcRpc, LiquidTestnet, ElementsRegtest } from '../../Bitcoin/index.ts';
65
import { SendFromWallet, AssertBalance } from '../../Bitcoin/test.ts';
7-
import { Signer, Keypair, Program, Wasm, Arg, Args } from './sdk.ts';
6+
import { Signer, Program, Wasm, Arg, Args } from './sdk.ts';
87
const { is, has } = Test;
98
const { CreateWallet, Rescan } = BtcRpc;
109
const { INITIAL_COINS, BITCOIN } = ElementsRegtest;
@@ -48,7 +47,7 @@ export function TestOnLocalnet () {
4847
const BALANCE_INITIAL = { [ElementsRegtest.ASSETS.REISSUE]: 1, bitcoin: Number(INITIAL_COINS / BITCOIN) };
4948
// Tests that run on temporary localnet:
5049
return Test('elementsregtest',
51-
() => ElementsRegtest({ debugs: true, debugexclude: ['libevent'] }),
50+
() => ElementsRegtest({ debugs: false, debugexclude: ['libevent'] }),
5251
Run.Verbose(true), // Pipe the localnet's output to stderr
5352
CreateWallet('test-simf', AssertBalance(BALANCE_EMPTY)),
5453
Rescan(AssertBalance(BALANCE_INITIAL)),
@@ -107,8 +106,6 @@ export function TestOnLocalnet () {
107106
interface TestSend extends Btc {
108107
/** Chain-specific asset IDs. */
109108
ASSETS: { [key: string]: unknown },
110-
/** Input transaction. */
111-
tx: unknown
112109
/** To provide funds on testnet. */
113110
callFaucet?: Fn.Returns<Fn.Async<{ txid: string }>>,
114111
/** Creates a P2WPKH address configured for the given network. */
@@ -119,28 +116,59 @@ interface TestSend extends Btc {
119116
recipient: string
120117
}
121118

122-
function TestSend (signer1 = null, signer2 = null, amount = 3000n, fee = 12000n) {
119+
function TestSend (amount = 3000n, fee = 12000n) {
123120
const keypair1 = keypair(new Uint8Array(Array(32).fill(8)));
124121
const keypair2 = keypair(new Uint8Array(Array(32).fill(9)));
125-
return Fn.Name('Test sendSigned', testSend);
122+
return Fn.Name(`Test sendSigned ${amount} for ${fee}`, testSend);
126123
async function testSend ({ debug = console.debug, ...context }: TestSend) {
127-
const { rpc, rest, esplora, callFaucet, tx: inputTx, ASSETS, P2WPKH } = context;
128-
const sender = P2WPKH(keypair1.publicKey()).address;
124+
const { rpc, rest, esplora, callFaucet, ASSETS, P2WPKH } = context;
125+
const sender = P2WPKH(keypair1.publicKey()).address;
129126
const recipient = P2WPKH(keypair2.publicKey()).address;
130127
debug(`Send ${amount} from ${sender} to ${recipient} at ${fee}`);
131-
const unspent = await rpc.listunspent(0, 9999999, [sender]); // TODO filter
132-
const utxo = unspent[0]; // { asset, txid, vout, value, address }
128+
const utxo = await findUtxo(sender);
133129
debug('Input:', utxo);
134-
const options = { sender, recipient, asset: utxo.asset, amount, fee, utxos: [utxo] };
135-
const signed = sendSigned(keypair1, options);
136-
debug('Signed:', signed);
137-
try {
138-
const id = await rpc!.sendrawtransaction(signed.hex);
139-
const tx = await rest!.tx(id);
140-
await rpc!.rescanblockchain();
141-
} catch (e) {
142-
await sleep(1000);
143-
throw e
130+
const options = { recipient, sender, utxos: [utxo], asset: utxo.asset, amount, fee };
131+
const signed = sendSigned(keypair1, options);
132+
const tx = await sendSignedTransaction(signed.hex);
133+
console.log({tx});
134+
135+
async function sendSignedTransaction (hex: string) {
136+
debug('Broadcasting signed transaction:', signed);
137+
if (rpc && rest) {
138+
const id = await rpc!.sendrawtransaction(hex);
139+
await rpc!.rescanblockchain();
140+
const tx = await rest!.tx(id);
141+
return tx;
142+
} else if (esplora) {
143+
const id = await esplora.postTx(hex);
144+
while (true) {
145+
const mempool = await esplora.getMempoolTxids().then(JSON.parse);
146+
if (mempool.includes(id)) {
147+
debug('TX still in mempool:', id);
148+
await sleep(1000);
149+
} else {
150+
return esplora.getTxInfo(id);
151+
}
152+
}
153+
} else {
154+
throw new Error('need { rpc, rest } or { esplora } to broadcast signed transaction');
155+
}
156+
}
157+
158+
async function findUtxo (address: string): { asset, txid, vout, amount, address } {
159+
if (rpc) {
160+
const unspent = await rpc.listunspent(0, 9999999, [sender]); // TODO filter
161+
if (!unspent[0]) throw new Error(`no UTXOs for ${sender}`);
162+
const { txid, vout, amount, asset } = unspent[0];
163+
return { asset, txid, vout, address, amount };
164+
} else if (esplora) {
165+
const unspent = await esplora.getAddressUtxos(sender);
166+
if (!unspent[0]) throw new Error(`no UTXOs for ${sender}`)
167+
const { txid, vout, value, asset } = unspent[0];
168+
return { asset, txid, vout, address, amount: BigInt(value) };
169+
} else {
170+
throw new Error('need { rpc } or { esplora } to find unspent output');
171+
}
144172
}
145173
}
146174
}

0 commit comments

Comments
 (0)