This adds support for timelocked contracts which can be used to atomically swap hash preimages over the blockchain. It is very similar to the script used by the lightning network.
Written in collaboration with Pieter Wuille.
This adds support for timelocked contracts which can be used to atomically swap hash preimages over the blockchain. It is very similar to the script used by the lightning network.
Written in collaboration with Pieter Wuille.
TX_HTLC
as to the standard templates?
standard.cpp -> Solver()
changes are only because we want to detect these types of P2SH scripts in the wallet.
Interestingly, this is useful for Paypub, as well as ZKCP, among other things.
Concept ACK
Some tests fail with:
0Running testscript wallet.py ...
1Initializing test directory /tmp/testr_T8PJ
2start_node: bitcoind started, calling bitcoin-cli -rpcwait getblockcount
3start_node: calling bitcoin-cli -rpcwait getblockcount returned
4JSONRPC error: preimage must be hexadecimal string (not '')
I can’t reproduce locally 8)
OP_ANYDATA
.
Concept ACK.
1.) Not sure if this requires a BIP, I guess we don’t need a BIP for every contract template and I can’t find the other template matching params (like OP_SMALLINTEGER
) in the BIPs.
I also concept ACK the IsStandard rule for HTLC to allow blockchain-visible HTLC, though, this might require a BIP.
OP_ANYDATA is just local wallet logic, it uses a range of script opcodes that are disabled in execution, and is only used inside the matching templates (I think it’s a bad idea to mix them in the same CScript type…), so I disagree with needing a BIP for that.
IsStandard changes so far have also been done without a BIP, but maybe we can postpone making raw HTLC standard for now.
Certainly agree we need tests.
I agree IsStandard changes do not need a BIP, but it seems any transaction type supported by the reference implementation necessarily involves coordination with other software/people, and therefore should have a BIP written describing how it works.
Is there a benefit to bare HTLC over P2SH (or SegWit) HTLC? If not, it seems pointless to expand the policy to allow for it. Note that many users do not enable bare multisig (and it should probably be disabled by default).
I don’t think initially we should make this standard outside P2SH (yet), so that’s definitely a change that should be made to this PR.
This work so far allows you to “import” a preimage into CWallet (so that you can redeem the atomic swap branch of the script) but it does not persist this to disk, and I’m curious if others think it should. (I’m skeptical of making bitcoind store secrets, especially if for some use cases they are ephemeral.)
838@@ -839,3 +839,4 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
839
840 return hashTx.GetHex();
841 }
842+
Rebased this on to master. Now supports RIPEMD160. Switched to CSV (block denominated mode). Added some RPC tests.
It can be trivially extended to use CLTV in the RPC, I just need to come up with a solid UX for it. The same goes for “relative” time strings like “10h” or “5d.” Also, still need to bring over the “preimage” display that showed in listtransactions
.
I’ll try to work alongside #7534 for the remaining work, including submitting a BIP.
62+ const opcodetype accepted_timeout_ops[] = {OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY};
63+
64+ BOOST_FOREACH(opcodetype hasher, accepted_hashers) {
65+ BOOST_FOREACH(opcodetype timeout_op, accepted_timeout_ops) {
66+ mTemplates.insert(make_pair(TX_HTLC, CScript()
67+ << hasher << OP_ANYDATA << OP_EQUAL
Before I rebase, I need to understand the consensus regarding preventing malleability of these scripts.
https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013036.html
Multiple suggestions were made and I’m not personally qualified to pick from them.
@ebfull: I’d suggest this one. But you may want to discuss it on mailing list to make sure it is compatible with other implementations (if any)
OP_IF
[HASHOP] <digest> OP_EQUALVERIFY
<seller pubkey>
OP_ELSE
<num> [TIMEOUTOP] OP_DROP
<buyer pubkey>
OP_ENDIF
OP_CHECKSIG
45@@ -46,6 +46,8 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool w
46 return false;
47 if (m < 1 || m > n)
48 return false;
49+ } else if (whichType == TX_HTLC) {
50+ return false;
@arielgabizon Would this actually reject all TX_HTLC items? I had the impression or understand that there was a design such that these would actually be completed in most instances. In lnd, a description of this was given as follows: “If payment/htlc amount is too small, than such output is called dust. If for some reason channel have been force closed during payment, and dust htlc/payment haven’t been settled (both sides haven’t agreed to remove the htlc and change the balances accordingly), th(e)n we (do) not include it in commitment transaction (thereby giv(ing it) as a fee to miners) in order to make it valid.” For reference to this comment (from a contributor in lnd) see: https://github.com/lightningnetwork/lnd/pull/115#issuecomment-305739226
With that said, I’m not sure of how the differences will play out between how bitcoin core is planning on handling it vs. how it is handled presently in the lnd development process.
cc @ebfull
107@@ -108,6 +108,30 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
108 ret.push_back(valtype()); // workaround CHECKMULTISIG bug
109 return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion));
110
111+ case TX_HTLC:
112+ {
113+ std::vector<unsigned char> image(vSolutions[0]);
114+ std::vector<unsigned char> preimage;
124@@ -125,6 +125,19 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
125 break;
126 }
127
128+ case TX_HTLC:
129+ {
130+ // Only consider HTLC's "mine" if we own ALL the keys
131+ // involved.
132+ vector<valtype> keys;
63+ make_pair(OP_SHA256, OP_BLOB32),
64+ make_pair(OP_RIPEMD160, OP_BLOB20)
65+ };
66+ const opcodetype accepted_timeout_ops[] = {OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY};
67+
68+ BOOST_FOREACH(auto hasher, accepted_hashers) {
178@@ -179,6 +179,10 @@ enum opcodetype
179
180
181 // template matching params
182+ OP_BLOB20 = 0xf7,
380+ uint32_t timeout,
381+ opcodetype hasher_type,
382+ opcodetype timeout_type)
383+{
384+ CScript script;
385+
345+ "It returns a json object with the address and redeemScript.\n"
346+
347+ "\nArguments:\n"
348+ "1. seller_key (string, required) The public key of the possessor of the preimage.\n"
349+ "2. refund_key (string, required) The public key of the recipient of the refund.\n"
350+ "3. hash (string, required) SHA256 or RIPEMD160 hash of the preimage.\n"
GetRandHash
preimage should be selected and returned to the caller.
114@@ -102,6 +115,16 @@ class CBasicKeyStore : public CKeyStore
115 virtual bool HaveCScript(const CScriptID &hash) const;
116 virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;
117
118+ bool GetPreimage(
119+ const std::vector<unsigned char>& image,
120+ std::vector<unsigned char>& preimage
121+ ) const;
122+
123+ bool AddPreimage(
122+
123+ bool AddPreimage(
124+ const std::vector<unsigned char>& image,
125+ const std::vector<unsigned char>& preimage
126+ );
127+
646+ return NullUniValue;
647+
648+ if (request.fHelp || request.params.size() != 1)
649+ throw runtime_error(
650+ "importpreimage \"data\"\n"
651+ "\nImports a preimage for use in HTLC transactions. Only remains in memory.\n"
124@@ -125,6 +125,19 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
125 break;
126 }
127
128+ case TX_HTLC:
129+ {
130+ // Only consider HTLC's "mine" if we own ALL the keys
131+ // involved.
132+ vector<valtype> keys;
133+ keys.push_back(vSolutions[1]);
Concept Ack.
I did some code review, overall looks very clean and concise.
I was slightly concerned with the use of new template parameters, but I think that the proposed new ones are reasonable & general purpose.
I think that the preimage map should persist entries; but perhaps that can be done as a later PR. I would also suggest adding a Lock/Unlock feature in RPC, because I think that that would ensure safer use of entries stored in the preimage map for users.
Thanks for the reviews @arielg and @JeremyRubin. I intend to rebase this again and clean it up.
Also, BIP199 has been submitted to start standardizing what is in this PR.
@ebfull Thanks for mentioning… that was my question, regarding BIP 199, when reading this thread.
A few questions actually -
28+
29+ def activateCSV(self):
30+ # activation should happen at block height 432 (3 periods)
31+ min_activation_height = 432
32+ height = self.nodes[0].getblockcount()
33+ assert(height < 432)
assert(height < min_activation_height)
here instead?