Skip to content

Commit 67b66d2

Browse files
committed
test: add run-close_tx to validate simple-close transaction functionality
1 parent 467b478 commit 67b66d2

2 files changed

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

0 commit comments

Comments
 (0)