PIVX Core  5.6.99
P2P Digital Currency
transaction_builder.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018-2020 The Zcash developers
2 // Copyright (c) 2020-2021 The PIVX Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or https://www.opensource.org/licenses/mit-license.php .
5 
7 
8 #include "script/sign.h"
9 #include "utilmoneystr.h"
10 #include "consensus/upgrades.h"
11 #include "policy/policy.h"
12 #include "validation.h"
13 
14 #include <librustzcash.h>
15 
17  const libzcash::SaplingNote& _note,
18  const uint256& _anchor,
19  const SaplingWitness& _witness):
20  expsk(_expsk),
21  note(_note),
22  anchor(_anchor),
23  witness(_witness)
24 {
26 }
27 
29  auto cmu = this->note.cmu();
30  if (!cmu) {
31  return nullopt;
32  }
33 
34  libzcash::SaplingNotePlaintext notePlaintext(this->note, this->memo);
35 
36  auto res = notePlaintext.encrypt(this->note.pk_d);
37  if (!res) {
38  return nullopt;
39  }
40  auto enc = res.get();
41  auto encryptor = enc.second;
42 
43  libzcash::SaplingPaymentAddress address(this->note.d, this->note.pk_d);
44  CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
45  ss << address;
46  std::vector<unsigned char> addressBytes(ss.begin(), ss.end());
47 
48  OutputDescription odesc;
50  ctx,
51  encryptor.get_esk().begin(),
52  addressBytes.data(),
53  this->note.r.begin(),
54  this->note.value(),
55  odesc.cv.begin(),
56  odesc.zkproof.begin())) {
57  return nullopt;
58  }
59 
60  odesc.cmu = *cmu;
61  odesc.ephemeralKey = encryptor.get_epk();
62  odesc.encCiphertext = enc.first;
63 
64  libzcash::SaplingOutgoingPlaintext outPlaintext(this->note.pk_d, encryptor.get_esk());
65  odesc.outCiphertext = outPlaintext.encrypt(
66  this->ovk,
67  odesc.cv,
68  odesc.cmu,
69  encryptor);
70 
71  return odesc;
72 }
73 
74 // Dummy constants used during fee-calculation loop
75 static OutputDescription CreateDummyOD()
76 {
77  OutputDescription dummyOD;
78  dummyOD.cv = UINT256_MAX;
79  dummyOD.cmu = UINT256_MAX;
80  dummyOD.ephemeralKey = UINT256_MAX;
81  dummyOD.encCiphertext = {{0xff}};
82  dummyOD.outCiphertext = {{0xff}};
83  dummyOD.zkproof = {{0xff}};
84  return dummyOD;
85 }
86 static SpendDescription CreateDummySD()
87 {
88  SpendDescription dummySD;
89  dummySD.cv = UINT256_MAX;
90  dummySD.anchor = UINT256_MAX;
91  dummySD.nullifier = UINT256_MAX;
92  dummySD.rk = UINT256_MAX;
93  dummySD.zkproof = {{0xff}};
94  dummySD.spendAuthSig = {{0xff}};
95  return dummySD;
96 }
97 
98 const OutputDescription DUMMY_SHIELD_OUT = CreateDummyOD();
99 const SpendDescription DUMMY_SHIELD_SPEND = CreateDummySD();
101 
102 
104 
106 
107 bool TransactionBuilderResult::IsTx() { return maybeTx != nullopt; }
108 
109 bool TransactionBuilderResult::IsError() { return maybeError != nullopt; }
110 
112  if (maybeTx) {
113  return maybeTx.get();
114  } else {
115  throw std::runtime_error("Failed to build transaction: " + GetError());
116  }
117 }
118 
120  return maybeTx;
121 }
122 
124  if (maybeError) {
125  return maybeError.get();
126  } else {
127  // This can only happen if isTx() is true in which case we should not call getError()
128  throw std::runtime_error("getError() was called in TransactionBuilderResult, but the result was not initialized as an error.");
129  }
130 }
131 
133  const Consensus::Params& _consensusParams,
134  CKeyStore* _keystore) :
135  consensusParams(_consensusParams),
136  keystore(_keystore)
137 {
138  Clear();
139 }
140 
142 {
145  spends.clear();
146  outputs.clear();
147  tIns.clear();
148  saplingChangeAddr = nullopt;
149  tChangeAddr = nullopt;
150  fee = -1; // Verified in Build(). Must be set before.
151 }
152 
155  const libzcash::SaplingNote& note,
156  const uint256& anchor,
157  const SaplingWitness& witness)
158 {
159  // Sanity check: cannot add Sapling spend to pre-Sapling transaction
161  throw std::runtime_error("TransactionBuilder cannot add Sapling spend to pre-Sapling transaction");
162  }
163 
164  // Consistency check: all anchors must equal the first one
165  if (spends.size() > 0 && spends[0].anchor != anchor) {
166  throw std::runtime_error("Anchor does not match previously-added Sapling spends.");
167  }
168 
169  spends.emplace_back(expsk, note, anchor, witness);
170  mtx.sapData->valueBalance += note.value();
171 }
172 
174  const uint256& ovk,
176  CAmount value,
177  const std::array<unsigned char, ZC_MEMO_SIZE>& memo)
178 {
179  // Sanity check: cannot add Sapling output to pre-Sapling transaction
181  throw std::runtime_error("TransactionBuilder cannot add Sapling output to pre-Sapling transaction");
182  }
183 
184  auto note = libzcash::SaplingNote(to, value);
185  outputs.emplace_back(ovk, note, memo);
186  mtx.sapData->valueBalance -= value;
187 }
188 
189 void TransactionBuilder::AddTransparentInput(const COutPoint& utxo, const CScript& scriptPubKey, CAmount value)
190 {
191  if (keystore == nullptr) {
192  throw std::runtime_error("Cannot add transparent inputs to a TransactionBuilder without a keystore");
193  }
194 
195  mtx.vin.emplace_back(utxo);
196  tIns.emplace_back(scriptPubKey, value);
197 }
198 
200 {
201  std::vector<std::vector<unsigned char> > vSolutions;
202  txnouttype whichType;
203  if (!Solver(out.scriptPubKey, whichType, vSolutions))
204  throw std::runtime_error("Transaction builder: invalid script for transparent output");
205  mtx.vout.push_back(out);
206 }
207 
209 {
211 }
212 
214 {
215  this->fee = _fee;
216 }
217 
219 {
220  saplingChangeAddr = std::make_pair(ovk, changeAddr);
221  tChangeAddr = nullopt;
222 }
223 
225 {
226  if (!IsValidDestination(changeAddr)) {
227  throw std::runtime_error("Invalid change address, not a valid taddr.");
228  }
229 
230  tChangeAddr = changeAddr;
231  saplingChangeAddr = nullopt;
232 }
233 
235 {
236  //
237  // Sapling spend descriptions
238  //
239  if (!spends.empty() || !outputs.empty()) {
240 
242 
243  // Create Sapling OutputDescriptions
244  for (auto output : outputs) {
245  // Check this out here as well to provide better logging.
246  if (!output.note.cmu()) {
248  return TransactionBuilderResult("Output is invalid");
249  }
250 
251  auto odesc = output.Build(ctx);
252  if (!odesc) {
254  return TransactionBuilderResult("Failed to create output description");
255  }
256 
257  mtx.sapData->vShieldedOutput.push_back(odesc.get());
258  }
259 
260  // Create Sapling SpendDescriptions
261  for (auto spend : spends) {
262  auto cm = spend.note.cmu();
263  auto nf = spend.note.nullifier(
264  spend.expsk.full_viewing_key(), spend.witness.position());
265  if (!cm || !nf) {
267  return TransactionBuilderResult("Spend is invalid");
268  }
269 
270  CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
271  ss << spend.witness.path();
272  std::vector<unsigned char> witness(ss.begin(), ss.end());
273 
274  SpendDescription sdesc;
276  ctx,
277  spend.expsk.full_viewing_key().ak.begin(),
278  spend.expsk.nsk.begin(),
279  spend.note.d.data(),
280  spend.note.r.begin(),
281  spend.alpha.begin(),
282  spend.note.value(),
283  spend.anchor.begin(),
284  witness.data(),
285  sdesc.cv.begin(),
286  sdesc.rk.begin(),
287  sdesc.zkproof.data())) {
289  return TransactionBuilderResult("Spend proof failed");
290  }
291 
292  sdesc.anchor = spend.anchor;
293  sdesc.nullifier = *nf;
294  mtx.sapData->vShieldedSpend.push_back(sdesc);
295  }
296 
297  //
298  // Signatures
299  //
300 
301  // Empty output script.
302  uint256 dataToBeSigned;
303  CScript scriptCode;
304  try {
305  dataToBeSigned = SignatureHash(scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_SAPLING);
306  } catch (const std::logic_error& ex) {
308  return TransactionBuilderResult("Could not construct signature hash: " + std::string(ex.what()));
309  }
310 
311  // Create Sapling spendAuth and binding signatures
312  for (size_t i = 0; i < spends.size(); i++) {
314  spends[i].expsk.ask.begin(),
315  spends[i].alpha.begin(),
316  dataToBeSigned.begin(),
317  mtx.sapData->vShieldedSpend[i].spendAuthSig.data());
318  }
319 
321  ctx,
322  mtx.sapData->valueBalance,
323  dataToBeSigned.begin(),
324  mtx.sapData->bindingSig.data());
325 
327  }
328 
329  // Transparent signatures
330  CTransaction txNewConst(mtx);
331  for (int nIn = 0; nIn < (int) mtx.vin.size(); nIn++) {
332  auto tIn = tIns[nIn];
333  SignatureData sigdata;
334  bool signSuccess = ProduceSignature(
336  keystore, &txNewConst, nIn, tIn.value, SIGHASH_ALL),
337  tIn.scriptPubKey, sigdata, SIGVERSION_SAPLING, false);
338 
339  if (!signSuccess) {
340  return TransactionBuilderResult("Failed to sign transaction");
341  } else {
342  UpdateTransaction(mtx, nIn, sigdata);
343  }
344  }
345 
347 }
348 
350 {
351  if (!spends.empty() || !outputs.empty()) {
352  // Add Dummy Sapling OutputDescriptions
353  for (unsigned int i = 0; i < outputs.size(); i++) {
354  mtx.sapData->vShieldedOutput.push_back(DUMMY_SHIELD_OUT);
355  }
356  // Add Dummy Sapling SpendDescriptions
357  for (unsigned int i = 0; i < spends.size(); i++) {
358  mtx.sapData->vShieldedSpend.push_back(DUMMY_SHIELD_SPEND);
359  }
360  // Add Dummy Binding sig
361  mtx.sapData->bindingSig = DUMMY_SHIELD_BINDSIG;
362  }
363 
364  // Add Dummmy Transparent signatures
365  CTransaction txNewConst(mtx);
366  for (int nIn = 0; nIn < (int) mtx.vin.size(); nIn++) {
367  auto tIn = tIns[nIn];
368  SignatureData sigdata;
369  if (!ProduceSignature(DummySignatureCreator(keystore), tIn.scriptPubKey, sigdata, SIGVERSION_SAPLING, false)) {
370  return TransactionBuilderResult("Failed to sign transaction");
371  } else {
372  UpdateTransaction(mtx, nIn, sigdata);
373  }
374  }
375 
377 }
378 
380 {
381  // Clear Sapling output descriptions
382  mtx.sapData->vShieldedOutput.clear();
383 
384  // Clear Sapling spend descriptions
385  mtx.sapData->vShieldedSpend.clear();
386 
387  // Clear Binding sig
388  mtx.sapData->bindingSig = {{0}};
389 
390  // Clear Transparent signatures
391  for (CTxIn& in : mtx.vin) in.scriptSig = CScript();
392 }
393 
395 {
396  //
397  // Consistency checks
398  //
399  // Valid fee
400  if (fee < 0) {
401  return TransactionBuilderResult("Fee cannot be negative");
402  }
403 
404  // Valid change
405  CAmount change = mtx.sapData->valueBalance - fee;
406  for (auto& tIn : tIns) {
407  change += tIn.value;
408  }
409  for (auto& tOut : mtx.vout) {
410  change -= tOut.nValue;
411  }
412  if (change < 0) {
413  return TransactionBuilderResult("Change cannot be negative");
414  }
415 
416  //
417  // Change output
418  //
419 
420  if (change > 0) {
421  // If we get here and the change is dust, add it to the fee
422  CAmount dustThreshold = (spends.empty() && outputs.empty()) ? GetDustThreshold(dustRelayFee)
424  if (change > dustThreshold) {
425  // Send change to the specified change address. If no change address
426  // was set, send change to the first Sapling address given as input
427  // (A t-address can only be used as the change address if explicitly set.)
428  if (saplingChangeAddr) {
429  AddSaplingOutput(saplingChangeAddr->first, saplingChangeAddr->second, change);
430  } else if (tChangeAddr) {
431  // tChangeAddr has already been validated.
433  } else if (!spends.empty()) {
434  auto fvk = spends[0].expsk.full_viewing_key();
435  auto note = spends[0].note;
436  libzcash::SaplingPaymentAddress changeAddr(note.d, note.pk_d);
437  AddSaplingOutput(fvk.ovk, changeAddr, change);
438  } else {
439  return TransactionBuilderResult("Could not determine change address");
440  }
441  } else {
442  // Not used after, but update for consistency
443  fee += change;
444  change = 0;
445  }
446  }
447 
448  return fDummySig ? AddDummySignatures() : ProveAndSign();
449 }
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
const_iterator end() const
Definition: streams.h:163
const_iterator begin() const
Definition: streams.h:161
A virtual base class for key stores.
Definition: keystore.h:23
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:72
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
An input of a transaction.
Definition: transaction.h:94
CScript scriptSig
Definition: transaction.h:97
An output of a transaction.
Definition: transaction.h:137
CScript scriptPubKey
Definition: transaction.h:140
A signature creator that just produces 72-byte empty signatyres.
Definition: sign.h:94
A shielded output to a transaction.
uint256 cmu
The u-coordinate of the note commitment for the output note.
libzcash::SaplingOutCiphertext outCiphertext
A ciphertext component for the encrypted output note.
libzcash::GrothProof zkproof
A zero-knowledge proof using the output circuit.
libzcash::SaplingEncCiphertext encCiphertext
A ciphertext component for the encrypted output note.
uint256 cv
A value commitment to the value of the output note.
uint256 ephemeralKey
A Jubjub public key.
std::array< unsigned char, BINDINGSIG_SIZE > binding_sig_t
A shielded input to a transaction.
spend_auth_sig_t spendAuthSig
A signature authorizing this spend.
uint256 cv
A value commitment to the value of the input note.
libzcash::GrothProof zkproof
A zero-knowledge proof using the spend circuit.
uint256 anchor
A Merkle root of the Sapling note commitment tree at some block height in the past.
uint256 rk
The randomized public key for spendAuthSig.
uint256 nullifier
The nullifier of the input note.
std::vector< OutputDescriptionInfo > outputs
void AddTransparentOutput(const CTxOut &out)
void SetFee(CAmount _fee)
std::vector< TransparentInputInfo > tIns
void AddSaplingSpend(const libzcash::SaplingExpandedSpendingKey &expsk, const libzcash::SaplingNote &note, const uint256 &anchor, const SaplingWitness &witness)
TransactionBuilderResult AddDummySignatures()
TransactionBuilderResult Build(bool fDummySig=false)
void AddSaplingOutput(const uint256 &ovk, const libzcash::SaplingPaymentAddress &to, CAmount value, const std::array< unsigned char, ZC_MEMO_SIZE > &memo)
TransactionBuilderResult ProveAndSign()
const CKeyStore * keystore
std::vector< SpendDescriptionInfo > spends
void AddTransparentInput(const COutPoint &utxo, const CScript &scriptPubKey, CAmount value)
TransactionBuilder(const Consensus::Params &consensusParams, CKeyStore *keyStore=nullptr)
CMutableTransaction mtx
void SendChangeTo(const libzcash::SaplingPaymentAddress &changeAddr, const uint256 &ovk)
Optional< CTxDestination > tChangeAddr
Optional< std::pair< uint256, libzcash::SaplingPaymentAddress > > saplingChangeAddr
Optional< CTransaction > GetTx()
Optional< CTransaction > maybeTx
Optional< std::string > maybeError
A signature creator for transactions.
Definition: sign.h:73
unsigned char * begin()
Definition: uint256.h:63
uint64_t value() const
Definition: note.h:30
Optional< uint256 > cmu() const
Definition: note.cpp:29
diversifier_t d
Definition: note.h:35
uint256 pk_d
Definition: note.h:36
Optional< SaplingNotePlaintextEncryptionResult > encrypt(const uint256 &pk_d) const
Definition: note.cpp:201
SaplingOutCiphertext encrypt(const uint256 &ovk, const uint256 &cv, const uint256 &cm, SaplingNoteEncryption &enc) const
Definition: note.cpp:226
Sapling functions.
Definition: address.h:30
256-bit opaque blob.
Definition: uint256.h:138
uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, int nHashType, const CAmount &amount, SigVersion sigversion, const PrecomputedTransactionData *cache)
const unsigned int NOT_AN_INPUT
Special case nIn for signing Sapling txs.
Definition: interpreter.h:19
@ SIGHASH_ALL
Definition: interpreter.h:24
bool librustzcash_sapling_binding_sig(const void *ctx, int64_t valueBalance, const unsigned char *sighash, unsigned char *result)
This function (using the proving context) constructs a binding signature.
bool librustzcash_sapling_spend_sig(const unsigned char *ask, const unsigned char *ar, const unsigned char *sighash, unsigned char *result)
Computes the signature for each Spend description, given the key ask, the re-randomization ar,...
bool librustzcash_sapling_output_proof(void *ctx, const unsigned char *esk, const unsigned char *payment_address, const unsigned char *rcm, const uint64_t value, unsigned char *cv, unsigned char *zkproof)
This function (using the proving context) constructs an Output proof given the necessary witness info...
void librustzcash_sapling_proving_ctx_free(void *)
Frees a Sapling proving context returned from librustzcash_sapling_proving_ctx_init.
bool librustzcash_sapling_spend_proof(void *ctx, const unsigned char *ak, const unsigned char *nsk, const unsigned char *diversifier, const unsigned char *rcm, const unsigned char *ar, const uint64_t value, const unsigned char *anchor, const unsigned char *witness, unsigned char *cv, unsigned char *rk, unsigned char *zkproof)
This function (using the proving context) constructs a Spend proof given the necessary witness inform...
void librustzcash_sapling_generate_r(unsigned char *result)
Generate uniformly random scalar in Jubjub.
void * librustzcash_sapling_proving_ctx_init()
Creates a Sapling proving context. Please free this when you're done.
@ SAPLING
Definition: logging.h:63
bool IsValidDestination(const CWDestination &address)
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:12
CAmount GetDustThreshold(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:21
CAmount GetShieldedDustThreshold(const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:50
CFeeRate dustRelayFee
Definition: policy.cpp:19
@ SER_NETWORK
Definition: serialize.h:174
void UpdateTransaction(CMutableTransaction &tx, unsigned int nIn, const SignatureData &data)
Definition: sign.cpp:186
bool ProduceSignature(const BaseSignatureCreator &creator, const CScript &fromPubKey, SignatureData &sigdata, SigVersion sigversion, bool fColdStake, ScriptError *serror)
Produce a script signature using a generic signature creator.
Definition: sign.cpp:153
bool Solver(const CScript &scriptPubKey, txnouttype &typeRet, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:90
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
Definition: standard.cpp:278
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
txnouttype
Definition: standard.h:46
A mutable version of CTransaction.
Definition: transaction.h:409
Optional< SaplingTxData > sapData
Definition: transaction.h:415
std::vector< CTxOut > vout
Definition: transaction.h:411
std::vector< CTxIn > vin
Definition: transaction.h:410
Parameters that influence chain consensus.
Definition: params.h:171
std::array< unsigned char, ZC_MEMO_SIZE > memo
Optional< OutputDescription > Build(void *ctx)
libzcash::SaplingNote note
SpendDescriptionInfo(const libzcash::SaplingExpandedSpendingKey &_expsk, const libzcash::SaplingNote &_note, const uint256 &_anchor, const SaplingWitness &_witness)
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
@ SIGVERSION_SAPLING
Definition: transaction.h:28
const SaplingTxData::binding_sig_t DUMMY_SHIELD_BINDSIG
const SpendDescription DUMMY_SHIELD_SPEND
const OutputDescription DUMMY_SHIELD_OUT
const uint256 UINT256_MAX
Definition: uint256.h:177