mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 01:43:36 +01:00
wallet/psbt_fixup: routine to fix invalid PBSTs which modern libwally won't load.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
4c6966d16a
commit
7174d06a70
@ -3,6 +3,7 @@
|
||||
WALLET_LIB_SRC := \
|
||||
wallet/db.c \
|
||||
wallet/invoices.c \
|
||||
wallet/psbt_fixup.c \
|
||||
wallet/txfilter.c \
|
||||
wallet/wallet.c \
|
||||
wallet/walletrpc.c
|
||||
|
@ -51,6 +51,9 @@ static void migrate_payments_scids_as_integers(struct lightningd *ld,
|
||||
static void fillin_missing_lease_satoshi(struct lightningd *ld,
|
||||
struct db *db);
|
||||
|
||||
static void fillin_missing_lease_satoshi(struct lightningd *ld,
|
||||
struct db *db);
|
||||
|
||||
/* Do not reorder or remove elements from this array, it is used to
|
||||
* migrate existing databases from a previous state, based on the
|
||||
* string indices */
|
||||
|
188
wallet/psbt_fixup.c
Normal file
188
wallet/psbt_fixup.c
Normal file
@ -0,0 +1,188 @@
|
||||
/* This is designed to fix up malformed PBSTs, where prior to v0.12.0
|
||||
* (commit 572942c783a58e518f0a1b449412a82717594636) we would put raw
|
||||
* signatures, not DER-encoded signatures, inside our PSBT inputs'
|
||||
* PSBT_IN_PARTIAL_SIG.
|
||||
*
|
||||
* As of libwally 0.88 (and perhaps 0.87?) it will refuse to load them.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <bitcoin/signature.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <common/utils.h>
|
||||
#include <wallet/psbt_fixup.h>
|
||||
#include <wire/wire.h>
|
||||
|
||||
struct keypair {
|
||||
u64 keytype;
|
||||
u8 *key;
|
||||
u8 *value;
|
||||
};
|
||||
|
||||
static size_t compact_size_len(u64 v)
|
||||
{
|
||||
if (v < 0xfd) {
|
||||
return 1;
|
||||
} else if (v <= 0xffff) {
|
||||
return 3;
|
||||
} else if (v <= 0xffffffff) {
|
||||
return 5;
|
||||
} else {
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
|
||||
static u64 fromwire_compact_size(const u8 **cursor, size_t *max)
|
||||
{
|
||||
u8 v;
|
||||
le16 v16;
|
||||
le32 v32;
|
||||
le64 v64;
|
||||
|
||||
v = fromwire_u8(cursor, max);
|
||||
switch (v) {
|
||||
case 0xfd:
|
||||
fromwire(cursor, max, &v16, sizeof(v16));
|
||||
return le16_to_cpu(v16);
|
||||
case 0xfe:
|
||||
fromwire(cursor, max, &v32, sizeof(v32));
|
||||
return le32_to_cpu(v32);
|
||||
case 0xff:
|
||||
fromwire(cursor, max, &v64, sizeof(v64));
|
||||
return le64_to_cpu(v64);
|
||||
default:
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t fromwire_compact_len(const u8 **cursor, size_t *max)
|
||||
{
|
||||
u64 len = fromwire_compact_size(cursor, max);
|
||||
if (len > *max) {
|
||||
fromwire_fail(cursor, max);
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* BIP-0174:
|
||||
* <keypair> := <key> <value>
|
||||
* <key> := <keylen> <keytype> <keydata>
|
||||
* <value> := <valuelen> <valuedata>
|
||||
*/
|
||||
static struct keypair *fromwire_keypair(const tal_t *ctx,
|
||||
const u8 **cursor,
|
||||
size_t *max)
|
||||
{
|
||||
struct keypair *kp = tal(ctx, struct keypair);
|
||||
u64 len;
|
||||
size_t keylen;
|
||||
|
||||
/* 0 byte terminates */
|
||||
len = fromwire_compact_len(cursor, max);
|
||||
if (len == 0)
|
||||
return tal_free(kp);
|
||||
|
||||
kp->keytype = fromwire_compact_size(cursor, max);
|
||||
/* Sanity check */
|
||||
if (compact_size_len(kp->keytype) > len)
|
||||
return tal_free(kp);
|
||||
keylen = len - compact_size_len(kp->keytype);
|
||||
kp->key = tal_arr(kp, u8, keylen);
|
||||
fromwire_u8_array(cursor, max, kp->key, keylen);
|
||||
|
||||
len = fromwire_compact_len(cursor, max);
|
||||
kp->value = tal_arr(kp, u8, len);
|
||||
fromwire_u8_array(cursor, max, kp->value, len);
|
||||
return kp;
|
||||
}
|
||||
|
||||
static void towire_compact_size(u8 **pptr, u64 v)
|
||||
{
|
||||
if (v < 0xfd) {
|
||||
towire_u8(pptr, v);
|
||||
} else if (v <= 0xffff) {
|
||||
le16 v16 = cpu_to_le16(v);
|
||||
towire_u8(pptr, 0xfd);
|
||||
towire(pptr, &v16, sizeof(v16));
|
||||
} else if (v <= 0xffffffff) {
|
||||
le32 v32 = cpu_to_le32(v);
|
||||
towire_u8(pptr, 0xfe);
|
||||
towire(pptr, &v32, sizeof(v32));
|
||||
} else {
|
||||
le64 v64 = cpu_to_le64(v);
|
||||
towire_u8(pptr, 0xff);
|
||||
towire(pptr, &v64, sizeof(v64));
|
||||
}
|
||||
}
|
||||
|
||||
static void towire_keypair(u8 **pptr, const struct keypair *kp)
|
||||
{
|
||||
towire_compact_size(pptr,
|
||||
compact_size_len(kp->keytype) + tal_bytelen(kp->key));
|
||||
towire_compact_size(pptr, kp->keytype);
|
||||
towire_u8_array(pptr, kp->key, tal_bytelen(kp->key));
|
||||
towire_compact_size(pptr, tal_bytelen(kp->value));
|
||||
towire_u8_array(pptr, kp->value, tal_bytelen(kp->value));
|
||||
}
|
||||
|
||||
static bool fixup_sig(struct keypair *kp)
|
||||
{
|
||||
const u8 *valcursor = kp->value;
|
||||
size_t vallen = tal_bytelen(kp->value);
|
||||
struct bitcoin_signature sig;
|
||||
size_t derlen;
|
||||
u8 der[73];
|
||||
|
||||
fromwire_secp256k1_ecdsa_signature(&valcursor, &vallen, &sig.s);
|
||||
sig.sighash_type = SIGHASH_ALL;
|
||||
|
||||
/* If that didn't parse, or there are more bytes
|
||||
* left, ignore it */
|
||||
if (valcursor == NULL || vallen != 0)
|
||||
return false;
|
||||
|
||||
derlen = signature_to_der(der, &sig);
|
||||
kp->value = tal_dup_arr(kp, u8, der, derlen, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* I am deeply, deeply unhappy with this code. I initially tried parsing the
|
||||
* entire PSBT, but that turns out not to be possible without decoding the
|
||||
* tranaction. Literally WTF */
|
||||
const u8 *psbt_fixup(const tal_t *ctx, const u8 *psbtblob)
|
||||
{
|
||||
const u8 *prev_cursor, *cursor = psbtblob;
|
||||
size_t max = tal_bytelen(psbtblob);
|
||||
u8 *ret;
|
||||
struct keypair *kp, *changed_kp;
|
||||
|
||||
/* Skip magic */
|
||||
fromwire_pad(&cursor, &max, 5);
|
||||
|
||||
/* Skip global map */
|
||||
while ((kp = fromwire_keypair(tmpctx, &cursor, &max)) != NULL);
|
||||
|
||||
/* Now input map */
|
||||
changed_kp = NULL;
|
||||
prev_cursor = cursor;
|
||||
while ((kp = fromwire_keypair(tmpctx, &cursor, &max)) != NULL) {
|
||||
/* PSBT_IN_PARTIAL_SIG = 0x02 */
|
||||
if (kp->keytype == 2 && fixup_sig(kp)) {
|
||||
changed_kp = kp;
|
||||
break;
|
||||
}
|
||||
prev_cursor = cursor;
|
||||
}
|
||||
|
||||
if (!changed_kp)
|
||||
return NULL;
|
||||
|
||||
ret = tal_dup_arr(ctx, u8, psbtblob, prev_cursor - psbtblob, 0);
|
||||
towire_keypair(&ret, changed_kp);
|
||||
towire_u8_array(&ret, cursor, max);
|
||||
|
||||
return ret;
|
||||
}
|
12
wallet/psbt_fixup.h
Normal file
12
wallet/psbt_fixup.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef LIGHTNING_WALLET_PSBT_FIXUP_H
|
||||
#define LIGHTNING_WALLET_PSBT_FIXUP_H
|
||||
#include "config.h"
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
/* If psbtblob cannot be parse, try rewriting to fix signature.
|
||||
* Returns NULL if it doesn't parse or was unchanged.
|
||||
*/
|
||||
const u8 *psbt_fixup(const tal_t *ctx, const u8 *psbtblob);
|
||||
|
||||
#endif /* LIGHTNING_WALLET_PSBT_FIXUP_H */
|
Loading…
Reference in New Issue
Block a user