Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dual funding, PSBT work #3902

Merged

Conversation

niftynei
Copy link
Collaborator

@niftynei niftynei commented Aug 4, 2020

This PR contains just the PSBT utilities needed for the dual-funding accepter PR.

This allows us to:

  • add a serial id to psbt inputs + outputs
  • sort psbt inputs + outputs by serial_id
  • produce a 'diff' between two psbts (must have serial_ids assigned to inputs + outputs though)

Changelog-None

Copy link
Contributor

@rustyrussell rustyrussell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style comments only, and some doc fixes...

bitcoin/psbt.c Outdated
Comment on lines 63 to 64
if (wally_tx_init_alloc(WALLY_TX_VERSION_2, 0, num_inputs, num_outputs, &wtx) != WALLY_OK)
return NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Abort if this fails. We don't (as a rule) check for allocation failures; in fact, tal() will abort if it can't allocate. Crashing due to NULL on the next line will give us a nice backtrace too :)

bitcoin/psbt.c Outdated
sizeof(struct bitcoin_txid),
outnum, sequence, NULL, 0, NULL,
&tx_in) != WALLY_OK)
return NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here too..

bitcoin/psbt.c Outdated
const u8 *script,
struct amount_sat amount)
{
size_t i = psbt->tx->num_outputs;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vague preference not to use i as anything but an iterator. In this case, the extra var declaraton is not really worth it, I think.

bitcoin/psbt.c Outdated
Comment on lines 494 to 495
struct wally_tx_input *in =
&psbt->tx->inputs[i];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this doesn't fit in 80 columns on a single line? OTOH, this is more poetic, I guess?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right. It fits!

bitcoin/psbt.h Outdated
* @num_inputs - number of inputs to allocate
* @num_outputs - number of outputs to allocate
*
* Returns NULL if there's a failure.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this.

return false;
assert(value_len == sizeof(*serial_id));
memcpy(serial_id, result, value_len);
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit round-about, allocating a key to do the comparison. Either we could implement psbt_get_lightning(), or if we want to be generic, have psbt_get_unknown() take the prefix and the keyvalue?

void *result = psbt_get_unknown(map, key, &value_len);
if (!result)
return false;
assert(value_len == sizeof(*serial_id));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry this is a vector by which bad PSBTs can crash us. Perhaps return false in this case?

void *result = psbt_get_unknown(input->unknowns, key, &value_len);
if (!result)
return false;
assert(value_len == sizeof(*max_witness_len));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too?

* If a serial_id has remained the same, but the underlying data
* has changed, this WILL NOT detect it.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not true any more?

* @added_outs - outputs added to {new}
* @rm_outs - outputs removed from {new}
*
* Returns true if no changes are found.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it doesn't!

Also probably needs warning about sets simply referring into orig and new here, not on implementation?

@jgriffiths
Copy link
Contributor

jgriffiths commented Aug 6, 2020

Assuming #3833 is merged (as the wally changes are in master), this PR will need updating to reflect the current wally interface changes. The major ones are:

  • Maps are all the same type now, see the wally_map_xx functions in wally_psbt.h
  • You don't need to create new maps if they are empty, just call wally_map_add and it will do the right thing
  • wally_map_find should replace your hand-rolled search loops
  • You can now add tx inputs and outputs directly to the psbt at any position and it will update the tx in step.
  • Some struct members have changed names to reflect the rest of the wally naming, see Jon wally update #3833 for details.

Other comments:

  • Per Jon wally update #3833 in psbt_append_input you don't need to allocate an input to add it, but you should use the elements init function rather than messing with the features bits yourself (they are an impl detail its better if you don't poke around in)
  • #define WALLY_PSBT_PROPRIETARY 0xFC you can just use PSBT_PROPRIETARY_TYPE from wally_psbt.h

@niftynei niftynei force-pushed the nifty/dual-fund-psbt-work branch 2 times, most recently from 2c83bf7 to 2ca8b30 Compare August 6, 2020 20:55
@niftynei niftynei force-pushed the nifty/dual-fund-psbt-work branch 2 times, most recently from 94e5826 to 17e210c Compare August 7, 2020 04:39
@niftynei
Copy link
Collaborator Author

niftynei commented Aug 7, 2020

Ok, updated to the latest things.There's a failing unit test I'll have to address tomorrow.

libwally now verifies that transactions have inputs before agreeing to serialize them, which impacted how linearize_outputs works. We now add an empty input before attempting serialization.

There's an outstanding issue here still in that our comparison functions will fail to detect maps with identical yet differently ordered entries. Filed ElementsProject/libwally-core#214.

@niftynei niftynei force-pushed the nifty/dual-fund-psbt-work branch 3 times, most recently from 79712de to e9fa0ed Compare August 7, 2020 16:46
bitcoin/psbt.c Outdated
abort();

tx_in->features = chainparams->is_elements ? WALLY_TX_IS_ELEMENTS : 0;
input = psbt_add_input(psbt, tx_in, insert_at);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

features is an internal impl detail and we may end up using it for more than just elements. please use wally_tx_elements_input_init_alloc for elements instead.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, updated

/* If is P2SH, redeemscript must be present */
const u8 *outscript =
wally_tx_output_get_script(tmpctx,
&input->utxo->outputs[psbt->tx->inputs[i].index]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want to assert this is in bounds for the utxo outputs before dereferencing here, just to be sure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, updated

@jgriffiths
Copy link
Contributor

Note that your lightning keys and values in maps need to be stored endian-independent - so rather than memcpy for your serial id you'll need to use cpu_to/from_ before copying, or things will go badly wrong when swapping PSBTs with an instance on a difference arch.

includes facilities for
  - sorting psbt inputs by serial_id
  - sorting psbt outputs by serial_id
  - adding a serial_id
  - getting a serial_id
  - finding the diffset between two psbts
  - adding a max_len to a psbt input
  - getting a max_len from a psbt input
There's no stable ordering on unknown serialization, so linearizing
identical but mis-ordered unknown data will lead to 'wrong' results.
Instead, we just ignore any data that's in the psbt unknown struct.

There's probably also problems here with other PSBT maps. Really, this
needs a finer grained comparison function .... fuck
psbt->outputs[0] = *out;
psbt->num_outputs++;
/* Blank out unknowns. These are unordered and serializing
* them might have different outputs for identical data */
psbt->outputs[0].unknowns.num_items = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wally_map_sort(&psbt->outputs[0].unknowns) can be used now that its been merged to wally master.

Our psbt input/output comparison functions use serialization to compare
the things, but if there's a map with things in it and the map isn't
sorted exactly the same, it's highly likely you'll mark an identical inputs
as different.

To fix this, we sort all the input/output maps before linearizing them.
@rustyrussell
Copy link
Contributor

Ack f99dbfa

@rustyrussell rustyrussell merged commit 6371a49 into ElementsProject:master Aug 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants