Skip to content

Conversation

@joemphilips
Copy link
Contributor

Previous attempt is in #675
I'e been rewriting from F# to C# for following reason.

  1. Mixing F# and C# in one solution complicates the build process.
  2. Often the editor screwed me up. which also caused a Maintainability issue.
  3. I wanted to refactor some logic. Namely, internal representation can be simplified by using classes more closer to the actual script.
  4. Ease for review.

@joemphilips joemphilips force-pushed the csharp_miniscript branch 3 times, most recently from 1491607 to 2901351 Compare April 24, 2019 07:24
@NicolasDorier
Copy link
Collaborator

Let me know when it is ready to review. I will probably use miniscript in NBXplorer so users can't have their own way to make arbitrary scripts.

@joemphilips
Copy link
Contributor Author

I think I can finish it in three days or so.

@NicolasDorier
Copy link
Collaborator

I have quickly checked. I think you do way too complicated for GetHashCode/Equal implementations.
I would say you don't have to implement them at all, or if you do, you can just compare the string representation of the AST of the miniscript.

@joemphilips
Copy link
Contributor Author

@NicolasDorier Thanks for review.
Yeah those GetHashCode and Equal methods are based on decompiled F# version.
I think it doesn't hurt so we can leave it there though.

@joemphilips joemphilips force-pushed the csharp_miniscript branch 2 times, most recently from b30723d to cf3cce2 Compare May 1, 2019 07:21
@joemphilips joemphilips changed the title WIP: Support Miniscript (with C#) Support Miniscript (with C#) May 1, 2019
@joemphilips
Copy link
Contributor Author

Ready for review.

@NicolasDorier
Copy link
Collaborator

Wow so F# just do this by default? cool.

@knocte
Copy link
Contributor

knocte commented May 2, 2019

Wow so F# just do this by default?

Yes!

@joemphilips
Copy link
Contributor Author

joemphilips commented May 2, 2019

The error in CI seems nothing to do with my code.

Wow so F# just do this by default? cool

In fact, it does more than this. IEquatable and IStructuralEquatable and IComparable by default.
three line DU in F# will be few hundreds line of code in C# . One reason I tried to write this thing in F# first.

@joemphilips
Copy link
Contributor Author

joemphilips commented May 2, 2019

The error in CI seems nothing to do with my code.

Oops sorry. It was my fault. Will fix now. Fixed

@joemphilips joemphilips force-pushed the csharp_miniscript branch from 448d5cf to ec0b258 Compare May 2, 2019 12:02
Copy link
Contributor Author

@joemphilips joemphilips left a comment

Choose a reason for hiding this comment

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

I did some simple self review.

@@ -0,0 +1,41 @@

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This class contains a method used to to be in transaction_test .
Some functions (e.g. RandomCoin ) is quite reusable so I've moved it to here.

[Fact]
[Trait("UnitTest", "UnitTest")]

public void ShouldPlayWellWithTransactionBuilder_2()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

See this test for how TransactionBuilder Supports HTLC by Miniscript


public bool IsFinalized() => final_script_sig != null || final_script_witness != null;

/// <summary>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removing this method has nothing to do with Miniscript. But I noticed that it is legacy code from my version of PSBT. So I removed it.

}
if (ageS.LockType == SequenceLockType.Time)
{
errors.Add(new SatisfyError(SatisfyErrorCode.UnSupportedRelativeLockTimeType, this));
Copy link
Contributor Author

@joemphilips joemphilips May 3, 2019

Choose a reason for hiding this comment

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

Currently, I decided to support only block-height based lock for time (which is OP_CSV )
so in DSL "time(0) ~ time(65535)" is allowed.

I don't know this will be standard among other Miniscript implementation. So it might change in the future.

}

Sequence? _Sequence;
public TransactionBuilder SetRelativeLockTime(int lockHeight)
Copy link
Collaborator

@NicolasDorier NicolasDorier May 6, 2019

Choose a reason for hiding this comment

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

I think you can just use SetSequence(Sequence).

My only problem with this is that sequence is a per input concept, not a global tx concept.
But I guess this is still useful if a wallet has several keys depending on the same miniscript with same expiration?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the api to take int blockHeight or TimeSpan period is better than taking Sequence because we must assure tx nVersion is bigger than 1.
users are not interested into how the rule is encoded. they just want to use the relative locktime feature.

What about
SetRelativeLockTimeTo(ICoin whichCoin, int lockHeight)

and hold the info as Dictionary<ICoin, Sequence> ? In this way, we can assure that it will affect only specific input.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tell me if the current implementation is not good. I decided to use Dictionary<OutPoint, Sequence> since Coins does not support GetHashCode

var scriptSig1 = extension.GenerateScriptSig(scriptPubKey, keyRepo, signer);
var scriptSig2 = extension.GenerateScriptSig(scriptPubKey, signer2, signer2);
var scriptSig1 = extension.GenerateScriptSig(scriptPubKey, keyRepo, signer, preimageRepo, txIn.TxIn.Sequence);
var scriptSig2 = extension.GenerateScriptSig(scriptPubKey, signer2, signer2, preimageRepo, txIn.TxIn.Sequence);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think that txIn.TxIn.Sequence can ever be useful to an extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is not necessary, but I think it is useful in the case of Miniscript extension
because txbuilder fails to sign when

  1. script contains OP_CSV. and
  2. user forgets to set Sequence appropriately.

without this, users will notice that they have signed to the invalid tx when they try to broadcast.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(To make me clear, the user does not have to set nSequence even if OP_CSV is in the script if he tries to redeem through non-timelocked path)

Copy link
Collaborator

Choose a reason for hiding this comment

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

But don't you have this problem in all case anyway? The transaction might still not be broadcastable depending on the Sequence, and the only way to know is to have the previous UTXOs's height.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, TX might be un-broadcastable anyway, difference is that if the user signs to nSequence which is not suitable to pass OP_CSV (e.g. disable flag is set) that signature will be useless for redeeming through timelocked redeem condition. so the tx wont be valid forever.

@NicolasDorier
Copy link
Collaborator

Unrelated to this PR, but it makes me think that a BIP should be proposed for PSBT to support adding preimages.

@joemphilips
Copy link
Contributor Author

Unrelated to this PR, but it makes me think that a BIP should be proposed for PSBT to support adding preimages.

Indeed, I was quite surprised that no one has written yet.

@joemphilips joemphilips force-pushed the csharp_miniscript branch from f7079cf to 59df0c0 Compare May 7, 2019 09:46
@NicolasDorier
Copy link
Collaborator

NicolasDorier commented May 7, 2019

@joemphilips if you feel motivated to do the BIP, you can ask to people on #bitcoin-dev on IRC about it. If nobody did, do your own, publish on the mailing list.
I don't think there is lot's of way to disagree with, so as long as it is well redacted, it should be fine and we can later add implementation to TxBuilder.

@NicolasDorier
Copy link
Collaborator

NicolasDorier commented May 16, 2019

Hey, so I just created the type IHDScriptPubKey that you want to implement for MiniScript.
This allow to use PSBT methods like GetBalance or SignAll.

If it get possible to finalize any miniscript then I can move this to NBXplorer then BTCpayServer.

BTCPayServer now support the signature of arbitrary PSBT, so as long as we have the finalizer... it will work!

@joemphilips
Copy link
Contributor Author

Ah thanks for mentioning.
PSBT and OutputDescriptor support for BTCPayServer is super cool IMO ... It opens up possibility for many extensions.

I've just realized that the spec for output descriptor in bitcoin core has been much detailed and broad than last time I've read. I will update parsers and its tests in this weekend. (And finalizer afterwords)

BTW, I've been using namespace NBitcoin.Miniscript but this collides with Miniscript class in there, so I want to change the namespace name, what do you think is the best name? ( NBitcoin.SmartContract or NBitcoin.MiniscriptModule ?)

@NicolasDorier
Copy link
Collaborator

@joemphilips I did an object model to build a OutputDescriptor, but it does not support parsing.

Maybe NBitcoin.Scripting for both MiniScript and OutputDescriptor is good.

* Preparet test vectors from bitcoin core.
* Allow to parse private keys
* Inject ISigningRepository to pickup private key info when parsing
* Prevent parsing Uncompressed pubkey when it is in witness context.
@NicolasDorier
Copy link
Collaborator

lol this PR is massive, can you break it down into 2 PR, like one with only the output descriptor stuff and the other one with miniscript?

@joemphilips
Copy link
Contributor Author

OK. I should have created separate PR in the first place ... Miniscript and OutputDescriptor is quite different beast.

@joemphilips
Copy link
Contributor Author

Closing in favor of #694, #695 , #696 .

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