diff --git a/README.md b/README.md index 8479005c0..0855aba61 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ installed. For non-development use, you can install wally with `pip` as follows: ``` -pip install wallycore==0.9.1 +pip install wallycore==0.9.2 ``` For python development, you can build and install wally using: @@ -132,7 +132,7 @@ You can also install the binary [wally releases](https://github.com/ElementsProj using the released wheel files without having to compile the library, e.g.: ``` -pip install wallycore-0.9.1-cp39-cp39m-linux_x86_64.whl +pip install wallycore-0.9.2-cp39-cp39m-linux_x86_64.whl ``` The script `tools/build_python_manylinux_wheels.sh` builds the Linux release files diff --git a/_CMakeLists.txt b/_CMakeLists.txt index ce0e5c97a..23a4b7f63 100644 --- a/_CMakeLists.txt +++ b/_CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20) project( libwallycore - VERSION 0.9.1 + VERSION 0.9.2 DESCRIPTION "A collection of useful primitives for cryptocurrency wallets" LANGUAGES C ) diff --git a/configure.ac b/configure.ac index 9c3a46048..05e10e868 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.60]) -AC_INIT([libwallycore],[0.9.1]) +AC_INIT([libwallycore],[0.9.2]) AC_CONFIG_AUX_DIR([tools/build-aux]) AC_CONFIG_MACRO_DIR([tools/build-aux/m4]) AC_CONFIG_SRCDIR([src/mnemonic.h]) diff --git a/docs/source/conf.py b/docs/source/conf.py index f36f6b2ee..ee16c4440 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -167,7 +167,7 @@ def extract_docs(infile, outfile): # built documents. # # The short X.Y version. -version = u'0.9.1' +version = u'0.9.2' # The full version, including alpha/beta/rc tags. release = version diff --git a/include/wally.hpp b/include/wally.hpp index 6c3de9fcf..193bf4705 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -1408,6 +1408,12 @@ inline int psbt_is_finalized(const PSBT& psbt, size_t* written) { return ret; } +template +inline int psbt_is_input_finalized(const PSBT& psbt, size_t index, size_t* written) { + int ret = ::wally_psbt_is_input_finalized(detail::get_p(psbt), index, written); + return ret; +} + inline int psbt_output_clear_amount(struct wally_psbt_output* output) { int ret = ::wally_psbt_output_clear_amount(output); return ret; diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 9e6bf2c43..f95a456ed 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -1958,6 +1958,18 @@ WALLY_CORE_API int wally_psbt_is_finalized( const struct wally_psbt *psbt, size_t *written); +/** + * Determine if a given PSBT input is finalized. + * + * :param psbt: The PSBT to check. + * :param index: The zero-based index of the input to check. + * :param written: On success, set to one if the input is finalized, otherwise zero. + */ +WALLY_CORE_API int wally_psbt_is_input_finalized( + const struct wally_psbt *psbt, + size_t index, + size_t *written); + /** * Set the global transaction for a PSBT. * diff --git a/setup.py b/setup.py index a39d8f359..350a5b316 100644 --- a/setup.py +++ b/setup.py @@ -93,7 +93,7 @@ def call(cmd): kwargs = { 'name': 'wallycore', - 'version': '0.9.1', + 'version': '0.9.2', 'description': 'libwally Bitcoin library', 'long_description': 'Python bindings for the libwally Bitcoin library', 'url': 'https://github.com/ElementsProject/libwally-core', @@ -109,11 +109,7 @@ def call(cmd): 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3', ], 'keywords': 'Bitcoin wallet BIP32 BIP38 BIP39 secp256k1', 'project_urls': { diff --git a/src/bip85.c b/src/bip85.c index 2b0ce7522..6ad5cf4fb 100644 --- a/src/bip85.c +++ b/src/bip85.c @@ -3,6 +3,7 @@ #include "ccan/ccan/crypto/sha512/sha512.h" #include #include +#include #include /* Bip85 path element values */ diff --git a/src/internal.h b/src/internal.h index 83cf07a2f..e73d187d3 100644 --- a/src/internal.h +++ b/src/internal.h @@ -120,4 +120,9 @@ const struct wally_map_item *map_find_equal_integer(const struct wally_map *lhs, /* Clamp initial witness stack allocation sizing */ #define MAX_WITNESS_ITEMS_ALLOC 100u /* Non-Taproot standardness limit */ +/* Absolute maximum number of inputs and outputs for BTC. + * Liquid numbers are smaller; we use the upper limit */ +#define TX_MAX_INPUTS (TX_MAX_INPUTS_ALLOC * 10) +#define TX_MAX_OUTPUTS (TX_MAX_OUTPUTS_ALLOC * 10) + #endif /* LIBWALLY_INTERNAL_H */ diff --git a/src/psbt.c b/src/psbt.c index 4f4e98cad..88ee130f4 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1077,9 +1077,10 @@ static int psbt_output_free(struct wally_psbt_output *output, bool free_parent) return WALLY_OK; } -static int wally_psbt_init(uint32_t version, size_t num_inputs, size_t num_outputs, - size_t num_unknowns, uint32_t flags, - struct wally_psbt *psbt_out) +static int psbt_init(uint32_t version, size_t num_inputs, size_t num_outputs, + size_t num_unknowns, uint32_t flags, + size_t max_num_inputs, size_t max_num_outputs, + struct wally_psbt *psbt_out) { int ret; @@ -1087,6 +1088,8 @@ static int wally_psbt_init(uint32_t version, size_t num_inputs, size_t num_outpu wally_clear(psbt_out, sizeof(*psbt_out)); if ((version != PSBT_0 && version != PSBT_2) || !psbt_out) return WALLY_EINVAL; /* Only v0/v2 are specified/supported */ + if (num_inputs > TX_MAX_INPUTS || num_outputs > TX_MAX_OUTPUTS) + return WALLY_EINVAL; /* Resulting tx could not fit in a block */ #ifdef BUILD_ELEMENTS if (flags & ~WALLY_PSBT_INIT_PSET || (flags & WALLY_PSBT_INIT_PSET && version != PSBT_2)) @@ -1097,13 +1100,13 @@ static int wally_psbt_init(uint32_t version, size_t num_inputs, size_t num_outpu #endif /* BUILD_ELEMENTS */ if (num_inputs) { - if (num_inputs > TX_MAX_INPUTS_ALLOC) - num_inputs = TX_MAX_INPUTS_ALLOC; + if (num_inputs > max_num_inputs) + num_inputs = max_num_inputs; psbt_out->inputs = wally_calloc(num_inputs * sizeof(struct wally_psbt_input)); } if (num_outputs) { - if (num_outputs > TX_MAX_OUTPUTS_ALLOC) - num_outputs = TX_MAX_OUTPUTS_ALLOC; + if (num_outputs > max_num_outputs) + num_outputs = max_num_outputs; psbt_out->outputs = wally_calloc(num_outputs * sizeof(struct wally_psbt_output)); } @@ -1142,14 +1145,17 @@ static int wally_psbt_init(uint32_t version, size_t num_inputs, size_t num_outpu return WALLY_OK; } -int wally_psbt_init_alloc(uint32_t version, size_t num_inputs, size_t num_outputs, - size_t num_unknowns, uint32_t flags, struct wally_psbt **output) +static int psbt_init_alloc(uint32_t version, size_t num_inputs, size_t num_outputs, + size_t num_unknowns, uint32_t flags, + size_t max_num_inputs, size_t max_num_outputs, + struct wally_psbt **output) { int ret; OUTPUT_CHECK; OUTPUT_ALLOC(struct wally_psbt); - ret = wally_psbt_init(version, num_inputs, num_outputs, num_unknowns, flags, *output); + ret = psbt_init(version, num_inputs, num_outputs, num_unknowns, flags, + max_num_inputs, max_num_outputs, *output); if (ret != WALLY_OK) { wally_free(*output); *output = NULL; @@ -1157,6 +1163,14 @@ int wally_psbt_init_alloc(uint32_t version, size_t num_inputs, size_t num_output return ret; } +int wally_psbt_init_alloc(uint32_t version, size_t num_inputs, size_t num_outputs, + size_t num_unknowns, uint32_t flags, struct wally_psbt **output) +{ + return psbt_init_alloc(version, num_inputs, num_outputs, num_unknowns, + flags, TX_MAX_INPUTS_ALLOC, TX_MAX_OUTPUTS_ALLOC, + output); +} + int wally_psbt_from_tx(const struct wally_tx *tx, uint32_t version, uint32_t flags, struct wally_psbt **output) { @@ -1167,8 +1181,8 @@ int wally_psbt_from_tx(const struct wally_tx *tx, uint32_t version, *output = NULL; if (!tx || !output || (version == WALLY_PSBT_VERSION_2 && tx->version < 2u)) return WALLY_EINVAL; - ret = wally_psbt_init_alloc(version, tx->num_inputs, tx->num_outputs, 0, - flags, output); + ret = psbt_init_alloc(version, tx->num_inputs, tx->num_outputs, 0, flags, + tx->num_inputs, tx->num_outputs, output); if (ret == WALLY_OK && version == WALLY_PSBT_VERSION_0) ret = wally_psbt_set_global_tx(*output, tx); else { @@ -1399,6 +1413,12 @@ int wally_psbt_is_finalized(const struct wally_psbt *psbt, return WALLY_OK; } +int wally_psbt_is_input_finalized(const struct wally_psbt *psbt, + size_t index, size_t *written) +{ + return wally_psbt_input_is_finalized(psbt_get_input(psbt, index), written); +} + static int psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx, bool do_clone) { struct wally_tx *new_tx = NULL; @@ -2588,7 +2608,8 @@ int wally_psbt_from_bytes(const unsigned char *bytes, size_t len, ret = WALLY_EINVAL; /* Tx version must be >= 2 */ else { struct wally_psbt tmp; - ret = wally_psbt_init((*output)->version, input_count, output_count, 0, 0, &tmp); + ret = psbt_init((*output)->version, input_count, output_count, + 0, 0, input_count, output_count, &tmp); if (ret == WALLY_OK) { /* Steal the allocated input/output arrays */ (*output)->inputs = tmp.inputs; @@ -3967,12 +3988,14 @@ int wally_psbt_clone_alloc(const struct wally_psbt *psbt, uint32_t flags, ret = wally_psbt_is_elements(psbt, &is_pset); if (ret == WALLY_OK) - ret = wally_psbt_init_alloc(psbt->version, - psbt->inputs_allocation_len, - psbt->outputs_allocation_len, - psbt->unknowns.items_allocation_len, - is_pset ? WALLY_PSBT_INIT_PSET : 0, - output); + ret = psbt_init_alloc(psbt->version, + psbt->inputs_allocation_len, + psbt->outputs_allocation_len, + psbt->unknowns.items_allocation_len, + is_pset ? WALLY_PSBT_INIT_PSET : 0, + psbt->inputs_allocation_len, + psbt->outputs_allocation_len, + output); if (ret == WALLY_OK) { (*output)->tx_version = psbt->tx_version; psbt_claim_allocated_inputs(*output, psbt->num_inputs, psbt->num_outputs); diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index 192bc7a08..b36c2cbbd 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -858,6 +858,7 @@ static jobjectArray create_jstringArray(JNIEnv *jenv, char **p, size_t len) { %rename("psbt_init") wally_psbt_init_alloc; %returns_size_t(wally_psbt_is_elements); %returns_size_t(wally_psbt_is_finalized); +%returns_size_t(wally_psbt_is_input_finalized); %returns_void__(wally_psbt_remove_input); %returns_void__(wally_psbt_remove_output); %returns_void__(wally_psbt_set_pset_modifiable_flags); diff --git a/src/test/util.py b/src/test/util.py index 9baac7882..edfe9ff5b 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -541,6 +541,7 @@ class wally_psbt(Structure): ('wally_psbt_input_taproot_keypath_add', c_int, [POINTER(wally_psbt_input), c_void_p, c_size_t, c_void_p, c_size_t, c_void_p, c_size_t, POINTER(c_uint32), c_size_t]), ('wally_psbt_is_elements', c_int, [POINTER(wally_psbt), c_size_t_p]), ('wally_psbt_is_finalized', c_int, [POINTER(wally_psbt), c_size_t_p]), + ('wally_psbt_is_input_finalized', c_int, [POINTER(wally_psbt), c_size_t, c_size_t_p]), ('wally_psbt_output_clear_amount', c_int, [POINTER(wally_psbt_output)]), ('wally_psbt_output_clear_asset', c_int, [POINTER(wally_psbt_output)]), ('wally_psbt_output_clear_asset_blinding_surjectionproof', c_int, [POINTER(wally_psbt_output)]), diff --git a/src/transaction.c b/src/transaction.c index 25b6e2505..0bb1e3ccf 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -1133,25 +1133,30 @@ int wally_tx_output_free(struct wally_tx_output *output) return tx_output_free(output, true); } -int wally_tx_init_alloc(uint32_t version, uint32_t locktime, - size_t inputs_allocation_len, - size_t outputs_allocation_len, - struct wally_tx **output) +static int tx_init_alloc(uint32_t version, uint32_t locktime, + size_t inputs_allocation_len, + size_t outputs_allocation_len, + size_t max_inputs_allocation_len, + size_t max_outputs_allocation_len, + struct wally_tx **output) { struct wally_tx_input *new_inputs = NULL; struct wally_tx_output *new_outputs = NULL; OUTPUT_CHECK; + if (inputs_allocation_len > TX_MAX_INPUTS || + outputs_allocation_len > TX_MAX_OUTPUTS) + return WALLY_EINVAL; /* Tx cannot fit in a block: invalid */ OUTPUT_ALLOC(struct wally_tx); if (inputs_allocation_len) { - if (inputs_allocation_len > TX_MAX_INPUTS_ALLOC) - inputs_allocation_len = TX_MAX_INPUTS_ALLOC; + if (inputs_allocation_len > max_inputs_allocation_len) + inputs_allocation_len = max_inputs_allocation_len; new_inputs = wally_calloc(inputs_allocation_len * sizeof(struct wally_tx_input)); } if (outputs_allocation_len) { - if (outputs_allocation_len > TX_MAX_OUTPUTS_ALLOC) - outputs_allocation_len = TX_MAX_OUTPUTS_ALLOC; + if (outputs_allocation_len > max_outputs_allocation_len) + outputs_allocation_len = max_outputs_allocation_len; new_outputs = wally_calloc(outputs_allocation_len * sizeof(struct wally_tx_output)); } if ((inputs_allocation_len && !new_inputs) || @@ -1174,6 +1179,16 @@ int wally_tx_init_alloc(uint32_t version, uint32_t locktime, return WALLY_OK; } +int wally_tx_init_alloc(uint32_t version, uint32_t locktime, + size_t inputs_allocation_len, + size_t outputs_allocation_len, + struct wally_tx **output) +{ + return tx_init_alloc(version, locktime, + inputs_allocation_len, outputs_allocation_len, + TX_MAX_INPUTS_ALLOC, TX_MAX_OUTPUTS_ALLOC, output); +} + static int tx_free(struct wally_tx *tx, bool free_parent) { size_t i; @@ -2962,7 +2977,9 @@ static int tx_from_bytes(const unsigned char *bytes, size_t bytes_len, &expect_witnesses) != WALLY_OK) return WALLY_EINVAL; - ret = wally_tx_init_alloc(0, 0, num_inputs, num_outputs, output); + /* Allow pre-allocating all inputs as we have already analyzed the tx */ + ret = tx_init_alloc(0, 0, num_inputs, num_outputs, + num_inputs, num_outputs, output); if (ret != WALLY_OK) return ret; diff --git a/src/wasm_package/package-lock.json b/src/wasm_package/package-lock.json index a0f501a66..b2352c941 100644 --- a/src/wasm_package/package-lock.json +++ b/src/wasm_package/package-lock.json @@ -1,12 +1,12 @@ { "name": "wallycore", - "version": "0.9.1", + "version": "0.9.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wallycore", - "version": "0.9.1", + "version": "0.9.2", "license": "(MIT or BSD)", "devDependencies": { "buffer": "^6.0.3", diff --git a/src/wasm_package/package.json b/src/wasm_package/package.json index 0f48131f7..afc68984a 100644 --- a/src/wasm_package/package.json +++ b/src/wasm_package/package.json @@ -1,6 +1,6 @@ { "name": "wallycore", - "version": "0.9.1", + "version": "0.9.2", "description": "JavaScript bindings for libwally", "main": "src/index.js", "type": "module", diff --git a/src/wasm_package/src/const.js b/src/wasm_package/src/const.js index 35e63a5a7..f8eb3545b 100755 --- a/src/wasm_package/src/const.js +++ b/src/wasm_package/src/const.js @@ -84,7 +84,6 @@ export const EC_XONLY_PUBLIC_KEY_LEN = 32; export const HASH160_LEN = 20; export const HMAC_SHA256_LEN = 32; export const HMAC_SHA512_LEN = 64; -export const LIBWALLY_CORE_PSBT_MEMBERS_H = 1; export const PBKDF2_HMAC_SHA256_LEN = 32; export const PBKDF2_HMAC_SHA512_LEN = 64; export const RIPEMD160_LEN = 20; diff --git a/src/wasm_package/src/functions.js b/src/wasm_package/src/functions.js index 49c172b68..2b7557126 100644 --- a/src/wasm_package/src/functions.js +++ b/src/wasm_package/src/functions.js @@ -482,6 +482,7 @@ export const psbt_input_set_witness_utxo_from_tx = wrap('wally_psbt_input_set_wi export const psbt_input_taproot_keypath_add = wrap('wally_psbt_input_taproot_keypath_add', [T.OpaqueRef, T.Bytes, T.Bytes, T.Bytes, T.Uint32Array]); export const psbt_is_elements = wrap('wally_psbt_is_elements', [T.OpaqueRef, T.DestPtr(T.Int32)]); export const psbt_is_finalized = wrap('wally_psbt_is_finalized', [T.OpaqueRef, T.DestPtr(T.Int32)]); +export const psbt_is_input_finalized = wrap('wally_psbt_is_input_finalized', [T.OpaqueRef, T.Int32, T.DestPtr(T.Int32)]); export const psbt_output_clear_amount = wrap('wally_psbt_output_clear_amount', [T.OpaqueRef]); export const psbt_output_clear_asset = wrap('wally_psbt_output_clear_asset', [T.OpaqueRef]); export const psbt_output_clear_asset_blinding_surjectionproof = wrap('wally_psbt_output_clear_asset_blinding_surjectionproof', [T.OpaqueRef]); diff --git a/src/wasm_package/src/index.d.ts b/src/wasm_package/src/index.d.ts index 22cc9ee84..121b9566b 100644 --- a/src/wasm_package/src/index.d.ts +++ b/src/wasm_package/src/index.d.ts @@ -434,6 +434,7 @@ export function psbt_input_set_witness_utxo_from_tx(input: Ref_wally_psbt_input, export function psbt_input_taproot_keypath_add(input: Ref_wally_psbt_input, pub_key: Buffer|Uint8Array, tapleaf_hashes: Buffer|Uint8Array, fingerprint: Buffer|Uint8Array, child_path: Uint32Array|number[]): void; export function psbt_is_elements(psbt: Ref_wally_psbt): number; export function psbt_is_finalized(psbt: Ref_wally_psbt): number; +export function psbt_is_input_finalized(psbt: Ref_wally_psbt, index: number): number; export function psbt_output_clear_amount(output: Ref_wally_psbt_output): void; export function psbt_output_clear_asset(output: Ref_wally_psbt_output): void; export function psbt_output_clear_asset_blinding_surjectionproof(output: Ref_wally_psbt_output): void; diff --git a/tools/update_wasm_package.sh b/tools/update_wasm_package.sh index 7511b6562..35f8ec1da 100755 --- a/tools/update_wasm_package.sh +++ b/tools/update_wasm_package.sh @@ -3,6 +3,7 @@ # Extract WALLY_ constants into const.js (echo '// AUTOGENERATED by update_wasm_package.sh' \ && egrep -r '#define [^ (]* ' include/*.h \ + | grep -v '#define LIBWALLY_CORE_' \ | grep -v '#define OP_' \ | sed -r 's~.*#define ([^ ]*) *~export const \1 = ~; s~( /\*)| *$~;\1~' \ | LC_ALL=C sort \ diff --git a/tools/wasm_exports.sh b/tools/wasm_exports.sh index 86d070424..bf18a3edb 100644 --- a/tools/wasm_exports.sh +++ b/tools/wasm_exports.sh @@ -290,6 +290,7 @@ EXPORTED_FUNCTIONS="['_malloc','_free','_bip32_key_free' \ ,'_wally_psbt_input_taproot_keypath_add' \ ,'_wally_psbt_is_elements' \ ,'_wally_psbt_is_finalized' \ +,'_wally_psbt_is_input_finalized' \ ,'_wally_psbt_output_clear_amount' \ ,'_wally_psbt_output_find_keypath' \ ,'_wally_psbt_output_find_unknown' \