Skip to content

Commit b6bb19a

Browse files
committed
WIP: First pass at PSBT for Confidential Assets
1 parent 8c21d41 commit b6bb19a

File tree

12 files changed

+1025
-155
lines changed

12 files changed

+1025
-155
lines changed

src/core_io.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,6 @@ std::string SighashToStr(unsigned char sighash_type);
3939
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
4040
void ScriptToUniv(const CScript& script, UniValue& out, bool include_address);
4141
void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0);
42+
std::string EncodePSBT(const PartiallySignedTransaction& psbt);
4243

4344
#endif // BITCOIN_CORE_IO_H

src/core_write.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <issuance.h>
1010
#include <key_io.h>
1111
#include <script/script.h>
12+
#include <script/sign.h>
1213
#include <script/standard.h>
1314
#include <serialize.h>
1415
#include <streams.h>
@@ -327,15 +328,21 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
327328
uint64_t minv;
328329
uint64_t maxv;
329330
const CTxOutWitness* ptxoutwit = tx.witness.vtxoutwit.size() <= i? NULL: &tx.witness.vtxoutwit[i];
330-
if (ptxoutwit && secp256k1_rangeproof_info(secp256k1_blind_context, &exp, &mantissa, &minv, &maxv, &ptxoutwit->vchRangeproof[0], ptxoutwit->vchRangeproof.size())) {
331-
if (exp == -1) {
332-
out.pushKV("value", ValueFromAmount((CAmount)minv));
333-
} else {
334-
out.pushKV("value-minimum", ValueFromAmount((CAmount)minv));
335-
out.pushKV("value-maximum", ValueFromAmount((CAmount)maxv));
331+
if (ptxoutwit) {
332+
if (ptxoutwit->vchRangeproof.size() && secp256k1_rangeproof_info(secp256k1_blind_context, &exp, &mantissa, &minv, &maxv, &ptxoutwit->vchRangeproof[0], ptxoutwit->vchRangeproof.size())) {
333+
if (exp == -1) {
334+
out.pushKV("value", ValueFromAmount((CAmount)minv));
335+
} else {
336+
out.pushKV("value-minimum", ValueFromAmount((CAmount)minv));
337+
out.pushKV("value-maximum", ValueFromAmount((CAmount)maxv));
338+
}
339+
out.pushKV("ct-exponent", exp);
340+
out.pushKV("ct-bits", mantissa);
341+
}
342+
343+
if (ptxoutwit->vchSurjectionproof.size()) {
344+
out.pushKV("surjectionproof", HexStr(ptxoutwit->vchSurjectionproof));
336345
}
337-
out.pushKV("ct-exponent", exp);
338-
out.pushKV("ct-bits", mantissa);
339346
}
340347
out.pushKV("valuecommitment", txout.nValue.GetHex());
341348
}
@@ -366,3 +373,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
366373
entry.pushKV("hex", EncodeHexTx(tx, serialize_flags)); // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction".
367374
}
368375
}
376+
377+
std::string EncodePSBT(const PartiallySignedTransaction& psbt)
378+
{
379+
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
380+
ssTx << psbt;
381+
return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
382+
}

src/rpc/rawtransaction.cpp

Lines changed: 255 additions & 33 deletions
Large diffs are not rendered by default.

src/rpc/rawtransaction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ class UniValue;
1313
UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType);
1414

1515
/** Create a transaction from univalue parameters */
16-
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf, const UniValue& assets_in);
16+
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf, const UniValue& assets_in, std::vector<CPubKey>* output_pubkeys_out = nullptr);
1717

1818
#endif // BITCOIN_RPC_RAWTRANSACTION_H

src/script/sign.cpp

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <script/sign.h>
77

8+
#include <confidential_validation.h>
89
#include <key.h>
910
#include <policy/policy.h>
1011
#include <primitives/transaction.h>
@@ -241,27 +242,31 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
241242
return sigdata.complete;
242243
}
243244

244-
bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash)
245+
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash)
245246
{
247+
fprintf(stderr, "signpsbtinput called!\n");
248+
const CMutableTransaction& tx = *psbt.tx;
249+
PSBTInput& input = psbt.inputs[index];
250+
246251
// if this input has a final scriptsig or scriptwitness, don't do anything with it
247252
if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) {
253+
fprintf(stderr, "already signed, though\n");
248254
return true;
249255
}
250256

251257
// Fill SignatureData with input info
252258
SignatureData sigdata;
253259
input.FillSignatureData(sigdata);
254260

255-
// Get UTXO
261+
// Get UTXO for this input
256262
bool require_witness_sig = false;
257263
CTxOut utxo;
264+
258265
if (input.non_witness_utxo) {
259266
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
260267
if (input.non_witness_utxo->GetHash() != tx.vin[index].prevout.hash) return false;
261-
// If both witness and non-witness UTXO are provided, verify that they match. This check shouldn't
262-
// matter, as the PSBT deserializer enforces only one of both is provided, and the only way both
263-
// can be present is when they're added simultaneously by FillPSBT (in which case they always match).
264-
// Still, check in order to not rely on callers to enforce this.
268+
// If both witness and non-witness UTXO are provided, verify that they match. This should not
269+
// actually be possible.
265270
if (!input.witness_utxo.IsNull() && input.non_witness_utxo->vout[tx.vin[index].prevout.n] != input.witness_utxo) return false;
266271
utxo = input.non_witness_utxo->vout[tx.vin[index].prevout.n];
267272
} else if (!input.witness_utxo.IsNull()) {
@@ -275,20 +280,24 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
275280
return false;
276281
}
277282

283+
fprintf(stderr, "gathering utxos\n");
284+
278285
MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash);
279286
sigdata.witness = false;
287+
fprintf(stderr, "about to produce signature\n");
280288
bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
289+
fprintf(stderr, "sig complete: %d\n", sig_complete);
281290
// Verify that a witness signature was produced in case one was required.
282-
if (require_witness_sig && !sigdata.witness) return false;
291+
if (require_witness_sig && !sigdata.witness) {
292+
fprintf(stderr, "oh no, witness problem\n");
293+
return false;
294+
}
283295
input.FromSignatureData(sigdata);
284296

285-
// If both UTXO types are present, drop the unnecessary one.
286-
if (input.non_witness_utxo && !input.witness_utxo.IsNull()) {
287-
if (sigdata.witness) {
288-
input.non_witness_utxo = nullptr;
289-
} else {
290-
input.witness_utxo.SetNull();
291-
}
297+
// If we have a witness signature, use the smaller witness UTXO.
298+
if (sigdata.witness) {
299+
input.witness_utxo = utxo;
300+
input.non_witness_utxo = nullptr;
292301
}
293302

294303
return sig_complete;
@@ -614,6 +623,11 @@ void PSBTInput::Merge(const PSBTInput& input)
614623
if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script;
615624
if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig;
616625
if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness;
626+
627+
if (!value && input.value) value = input.value;
628+
if (value_blinding_factor.IsNull() && !input.value_blinding_factor.IsNull()) value_blinding_factor = input.value_blinding_factor;
629+
if (asset.IsNull() && !input.asset.IsNull()) asset = input.asset;
630+
if (asset_blinding_factor.IsNull() && !input.asset_blinding_factor.IsNull()) asset_blinding_factor = input.asset_blinding_factor;
617631
}
618632

619633
bool PSBTInput::IsSane() const
@@ -666,6 +680,15 @@ void PSBTOutput::Merge(const PSBTOutput& output)
666680

667681
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
668682
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
683+
684+
if (!blinding_pubkey.IsValid() && output.blinding_pubkey.IsValid()) blinding_pubkey = output.blinding_pubkey;
685+
if (value_commitment.IsNull() && !output.value_commitment.IsNull()) value_commitment = output.value_commitment;
686+
if (value_blinding_factor.IsNull() && !output.value_blinding_factor.IsNull()) value_blinding_factor = output.value_blinding_factor;
687+
if (asset_commitment.IsNull() && !output.asset_commitment.IsNull()) asset_commitment = output.asset_commitment;
688+
if (asset_blinding_factor.IsNull() && !output.asset_blinding_factor.IsNull()) asset_blinding_factor = output.asset_blinding_factor;
689+
if (nonce_commitment.IsNull() && !output.nonce_commitment.IsNull()) nonce_commitment = output.nonce_commitment;
690+
if (range_proof.empty() && !output.range_proof.empty()) range_proof = output.range_proof;
691+
if (surjection_proof.empty() && !output.surjection_proof.empty()) surjection_proof = output.surjection_proof;
669692
}
670693

671694
bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const

0 commit comments

Comments
 (0)