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

psbt script spend [3/3]: allow signing for asset script path spends through PSBTs #245

Merged
merged 11 commits into from
Feb 22, 2023

Conversation

guggero
Copy link
Member

@guggero guggero commented Jan 25, 2023

Depends on #243.
Depends on #244.
Depends on btcsuite/btcd#1942.

Fixes #75.

This PR contains the PSBT serialization logic for transporting asset related meta data in a BIP-174 based PSBT packet as well as all the required RPCs to allow creating and sending to a Taro address that locks assets to a script spend path.

@guggero guggero changed the title psbt script spend [2/3]: allow signing for asset script path spends through PSBTs psbt script spend [3/3]: allow signing for asset script path spends through PSBTs Jan 25, 2023
@guggero guggero force-pushed the psbt-3-of-3-script-sign branch 2 times, most recently from cc9aed4 to 8afc879 Compare January 30, 2023 10:56
Copy link
Collaborator

@jharveyb jharveyb left a comment

Choose a reason for hiding this comment

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

Looking good! Surprisingly small changes to get script working. Only major suggested change is the FetchCommitment usage.

Will revisit to double-check the encode and Taproot logic.

itest/psbt_test.go Outdated Show resolved Hide resolved
bobScriptKeyDesc.RawKeyBytes,
)
require.NoError(t.t, err)
bobInternalKeyDesc, err := bobLnd.WalletKitClient.DeriveNextKey(
Copy link
Collaborator

Choose a reason for hiding this comment

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

General comment: Wondering if this is an RPC we should expose from tarod in the future? May be relevant for tracking which keys to backup as well.

Copy link
Member

Choose a reason for hiding this comment

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

As in re-expose the lnd API used to create keys in the first place?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I think it could be useful to have this call be threaded through the daemon so we don't need to know what key family to use in lnd when talking to tarod. Will add that to the PR that adds the BTC level PSBT stuff (for funding and signing the anchor transactions externally).

itest/psbt_test.go Show resolved Hide resolved
tarodb/assets_store.go Outdated Show resolved Hide resolved
tarodb/assets_store.go Show resolved Hide resolved
taropsbt/decode.go Outdated Show resolved Hide resolved
taropsbt/decode.go Outdated Show resolved Hide resolved
taropsbt/interface.go Show resolved Hide resolved
taroscript/tx.go Show resolved Hide resolved
tarofreighter/chain_porter.go Outdated Show resolved Hide resolved
Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

Excellent work! Gotta love when a few well crafted abstractions nicely fall into place.

See comments in line, some carried over from the PR before it was split up.

Few things popped out:

  • Ensuring that all the decoding + parsing is generic up until we restrict things to a single input deeper within the pipeline.
  • Adding a similar coin selection mutex like we have in lnd over everything, which ensures that we don't have weird double spending issues. Alternatively, we can pipe everything through the porter and have it do single threaded coin selection + locking accounting.
  • Update the test to also have a checksig in addition to the pre-image reveal so the vPSBT signing can be exercised there.

taropsbt/decode.go Outdated Show resolved Hide resolved
taropsbt/decode.go Show resolved Hide resolved

if groupKey != nil {
key := groupKey.GroupPubKey
filter.KeyGroupFilter = key.SerializeCompressed()
Copy link
Member

Choose a reason for hiding this comment

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

isn't the asset ID enough to be able to uniquely pick out an asset?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, in case of a normal asset where I have multiple coins, we actually need the script key, which I added now. We don't necessarily need the group key for our specific query, but because this function creates a generic filter, I'm leaving that in for now.

tarodb/assets_store.go Show resolved Hide resolved
tarodb/assets_store.go Show resolved Hide resolved
rpcserver.go Outdated
rpcsLog.Debugf("Selected commitment for anchor point %v, requesting "+
"delivery", inputCommitment.AnchorPoint)

resp, err := r.cfg.ChainPorter.RequestSignedDelivery(
Copy link
Member

Choose a reason for hiding this comment

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

So then this also assumes that the wallet as is will fully handle all the PSBT components? Could imagine another world where there's another external round to sign the Bitcoin portion (as that has a multi-sig/musig2 layer or w/e).

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, definitely. The BTC level PSBT components will come in a later PR and give you full control over how the anchor TX is created, signed and published.

tarorpc/assetwalletrpc/assetwallet.proto Show resolved Hide resolved
itest/psbt_test.go Outdated Show resolved Hide resolved
bobScriptKeyDesc.RawKeyBytes,
)
require.NoError(t.t, err)
bobInternalKeyDesc, err := bobLnd.WalletKitClient.DeriveNextKey(
Copy link
Member

Choose a reason for hiding this comment

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

As in re-expose the lnd API used to create keys in the first place?

itest/psbt_test.go Outdated Show resolved Hide resolved
@guggero guggero force-pushed the psbt-3-of-3-script-sign branch 2 times, most recently from 6773c33 to 57b4bf7 Compare February 3, 2023 20:31
@dstadulis
Copy link
Collaborator

full value send test needs to be written.

@guggero guggero force-pushed the psbt-3-of-3-script-sign branch 3 times, most recently from 3a1bfa7 to 16dcf55 Compare February 9, 2023 16:50
@guggero
Copy link
Member Author

guggero commented Feb 9, 2023

Thanks a lot for all the feedback, @Roasbeef and @jharveyb!

I addressed all of the comments and rebased on the latest version of part 2.

* Ensuring that all the decoding + parsing is generic up until we restrict things to a single input deeper within the pipeline.

Good idea, done!

* Adding a similar coin selection mutex like we have in `lnd` over everything, which ensures that we don't have weird double spending issues. Alternatively, we can pipe everything through the porter and have it do single threaded coin selection + locking accounting.

I agree. Though I think a mutex only adds any value if we can also mark a coin as being used/locked in the DB. I created an issue (#261) to track that.

* Update the test to also have a checksig in addition to the pre-image reveal so the vPSBT signing can be exercised there.

Yes, done.

I'm also going to split off the interactive send changes into a separate PR (I guess it will be [4/3] 😅 ), since the changes were a bit more involved than expected.

@guggero guggero force-pushed the psbt-3-of-3-script-sign branch 2 times, most recently from 8b32e68 to 1b0a54a Compare February 14, 2023 18:15
Copy link
Collaborator

@jharveyb jharveyb left a comment

Choose a reason for hiding this comment

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

Looks good, only nits left IMO + changes in preceding PR.

itest/psbt_test.go Show resolved Hide resolved
tarodb/assets_store_test.go Show resolved Hide resolved
tarogarden/mock.go Show resolved Hide resolved
taropsbt/decode.go Show resolved Hide resolved
taropsbt/encode.go Outdated Show resolved Hide resolved
taroscript/send.go Outdated Show resolved Hide resolved
tarofreighter/parcel.go Show resolved Hide resolved
@guggero
Copy link
Member Author

guggero commented Feb 16, 2023

Addressed all comments and added the input proof validation as well.

Copy link
Collaborator

@jharveyb jharveyb left a comment

Choose a reason for hiding this comment

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

Looking good! Just have to remove proof{Encoder,Decoder}.

// Before we sign the transaction, we want to make sure the
// inclusion proof is valid and the asset is actually committed
// in the anchor transaction.
err := verifyInclusionProof(vPkt.Inputs[idx])
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably want a TODO here to add a call to ChainBridge later on? To verify the anchor TX from the proof is in the chain.

Copy link
Member Author

Choose a reason for hiding this comment

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

Great point! That also reminded me that we didn't check the anchor TX in the input vs. the one in the proof, which I added now. So only the "is the block in the chain" logic remains, for which I added a TODO.

tarofreighter/wallet.go Show resolved Hide resolved
@guggero guggero force-pushed the psbt-3-of-3-script-sign branch 2 times, most recently from 535e7b1 to 3ad1f00 Compare February 20, 2023 22:31
Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

LGTM 🌳

Just have one clarifying question (about the leaf hashes in the PSBT), and another re a field that doesn't need to be set for a script path spend (the tap tweak).

taroscript/tx.go Outdated
}

spendDesc.SignMethod = input.TaprootScriptSpendSignMethod
spendDesc.TapTweak = vIn.TaprootMerkleRoot
Copy link
Member

Choose a reason for hiding this comment

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

Why is the tap tweak needed for a script spend from the tree? This is only needed for keyspend paths.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, removed.

// One leaf hash and a merkle root means we're signing a specific
// script.
case len(vIn.TaprootMerkleRoot) == sha256.Size &&
len(derivation.LeafHashes) == 1:
Copy link
Member

Choose a reason for hiding this comment

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

Does this restrict to only a control block of size 1? So you only have a single sibling.

Copy link
Member Author

Choose a reason for hiding this comment

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

No, we just only support signing for a single leaf at a time. The PSBT spec allows you to specify multiple leaf hashes and that would indicate to the signer that it should create a signature for each of them. But since we always know which path we're going to use, we haven't implemented this in lnd either. I updated the comment to make it more clear.

To avoid yet another circular dependency, we move the commitment proof
related encoders and records into the commitment package.
The asset minting test is currently flaky because the total sum of all
asset amounts minted exceeds the database's precision. This should be
fixed by building the sum outside of the database. Or by disallowing
amounts exceeding a certain number.
For now we just fix the flake by choosing smaller random amounts.
This fixes an issue with the itest that the requests were modified in
place, affecting the next test that's being run.
By copying the request before modifying it, this can be avoided.
@guggero guggero added this pull request to the merge queue Feb 22, 2023
Merged via the queue into main with commit 079bc59 Feb 22, 2023
@guggero guggero deleted the psbt-3-of-3-script-sign branch February 22, 2023 09:22
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.

addr+rpc: add code paths for creating an address w/ a script path
4 participants