Skip to content

Commit aa8a412

Browse files
committed
test: add run-close_tx to validate simple-close transaction functionality
1 parent 1db4760 commit aa8a412

2 files changed

Lines changed: 297 additions & 0 deletions

File tree

common/test/Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,13 @@ common/test/run-wireaddr: wire/towire.o wire/fromwire.o
166166

167167
common/test/run-jsonrpc_io: common/json_parse_simple.o
168168

169+
common/test/run-close_tx: \
170+
common/amount.o \
171+
common/close_tx.o \
172+
common/permute_tx.o \
173+
common/psbt_keypath.o \
174+
common/pseudorand.o \
175+
wire/fromwire.o \
176+
wire/towire.o
177+
169178
check-units: $(COMMON_TEST_PROGRAMS:%=unittest/%)

common/test/run-close_tx.c

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
#include "config.h"
2+
#include <assert.h>
3+
#include <bitcoin/chainparams.h>
4+
#include <bitcoin/pubkey.h>
5+
#include <bitcoin/script.h>
6+
#include <bitcoin/tx.h>
7+
#include <common/close_tx.h>
8+
#include <common/setup.h>
9+
#include <common/utils.h>
10+
#include <external/libwally-core/include/wally_script.h>
11+
#include <stdio.h>
12+
13+
static void test_create_simple_close_tx_basic(void)
14+
{
15+
struct bitcoin_tx *tx;
16+
struct bitcoin_outpoint funding_outpoint;
17+
struct amount_sat funding_sats = AMOUNT_SAT(1000000);
18+
struct amount_sat closer_amount = AMOUNT_SAT(600000);
19+
struct amount_sat closee_amount = AMOUNT_SAT(400000);
20+
u32 locktime = 12345;
21+
const u8 *closer_script, *closee_script, *funding_wscript;
22+
23+
/* Create test scripts */
24+
static const u8 closer_script_data[] = {0x00, 0x14, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44};
25+
static const u8 closee_script_data[] = {0x00, 0x14, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
26+
closer_script = tal_dup_arr(tmpctx, u8, closer_script_data, sizeof(closer_script_data), 0);
27+
closee_script = tal_dup_arr(tmpctx, u8, closee_script_data, sizeof(closee_script_data), 0);
28+
29+
/* Create funding script (2-of-2 multisig) */
30+
struct pubkey *pk1 = tal(tmpctx, struct pubkey);
31+
struct pubkey *pk2 = tal(tmpctx, struct pubkey);
32+
assert(pubkey_from_hexstr("034fede2c619f647fe7c01d40ae22e4c285291ca2ffb47937bbfb7d6e8285a081f",
33+
2 * PUBKEY_CMPR_LEN, pk1));
34+
assert(pubkey_from_hexstr("028dfe31019dd61fa04c76ad065410e5d063ac2949c04c14b214c1b363e517452f",
35+
2 * PUBKEY_CMPR_LEN, pk2));
36+
funding_wscript = bitcoin_redeem_2of2(tmpctx, pk1, pk2);
37+
38+
/* Create outpoint */
39+
memset(&funding_outpoint, 0, sizeof(funding_outpoint));
40+
/* Just use a fixed txid for testing */
41+
funding_outpoint.n = 0;
42+
43+
/* Test basic functionality */
44+
tx = create_simple_close_tx(tmpctx, NULL, NULL, closer_script,
45+
closee_script, funding_wscript, &funding_outpoint, funding_sats,
46+
closer_amount, closee_amount, locktime);
47+
48+
assert(tx != NULL);
49+
assert(tx->wtx->num_inputs == 1);
50+
assert(tx->wtx->num_outputs == 2);
51+
assert(tx->wtx->locktime == locktime);
52+
assert(tx->wtx->inputs[0].sequence == 0xFFFFFFFD); /* RBF */
53+
54+
/* Check outputs (BIP69 order: smallest sats first). */
55+
assert(tx->wtx->outputs[0].satoshi == closee_amount.satoshis);
56+
assert(tx->wtx->outputs[1].satoshi == closer_amount.satoshis);
57+
58+
tal_free(tx);
59+
}
60+
61+
static void test_create_simple_close_tx_omitted_closer_output(void)
62+
{
63+
struct bitcoin_tx *tx;
64+
struct bitcoin_outpoint funding_outpoint;
65+
struct amount_sat funding_sats = AMOUNT_SAT(1000000);
66+
struct amount_sat closer_amount = AMOUNT_SAT(600000);
67+
struct amount_sat closee_amount = AMOUNT_SAT(400000);
68+
u32 locktime = 12345;
69+
const u8 *closee_script, *funding_wscript;
70+
71+
/* Create test scripts - closer_script is NULL */
72+
static const u8 closee_script_data[] = {0x00, 0x14, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
73+
closee_script = tal_dup_arr(tmpctx, u8, closee_script_data, sizeof(closee_script_data), 0);
74+
75+
/* Create funding script (2-of-2 multisig) */
76+
struct pubkey *pk1 = tal(tmpctx, struct pubkey);
77+
struct pubkey *pk2 = tal(tmpctx, struct pubkey);
78+
assert(pubkey_from_hexstr("034fede2c619f647fe7c01d40ae22e4c285291ca2ffb47937bbfb7d6e8285a081f",
79+
2 * PUBKEY_CMPR_LEN, pk1));
80+
assert(pubkey_from_hexstr("028dfe31019dd61fa04c76ad065410e5d063ac2949c04c14b214c1b363e517452f",
81+
2 * PUBKEY_CMPR_LEN, pk2));
82+
funding_wscript = bitcoin_redeem_2of2(tmpctx, pk1, pk2);
83+
84+
/* Create outpoint */
85+
memset(&funding_outpoint, 0, sizeof(funding_outpoint));
86+
funding_outpoint.n = 0;
87+
88+
/* Test omitted closer output */
89+
tx = create_simple_close_tx(tmpctx, NULL, NULL, NULL, closee_script,
90+
funding_wscript, &funding_outpoint, funding_sats, closer_amount,
91+
closee_amount, locktime);
92+
93+
assert(tx != NULL);
94+
assert(tx->wtx->num_inputs == 1);
95+
assert(tx->wtx->num_outputs == 1); /* Only closee output */
96+
assert(tx->wtx->locktime == locktime);
97+
assert(tx->wtx->inputs[0].sequence == 0xFFFFFFFD); /* RBF */
98+
99+
/* Check output */
100+
assert(tx->wtx->outputs[0].satoshi == closee_amount.satoshis);
101+
102+
tal_free(tx);
103+
}
104+
105+
static void test_create_simple_close_tx_omitted_closee_output(void)
106+
{
107+
struct bitcoin_tx *tx;
108+
struct bitcoin_outpoint funding_outpoint;
109+
struct amount_sat funding_sats = AMOUNT_SAT(1000000);
110+
struct amount_sat closer_amount = AMOUNT_SAT(600000);
111+
struct amount_sat closee_amount = AMOUNT_SAT(400000);
112+
u32 locktime = 12345;
113+
const u8 *closer_script, *funding_wscript;
114+
115+
/* Create test scripts - closee_script is NULL */
116+
static const u8 closer_script_data[] = {0x00, 0x14, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44};
117+
closer_script = tal_dup_arr(tmpctx, u8, closer_script_data, sizeof(closer_script_data), 0);
118+
119+
/* Create funding script (2-of-2 multisig) */
120+
struct pubkey *pk1 = tal(tmpctx, struct pubkey);
121+
struct pubkey *pk2 = tal(tmpctx, struct pubkey);
122+
assert(pubkey_from_hexstr("034fede2c619f647fe7c01d40ae22e4c285291ca2ffb47937bbfb7d6e8285a081f",
123+
2 * PUBKEY_CMPR_LEN, pk1));
124+
assert(pubkey_from_hexstr("028dfe31019dd61fa04c76ad065410e5d063ac2949c04c14b214c1b363e517452f",
125+
2 * PUBKEY_CMPR_LEN, pk2));
126+
funding_wscript = bitcoin_redeem_2of2(tmpctx, pk1, pk2);
127+
128+
/* Create outpoint */
129+
memset(&funding_outpoint, 0, sizeof(funding_outpoint));
130+
funding_outpoint.n = 0;
131+
132+
/* Test omitted closee output */
133+
tx = create_simple_close_tx(tmpctx, NULL, NULL, closer_script, NULL,
134+
funding_wscript, &funding_outpoint, funding_sats, closer_amount,
135+
closee_amount, locktime);
136+
137+
assert(tx != NULL);
138+
assert(tx->wtx->num_inputs == 1);
139+
assert(tx->wtx->num_outputs == 1); /* Only closer output */
140+
assert(tx->wtx->locktime == locktime);
141+
assert(tx->wtx->inputs[0].sequence == 0xFFFFFFFD); /* RBF */
142+
143+
/* Check output */
144+
assert(tx->wtx->outputs[0].satoshi == closer_amount.satoshis);
145+
146+
tal_free(tx);
147+
}
148+
149+
static void test_create_simple_close_tx_op_return_closer(void)
150+
{
151+
struct bitcoin_tx *tx;
152+
struct bitcoin_outpoint funding_outpoint;
153+
struct amount_sat funding_sats = AMOUNT_SAT(1000000);
154+
struct amount_sat closer_amount = AMOUNT_SAT(600000);
155+
struct amount_sat closee_amount = AMOUNT_SAT(400000);
156+
u32 locktime = 12345;
157+
const u8 *closer_script, *closee_script, *funding_wscript;
158+
159+
/* Create OP_RETURN script for closer */
160+
static const u8 closer_script_data[] = {OP_RETURN, 0x04, 't', 'e', 's', 't'};
161+
static const u8 closee_script_data[] = {0x00, 0x14, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
162+
closer_script = tal_dup_arr(tmpctx, u8, closer_script_data, sizeof(closer_script_data), 0);
163+
closee_script = tal_dup_arr(tmpctx, u8, closee_script_data, sizeof(closee_script_data), 0);
164+
165+
/* Create funding script (2-of-2 multisig) */
166+
struct pubkey *pk1 = tal(tmpctx, struct pubkey);
167+
struct pubkey *pk2 = tal(tmpctx, struct pubkey);
168+
assert(pubkey_from_hexstr("034fede2c619f647fe7c01d40ae22e4c285291ca2ffb47937bbfb7d6e8285a081f",
169+
2 * PUBKEY_CMPR_LEN, pk1));
170+
assert(pubkey_from_hexstr("028dfe31019dd61fa04c76ad065410e5d063ac2949c04c14b214c1b363e517452f",
171+
2 * PUBKEY_CMPR_LEN, pk2));
172+
funding_wscript = bitcoin_redeem_2of2(tmpctx, pk1, pk2);
173+
174+
/* Create outpoint */
175+
memset(&funding_outpoint, 0, sizeof(funding_outpoint));
176+
funding_outpoint.n = 0;
177+
178+
/* Test OP_RETURN closer output - should have zero amount */
179+
tx = create_simple_close_tx(tmpctx, NULL, NULL, closer_script,
180+
closee_script, funding_wscript, &funding_outpoint, funding_sats,
181+
closer_amount, closee_amount, locktime);
182+
183+
assert(tx != NULL);
184+
assert(tx->wtx->num_inputs == 1);
185+
assert(tx->wtx->num_outputs == 2);
186+
assert(tx->wtx->locktime == locktime);
187+
assert(tx->wtx->inputs[0].sequence == 0xFFFFFFFD); /* RBF */
188+
189+
/* Check outputs - closer should be zero due to OP_RETURN */
190+
assert(tx->wtx->outputs[0].satoshi == 0);
191+
assert(tx->wtx->outputs[1].satoshi == closee_amount.satoshis);
192+
193+
tal_free(tx);
194+
}
195+
196+
static void test_create_simple_close_tx_op_return_closee(void)
197+
{
198+
struct bitcoin_tx *tx;
199+
struct bitcoin_outpoint funding_outpoint;
200+
struct amount_sat funding_sats = AMOUNT_SAT(1000000);
201+
struct amount_sat closer_amount = AMOUNT_SAT(600000);
202+
struct amount_sat closee_amount = AMOUNT_SAT(400000);
203+
u32 locktime = 12345;
204+
const u8 *closer_script, *closee_script, *funding_wscript;
205+
206+
/* Create OP_RETURN script for closee */
207+
static const u8 closer_script_data[] = {0x00, 0x14, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44};
208+
static const u8 closee_script_data[] = {OP_RETURN, 0x04, 't', 'e', 's', 't'};
209+
closer_script = tal_dup_arr(tmpctx, u8, closer_script_data, sizeof(closer_script_data), 0);
210+
closee_script = tal_dup_arr(tmpctx, u8, closee_script_data, sizeof(closee_script_data), 0);
211+
212+
/* Create funding script (2-of-2 multisig) */
213+
struct pubkey *pk1 = tal(tmpctx, struct pubkey);
214+
struct pubkey *pk2 = tal(tmpctx, struct pubkey);
215+
assert(pubkey_from_hexstr("034fede2c619f647fe7c01d40ae22e4c285291ca2ffb47937bbfb7d6e8285a081f",
216+
2 * PUBKEY_CMPR_LEN, pk1));
217+
assert(pubkey_from_hexstr("028dfe31019dd61fa04c76ad065410e5d063ac2949c04c14b214c1b363e517452f",
218+
2 * PUBKEY_CMPR_LEN, pk2));
219+
funding_wscript = bitcoin_redeem_2of2(tmpctx, pk1, pk2);
220+
221+
/* Create outpoint */
222+
memset(&funding_outpoint, 0, sizeof(funding_outpoint));
223+
funding_outpoint.n = 0;
224+
225+
/* Test OP_RETURN closee output - should have zero amount */
226+
tx = create_simple_close_tx(tmpctx, NULL, NULL, closer_script,
227+
closee_script, funding_wscript, &funding_outpoint, funding_sats,
228+
closer_amount, closee_amount, locktime);
229+
230+
assert(tx != NULL);
231+
assert(tx->wtx->num_inputs == 1);
232+
assert(tx->wtx->num_outputs == 2);
233+
assert(tx->wtx->locktime == locktime);
234+
assert(tx->wtx->inputs[0].sequence == 0xFFFFFFFD); /* RBF */
235+
236+
/* Check outputs - closee should be zero due to OP_RETURN */
237+
assert(tx->wtx->outputs[0].satoshi == 0);
238+
assert(tx->wtx->outputs[1].satoshi == closer_amount.satoshis);
239+
240+
tal_free(tx);
241+
}
242+
243+
static void test_create_simple_close_tx_both_outputs_omitted(void)
244+
{
245+
struct bitcoin_tx *tx;
246+
struct bitcoin_outpoint funding_outpoint;
247+
struct amount_sat funding_sats = AMOUNT_SAT(1000000);
248+
struct amount_sat closer_amount = AMOUNT_SAT(600000);
249+
struct amount_sat closee_amount = AMOUNT_SAT(400000);
250+
u32 locktime = 12345;
251+
const u8 *funding_wscript;
252+
253+
/* Create funding script (2-of-2 multisig) */
254+
struct pubkey *pk1 = tal(tmpctx, struct pubkey);
255+
struct pubkey *pk2 = tal(tmpctx, struct pubkey);
256+
assert(pubkey_from_hexstr("034fede2c619f647fe7c01d40ae22e4c285291ca2ffb47937bbfb7d6e8285a081f",
257+
2 * PUBKEY_CMPR_LEN, pk1));
258+
assert(pubkey_from_hexstr("028dfe31019dd61fa04c76ad065410e5d063ac2949c04c14b214c1b363e517452f",
259+
2 * PUBKEY_CMPR_LEN, pk2));
260+
funding_wscript = bitcoin_redeem_2of2(tmpctx, pk1, pk2);
261+
262+
/* Create outpoint */
263+
memset(&funding_outpoint, 0, sizeof(funding_outpoint));
264+
funding_outpoint.n = 0;
265+
266+
/* Test both outputs omitted - should return NULL */
267+
tx = create_simple_close_tx(tmpctx, NULL, NULL, NULL, NULL,
268+
funding_wscript, &funding_outpoint, funding_sats, closer_amount,
269+
closee_amount, locktime);
270+
271+
assert(tx == NULL); /* Should fail with no outputs */
272+
}
273+
274+
int main(int argc, char *argv[])
275+
{
276+
common_setup(argv[0]);
277+
chainparams = chainparams_for_network("bitcoin");
278+
279+
test_create_simple_close_tx_basic();
280+
test_create_simple_close_tx_omitted_closer_output();
281+
test_create_simple_close_tx_omitted_closee_output();
282+
test_create_simple_close_tx_op_return_closer();
283+
test_create_simple_close_tx_op_return_closee();
284+
test_create_simple_close_tx_both_outputs_omitted();
285+
286+
common_shutdown();
287+
return 0;
288+
}

0 commit comments

Comments
 (0)