Skip to content

Commit

Permalink
tx: add get_witness_num_items to get the number of witness items in a…
Browse files Browse the repository at this point in the history
…n input

Wrapped languages currently have to iterate until an error is thrown to
retrieve the witness. Provide the number of items so they can avoid this.

Fixes wally_tx_input_get_witness not setting the output length to zero
if a NULL buffer was passed.

Also adds tests for fetching input witness data.
  • Loading branch information
jgriffiths committed Dec 21, 2023
1 parent 72e23d3 commit 50a4882
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

- PSBT: Allow extracting partially finalized transactions in `wally_psbt_extract`
by passing a new `WALLY_PSBT_EXTRACT_OPT_FINAL` flag.
- Allow getting the number of items in a transactions input witness via
`wally_tx_input_get_witness_num_items`/`wally_tx_get_input_witness_num_items`.

### Changed

### Fixed

- tx_input_get_witness now correctly returns 0 bytes written if passed a NULL input.


## Version 1.0.0

Expand Down
2 changes: 2 additions & 0 deletions include/wally_transaction_members.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ WALLY_CORE_API int wally_tx_input_get_txhash(const struct wally_tx_input *tx_inp

WALLY_CORE_API int wally_tx_input_get_script(const struct wally_tx_input *tx_input_in, unsigned char *bytes_out, size_t len, size_t *written);
WALLY_CORE_API int wally_tx_input_get_script_len(const struct wally_tx_input *tx_input_in, size_t *written);
WALLY_CORE_API int wally_tx_input_get_witness_num_items(const struct wally_tx_input *tx_input_in, size_t *written);
WALLY_CORE_API int wally_tx_input_get_witness(const struct wally_tx_input *tx_input_in, size_t index, unsigned char *bytes_out, size_t len, size_t *written);
WALLY_CORE_API int wally_tx_input_get_witness_len(const struct wally_tx_input *tx_input_in, size_t index, size_t *written);
WALLY_CORE_API int wally_tx_input_get_index(const struct wally_tx_input *tx_input_in, size_t *written);
Expand Down Expand Up @@ -98,6 +99,7 @@ WALLY_CORE_API int wally_tx_get_input_txhash(const struct wally_tx *tx_in, size_

WALLY_CORE_API int wally_tx_get_input_script(const struct wally_tx *tx_in, size_t index, unsigned char *bytes_out, size_t len, size_t *written);
WALLY_CORE_API int wally_tx_get_input_script_len(const struct wally_tx *tx_in, size_t index, size_t *written);
WALLY_CORE_API int wally_tx_get_input_witness_num_items(const struct wally_tx *tx_in, size_t index, size_t *written);
WALLY_CORE_API int wally_tx_get_input_witness(const struct wally_tx *tx_in, size_t index, size_t wit_index, unsigned char *bytes_out, size_t len, size_t *written);
WALLY_CORE_API int wally_tx_get_input_witness_len(const struct wally_tx *tx_in, size_t index, size_t wit_index, size_t *written);
WALLY_CORE_API int wally_tx_get_input_index(const struct wally_tx *tx_in, size_t index, size_t *written);
Expand Down
2 changes: 2 additions & 0 deletions src/swig_java/swig.i
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,7 @@ static jobjectArray create_jstringArray(JNIEnv *jenv, char **p, size_t len) {
%rename("_tx_get_input_sequence") wally_tx_get_input_sequence;
%returns_size_t(_tx_get_input_sequence);
%returns_array_(wally_tx_get_input_txhash, 3, 4, SHA256_LEN);
%returns_size_t(wally_tx_get_input_witness_num_items);
%rename("_tx_get_input_witness") wally_tx_get_input_witness;
%returns_size_t(_tx_get_input_witness);
%returns_size_t(wally_tx_get_input_witness_len);
Expand Down Expand Up @@ -1074,6 +1075,7 @@ static jobjectArray create_jstringArray(JNIEnv *jenv, char **p, size_t len) {
%returns_array_(wally_tx_input_get_txhash, 2, 3, WALLY_TXHASH_LEN);
%rename("_tx_input_get_witness") wally_tx_input_get_witness;
%returns_size_t(_tx_input_get_witness);
%returns_size_t(wally_tx_input_get_witness_num_items);
%returns_size_t(wally_tx_input_get_witness_len);
%returns_struct(wally_tx_input_init_alloc, wally_tx_input);
%rename("tx_input_init") wally_tx_input_init_alloc;
Expand Down
26 changes: 24 additions & 2 deletions src/test/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def test_serialization(self):
utf8('ff')+TX_FAKE_HEX[2:],
TX_FAKE_HEX,
TX_WITNESS_HEX ]:
self.assertEqual(WALLY_OK, wally_tx_from_hex(tx_hex, 0 ,tx_out))
self.assertEqual(WALLY_OK, wally_tx_from_hex(tx_hex, 0, tx_out))
hex_ = utf8(self.tx_serialize_hex(tx_out))
self.assertEqual(tx_hex, hex_)
# Check the transaction can be cloned and serializes to the same hex
Expand Down Expand Up @@ -216,7 +216,6 @@ def remove_and_test(idx):
2, 0xfffffffd, script, script_len, wit, 0)
self.assertEqual(ret, WALLY_EINVAL) # Invalid index


def test_witness(self):
"""Testing functions manipulating witness stacks"""
witness = wally_tx_witness_stack()
Expand Down Expand Up @@ -256,6 +255,29 @@ def test_witness(self):
]:
self.assertEqual((WALLY_EINVAL, 0), wally_tx_witness_stack_to_bytes(*args))

# Witness functions on inputs
out, out_len = make_cbuffer('00' * 128)
tx = pointer(wally_tx())
self.assertEqual(WALLY_OK, wally_tx_from_hex(TX_WITNESS_HEX, 0, tx))
for wit_tx, wit_index, expected_len in [
(None, 0, 0), # NULL tx
(tx, 1, 0), # Invalid input index
(tx, 0, 4), # Valid input index
]:
# num items
ret, num_items = wally_tx_get_input_witness_num_items(wit_tx, wit_index)
self.assertEqual(ret, WALLY_OK if expected_len else WALLY_EINVAL)
self.assertEqual(num_items, expected_len)
item_index = expected_len - 1 if expected_len else 0
# item length
ret, item_len = wally_tx_get_input_witness_len(wit_tx, wit_index, item_index)
self.assertEqual(ret, WALLY_OK if expected_len else WALLY_EINVAL)
self.assertTrue(ret == WALLY_EINVAL or item_len > 0)
# item
ret, item_len = wally_tx_get_input_witness(wit_tx, wit_index, item_index, out, out_len)
self.assertEqual(ret, WALLY_OK if expected_len else WALLY_EINVAL)
self.assertTrue(ret == WALLY_EINVAL or item_len > 0)

# Round-trip serialization
def check_witness_to_bytes(w, expected, expected_len):
out, out_len = make_cbuffer('00' * 64)
Expand Down
2 changes: 2 additions & 0 deletions src/test/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,7 @@ class wally_psbt(Structure):
('wally_tx_get_input_txhash', c_int, [POINTER(wally_tx), c_size_t, c_void_p, c_size_t]),
('wally_tx_get_input_witness', c_int, [POINTER(wally_tx), c_size_t, c_size_t, c_void_p, c_size_t, c_size_t_p]),
('wally_tx_get_input_witness_len', c_int, [POINTER(wally_tx), c_size_t, c_size_t, c_size_t_p]),
('wally_tx_get_input_witness_num_items', c_int, [POINTER(wally_tx), c_size_t, c_size_t_p]),
('wally_tx_get_locktime', c_int, [POINTER(wally_tx), c_size_t_p]),
('wally_tx_get_num_inputs', c_int, [POINTER(wally_tx), c_size_t_p]),
('wally_tx_get_num_outputs', c_int, [POINTER(wally_tx), c_size_t_p]),
Expand Down Expand Up @@ -985,6 +986,7 @@ class wally_psbt(Structure):
('wally_tx_input_get_txhash', c_int, [POINTER(wally_tx_input), c_void_p, c_size_t]),
('wally_tx_input_get_witness', c_int, [POINTER(wally_tx_input), c_size_t, c_void_p, c_size_t, c_size_t_p]),
('wally_tx_input_get_witness_len', c_int, [POINTER(wally_tx_input), c_size_t, c_size_t_p]),
('wally_tx_input_get_witness_num_items', c_int, [POINTER(wally_tx_input), c_size_t_p]),
('wally_tx_input_set_blinding_nonce', c_int, [POINTER(wally_tx_input), c_void_p, c_size_t]),
('wally_tx_input_set_entropy', c_int, [POINTER(wally_tx_input), c_void_p, c_size_t]),
('wally_tx_input_set_index', c_int, [POINTER(wally_tx_input), c_uint32]),
Expand Down
26 changes: 20 additions & 6 deletions src/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -3547,6 +3547,16 @@ static int tx_getb_impl(const void *input,
GET_TX_B_FIXED(tx_input, txhash, WALLY_TXHASH_LEN, WALLY_TXHASH_LEN)
GET_TX_B(tx_input, script, input->script_len)

int wally_tx_input_get_witness_num_items(const struct wally_tx_input *input, size_t *written)
{
if (written)
*written = 0;
if (!is_valid_tx_input(input) || !written)
return WALLY_EINVAL;
*written = input->witness ? input->witness->num_items : 0;
return WALLY_OK;
}

static const struct wally_tx_witness_item *get_witness_preamble(
const struct wally_tx_input *input, size_t index, size_t *written)
{
Expand All @@ -3563,7 +3573,7 @@ int wally_tx_input_get_witness(const struct wally_tx_input *input, size_t index,
unsigned char *bytes_out, size_t len, size_t *written)
{
const struct wally_tx_witness_item *item;
if (!bytes_out || !(item = get_witness_preamble(input, index, written)) ||
if (!(item = get_witness_preamble(input, index, written)) || !bytes_out ||
len < item->witness_len)
return WALLY_EINVAL;
if (item->witness_len)
Expand All @@ -3572,10 +3582,6 @@ int wally_tx_input_get_witness(const struct wally_tx_input *input, size_t index,
return WALLY_OK;
}

GET_TX_I(tx_input, index, size_t)
GET_TX_I(tx_input, sequence, size_t)
GET_TX_I(tx_input, script_len, size_t)

int wally_tx_input_get_witness_len(const struct wally_tx_input *input,
size_t index, size_t *written)
{
Expand All @@ -3586,6 +3592,10 @@ int wally_tx_input_get_witness_len(const struct wally_tx_input *input,
return WALLY_OK;
}

GET_TX_I(tx_input, index, size_t)
GET_TX_I(tx_input, sequence, size_t)
GET_TX_I(tx_input, script_len, size_t)

#ifndef WALLY_ABI_NO_ELEMENTS
GET_TX_B_FIXED(tx_input, blinding_nonce, SHA256_LEN, SHA256_LEN)
GET_TX_B_FIXED(tx_input, entropy, SHA256_LEN, SHA256_LEN)
Expand Down Expand Up @@ -3801,6 +3811,11 @@ TX_GET_B_FIXED(input, txhash)
TX_GET_I(input, index)
TX_GET_I(input, sequence)

int wally_tx_get_input_witness_num_items(const struct wally_tx *tx, size_t index, size_t *written)
{
return wally_tx_input_get_witness_num_items(tx_get_input(tx, index), written);
}

int wally_tx_get_input_witness(const struct wally_tx *tx, size_t index, size_t wit_index, unsigned char *bytes_out, size_t len, size_t *written)
{
return wally_tx_input_get_witness(tx_get_input(tx, index), wit_index, bytes_out, len, written);
Expand Down Expand Up @@ -3910,7 +3925,6 @@ int wally_tx_set_input_witness(const struct wally_tx *tx, size_t index,
return wally_tx_input_set_witness(tx_get_input(tx, index), stack);
}


int wally_tx_input_set_script(struct wally_tx_input *input,
const unsigned char *script, size_t script_len)
{
Expand Down
2 changes: 2 additions & 0 deletions src/wasm_package/src/functions.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/wasm_package/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ export function tx_get_input_script_len(tx_in: Ref_wally_tx, index: number): num
export function tx_get_input_sequence(tx_in: Ref_wally_tx, index: number): number;
export function tx_get_input_txhash(tx_in: Ref_wally_tx, index: number): Buffer;
export function tx_get_input_witness_len(tx_in: Ref_wally_tx, index: number, wit_index: number): number;
export function tx_get_input_witness_num_items(tx_in: Ref_wally_tx, index: number): number;
export function tx_get_length(tx: Ref_wally_tx, flags: number): number;
export function tx_get_locktime(tx_in: Ref_wally_tx): number;
export function tx_get_num_inputs(tx_in: Ref_wally_tx): number;
Expand Down Expand Up @@ -648,6 +649,7 @@ export function tx_input_get_script_len(tx_input_in: Ref_wally_tx_input): number
export function tx_input_get_sequence(tx_input_in: Ref_wally_tx_input): number;
export function tx_input_get_txhash(tx_input_in: Ref_wally_tx_input): Buffer;
export function tx_input_get_witness_len(tx_input_in: Ref_wally_tx_input, index: number): number;
export function tx_input_get_witness_num_items(tx_input_in: Ref_wally_tx_input): number;
export function tx_input_init(txhash: Buffer|Uint8Array, utxo_index: number, sequence: number, script: Buffer|Uint8Array, witness: Ref_wally_tx_witness_stack): Ref_wally_tx_input;
export function tx_input_set_blinding_nonce(tx_input_in: Ref_wally_tx_input, blinding_nonce: Buffer|Uint8Array): void;
export function tx_input_set_entropy(tx_input_in: Ref_wally_tx_input, entropy: Buffer|Uint8Array): void;
Expand Down
2 changes: 2 additions & 0 deletions tools/wasm_exports.sh
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ EXPORTED_FUNCTIONS="['_malloc','_free','_bip32_key_free' \
,'_wally_tx_get_input_txhash' \
,'_wally_tx_get_input_witness' \
,'_wally_tx_get_input_witness_len' \
,'_wally_tx_get_input_witness_num_items' \
,'_wally_tx_get_length' \
,'_wally_tx_get_locktime' \
,'_wally_tx_get_num_inputs' \
Expand All @@ -417,6 +418,7 @@ EXPORTED_FUNCTIONS="['_malloc','_free','_bip32_key_free' \
,'_wally_tx_input_get_txhash' \
,'_wally_tx_input_get_witness' \
,'_wally_tx_input_get_witness_len' \
,'_wally_tx_input_get_witness_num_items' \
,'_wally_tx_input_init_alloc' \
,'_wally_tx_input_set_index' \
,'_wally_tx_input_set_script' \
Expand Down

0 comments on commit 50a4882

Please sign in to comment.