Rename some usage of 'pour'.
This commit is contained in:
parent
bb64be52fe
commit
b7e4abd6f7
|
@ -24,7 +24,7 @@ class PourTxTest(BitcoinTestFramework):
|
|||
|
||||
(total_in, inputs) = gather_inputs(self.nodes[0], 40)
|
||||
protect_tx = self.nodes[0].createrawtransaction(inputs, {})
|
||||
pour_result = self.nodes[0].zcrawpour(protect_tx, {}, {zcaddress:39.9}, 39.9, 0)
|
||||
pour_result = self.nodes[0].zcrawjoinsplit(protect_tx, {}, {zcaddress:39.9}, 39.9, 0)
|
||||
|
||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, pour_result["encryptedbucket1"])
|
||||
assert_equal(receive_result["exists"], False)
|
||||
|
@ -37,7 +37,7 @@ class PourTxTest(BitcoinTestFramework):
|
|||
assert_equal(receive_result["exists"], True)
|
||||
|
||||
pour_tx = self.nodes[0].createrawtransaction([], {})
|
||||
pour_result = self.nodes[0].zcrawpour(pour_tx, {receive_result["bucket"] : zcsecretkey}, {zcaddress: 39.8}, 0, 0.1)
|
||||
pour_result = self.nodes[0].zcrawjoinsplit(pour_tx, {receive_result["bucket"] : zcsecretkey}, {zcaddress: 39.8}, 0, 0.1)
|
||||
|
||||
self.nodes[0].sendrawtransaction(pour_result["rawtxn"])
|
||||
self.nodes[0].generate(1)
|
||||
|
|
|
@ -56,7 +56,7 @@ class PourTxTest(BitcoinTestFramework):
|
|||
for i in range(4):
|
||||
(total_in, inputs) = gather_inputs(self.nodes[i], 40)
|
||||
pool[i] = self.nodes[i].createrawtransaction(inputs, {})
|
||||
pool[i] = self.nodes[i].zcrawpour(pool[i], {}, {zcaddress:39.9}, 39.9, 0)
|
||||
pool[i] = self.nodes[i].zcrawjoinsplit(pool[i], {}, {zcaddress:39.9}, 39.9, 0)
|
||||
signed = self.nodes[i].signrawtransaction(pool[i]["rawtxn"])
|
||||
|
||||
# send the tx to both halves of the network
|
||||
|
@ -88,25 +88,25 @@ class PourTxTest(BitcoinTestFramework):
|
|||
|
||||
blank_tx = self.nodes[0].createrawtransaction([], {})
|
||||
# Create pour {A, B}->{*}
|
||||
pour_AB = self.nodes[0].zcrawpour(blank_tx,
|
||||
pour_AB = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||
{pool[0] : zcsecretkey, pool[1] : zcsecretkey},
|
||||
{zcaddress:(39.9*2)-0.1},
|
||||
0, 0.1)
|
||||
|
||||
# Create pour {B, C}->{*}
|
||||
pour_BC = self.nodes[0].zcrawpour(blank_tx,
|
||||
pour_BC = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||
{pool[1] : zcsecretkey, pool[2] : zcsecretkey},
|
||||
{zcaddress:(39.9*2)-0.1},
|
||||
0, 0.1)
|
||||
|
||||
# Create pour {C, D}->{*}
|
||||
pour_CD = self.nodes[0].zcrawpour(blank_tx,
|
||||
pour_CD = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||
{pool[2] : zcsecretkey, pool[3] : zcsecretkey},
|
||||
{zcaddress:(39.9*2)-0.1},
|
||||
0, 0.1)
|
||||
|
||||
# Create pour {A, D}->{*}
|
||||
pour_AD = self.nodes[0].zcrawpour(blank_tx,
|
||||
pour_AD = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||
{pool[0] : zcsecretkey, pool[3] : zcsecretkey},
|
||||
{zcaddress:(39.9*2)-0.1},
|
||||
0, 0.1)
|
||||
|
|
|
@ -149,7 +149,7 @@ void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) {
|
|||
|
||||
// We don't want to overwrite an anchor we already have.
|
||||
// This occurs when a block doesn't modify mapAnchors at all,
|
||||
// because there are no pours. We could get around this a
|
||||
// because there are no joinsplits. We could get around this a
|
||||
// different way (make all blocks modify mapAnchors somehow)
|
||||
// but this is simpler to reason about.
|
||||
if (currentRoot != newrt) {
|
||||
|
@ -394,9 +394,9 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
|
|||
{
|
||||
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
|
||||
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit)
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit)
|
||||
{
|
||||
BOOST_FOREACH(const uint256& serial, pour.nullifiers)
|
||||
BOOST_FOREACH(const uint256& serial, joinsplit.nullifiers)
|
||||
{
|
||||
if (GetNullifier(serial)) {
|
||||
// If the serial is set, this transaction
|
||||
|
@ -406,14 +406,14 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
|
|||
}
|
||||
|
||||
ZCIncrementalMerkleTree tree;
|
||||
auto it = intermediates.find(pour.anchor);
|
||||
auto it = intermediates.find(joinsplit.anchor);
|
||||
if (it != intermediates.end()) {
|
||||
tree = it->second;
|
||||
} else if (!GetAnchorAt(pour.anchor, tree)) {
|
||||
} else if (!GetAnchorAt(joinsplit.anchor, tree)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const uint256& commitment, pour.commitments)
|
||||
BOOST_FOREACH(const uint256& commitment, joinsplit.commitments)
|
||||
{
|
||||
tree.append(commitment);
|
||||
}
|
||||
|
|
|
@ -515,7 +515,7 @@ public:
|
|||
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
|
||||
bool HaveInputs(const CTransaction& tx) const;
|
||||
|
||||
//! Check whether all pour requirements (anchors/serials) are satisfied
|
||||
//! Check whether all joinsplit requirements (anchors/serials) are satisfied
|
||||
bool HaveJoinSplitRequirements(const CTransaction& tx) const;
|
||||
|
||||
//! Return priority of tx at height nHeight
|
||||
|
|
82
src/main.cpp
82
src/main.cpp
|
@ -876,10 +876,10 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
|||
return false;
|
||||
} else {
|
||||
// Ensure that zk-SNARKs verify
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit) {
|
||||
if (!pour.Verify(*pzcashParams, tx.joinSplitPubKey)) {
|
||||
return state.DoS(100, error("CheckTransaction(): pour does not verify"),
|
||||
REJECT_INVALID, "bad-txns-pour-verification-failed");
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
if (!joinsplit.Verify(*pzcashParams, tx.joinSplitPubKey)) {
|
||||
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
|
||||
REJECT_INVALID, "bad-txns-joinsplit-verification-failed");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -920,35 +920,35 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
|||
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
||||
}
|
||||
|
||||
// Ensure that pour values are well-formed
|
||||
BOOST_FOREACH(const JSDescription& pour, tx.vjoinsplit)
|
||||
// Ensure that joinsplit values are well-formed
|
||||
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit)
|
||||
{
|
||||
if (pour.vpub_old < 0) {
|
||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_old negative"),
|
||||
if (joinsplit.vpub_old < 0) {
|
||||
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_old negative"),
|
||||
REJECT_INVALID, "bad-txns-vpub_old-negative");
|
||||
}
|
||||
|
||||
if (pour.vpub_new < 0) {
|
||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_new negative"),
|
||||
if (joinsplit.vpub_new < 0) {
|
||||
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new negative"),
|
||||
REJECT_INVALID, "bad-txns-vpub_new-negative");
|
||||
}
|
||||
|
||||
if (pour.vpub_old > MAX_MONEY) {
|
||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_old too high"),
|
||||
if (joinsplit.vpub_old > MAX_MONEY) {
|
||||
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_old too high"),
|
||||
REJECT_INVALID, "bad-txns-vpub_old-toolarge");
|
||||
}
|
||||
|
||||
if (pour.vpub_new > MAX_MONEY) {
|
||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_new too high"),
|
||||
if (joinsplit.vpub_new > MAX_MONEY) {
|
||||
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new too high"),
|
||||
REJECT_INVALID, "bad-txns-vpub_new-toolarge");
|
||||
}
|
||||
|
||||
if (pour.vpub_new != 0 && pour.vpub_old != 0) {
|
||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_new and pour.vpub_old both nonzero"),
|
||||
if (joinsplit.vpub_new != 0 && joinsplit.vpub_old != 0) {
|
||||
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new and joinsplit.vpub_old both nonzero"),
|
||||
REJECT_INVALID, "bad-txns-vpubs-both-nonzero");
|
||||
}
|
||||
|
||||
nValueOut += pour.vpub_new;
|
||||
nValueOut += joinsplit.vpub_new;
|
||||
if (!MoneyRange(nValueOut)) {
|
||||
return state.DoS(100, error("CheckTransaction(): txout total out of range"),
|
||||
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
||||
|
@ -966,15 +966,15 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
|||
vInOutPoints.insert(txin.prevout);
|
||||
}
|
||||
|
||||
// Check for duplicate pour nullifiers in this transaction
|
||||
// Check for duplicate joinsplit nullifiers in this transaction
|
||||
set<uint256> vJoinSplitNullifiers;
|
||||
BOOST_FOREACH(const JSDescription& pour, tx.vjoinsplit)
|
||||
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit)
|
||||
{
|
||||
BOOST_FOREACH(const uint256& serial, pour.nullifiers)
|
||||
BOOST_FOREACH(const uint256& serial, joinsplit.nullifiers)
|
||||
{
|
||||
if (vJoinSplitNullifiers.count(serial))
|
||||
return state.DoS(100, error("CheckTransaction(): duplicate nullifiers"),
|
||||
REJECT_INVALID, "bad-pours-nullifiers-duplicate");
|
||||
REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate");
|
||||
|
||||
vJoinSplitNullifiers.insert(serial);
|
||||
}
|
||||
|
@ -982,10 +982,10 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
|||
|
||||
if (tx.IsCoinBase())
|
||||
{
|
||||
// There should be no pours in a coinbase transaction
|
||||
// There should be no joinsplits in a coinbase transaction
|
||||
if (tx.vjoinsplit.size() > 0)
|
||||
return state.DoS(100, error("CheckTransaction(): coinbase has pours"),
|
||||
REJECT_INVALID, "bad-cb-has-pours");
|
||||
return state.DoS(100, error("CheckTransaction(): coinbase has joinsplits"),
|
||||
REJECT_INVALID, "bad-cb-has-joinsplits");
|
||||
|
||||
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
|
||||
return state.DoS(100, error("CheckTransaction(): coinbase script size"),
|
||||
|
@ -1104,8 +1104,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
return false;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.nullifiers) {
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, joinsplit.nullifiers) {
|
||||
if (pool.mapNullifiers.count(serial))
|
||||
{
|
||||
return false;
|
||||
|
@ -1144,10 +1144,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),
|
||||
REJECT_DUPLICATE, "bad-txns-inputs-spent");
|
||||
|
||||
// are the pour's requirements met?
|
||||
// are the joinsplit's requirements met?
|
||||
if (!view.HaveJoinSplitRequirements(tx))
|
||||
return state.Invalid(error("AcceptToMemoryPool: pour requirements not met"),
|
||||
REJECT_DUPLICATE, "bad-txns-pour-requirements-not-met");
|
||||
return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),
|
||||
REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met");
|
||||
|
||||
// Bring the best block into scope
|
||||
view.GetBestBlock();
|
||||
|
@ -1586,8 +1586,8 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
|||
}
|
||||
|
||||
// spend nullifiers
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.nullifiers) {
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, joinsplit.nullifiers) {
|
||||
inputs.SetNullifier(serial, true);
|
||||
}
|
||||
}
|
||||
|
@ -1622,9 +1622,9 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
|
|||
if (!inputs.HaveInputs(tx))
|
||||
return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString()));
|
||||
|
||||
// are the pour's requirements met?
|
||||
// are the JoinSplit's requirements met?
|
||||
if (!inputs.HaveJoinSplitRequirements(tx))
|
||||
return state.Invalid(error("CheckInputs(): %s pour requirements not met", tx.GetHash().ToString()));
|
||||
return state.Invalid(error("CheckInputs(): %s JoinSplit requirements not met", tx.GetHash().ToString()));
|
||||
|
||||
CAmount nValueIn = 0;
|
||||
CAmount nFees = 0;
|
||||
|
@ -1908,8 +1908,8 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||
}
|
||||
|
||||
// unspend nullifiers
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.nullifiers) {
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, joinsplit.nullifiers) {
|
||||
view.SetNullifier(serial, false);
|
||||
}
|
||||
}
|
||||
|
@ -2130,10 +2130,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
|
||||
REJECT_INVALID, "bad-txns-inputs-missingorspent");
|
||||
|
||||
// are the pour's requirements met?
|
||||
// are the JoinSplit's requirements met?
|
||||
if (!view.HaveJoinSplitRequirements(tx))
|
||||
return state.DoS(100, error("ConnectBlock(): pour requirements not met"),
|
||||
REJECT_INVALID, "bad-txns-pour-requirements-not-met");
|
||||
return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"),
|
||||
REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met");
|
||||
|
||||
// Add in sigops done by pay-to-script-hash inputs;
|
||||
// this is to prevent a "rogue miner" from creating
|
||||
|
@ -2157,8 +2157,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
}
|
||||
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
|
||||
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &bucket_commitment, pour.commitments) {
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &bucket_commitment, joinsplit.commitments) {
|
||||
// Insert the bucket commitments into our temporary tree.
|
||||
|
||||
tree.append(bucket_commitment);
|
||||
|
@ -4733,7 +4733,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
BOOST_FOREACH(uint256 hash, vEraseQueue)
|
||||
EraseOrphanTx(hash);
|
||||
}
|
||||
// TODO: currently, prohibit pours from entering mapOrphans
|
||||
// TODO: currently, prohibit joinsplits from entering mapOrphans
|
||||
else if (fMissingInputs && tx.vjoinsplit.size() == 0)
|
||||
{
|
||||
AddOrphanTx(tx, pfrom->GetId());
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
CAmount vpub_old;
|
||||
CAmount vpub_new;
|
||||
|
||||
// Pours are always anchored to a root in the bucket
|
||||
// JoinSplits are always anchored to a root in the bucket
|
||||
// commitment tree at some point in the blockchain
|
||||
// history or in the history of the current
|
||||
// transaction.
|
||||
|
@ -39,7 +39,7 @@ public:
|
|||
|
||||
// Bucket commitments are introduced into the commitment
|
||||
// tree, blinding the public about the values and
|
||||
// destinations involved in the Pour. The presence of a
|
||||
// destinations involved in the JoinSplit. The presence of a
|
||||
// commitment in the bucket commitment tree is required
|
||||
// to spend it.
|
||||
boost::array<uint256, ZC_NUM_JS_OUTPUTS> commitments;
|
||||
|
@ -57,12 +57,12 @@ public:
|
|||
uint256 randomSeed;
|
||||
|
||||
// MACs
|
||||
// The verification of the pour requires these MACs
|
||||
// The verification of the JoinSplit requires these MACs
|
||||
// to be provided as an input.
|
||||
boost::array<uint256, ZC_NUM_JS_INPUTS> macs;
|
||||
|
||||
// Pour proof
|
||||
// This is a zk-SNARK which ensures that this pour is valid.
|
||||
// JoinSplit proof
|
||||
// This is a zk-SNARK which ensures that this JoinSplit is valid.
|
||||
boost::array<unsigned char, ZKSNARK_PROOF_SIZE> proof;
|
||||
|
||||
JSDescription(): vpub_old(0), vpub_new(0) { }
|
||||
|
@ -76,7 +76,7 @@ public:
|
|||
CAmount vpub_new
|
||||
);
|
||||
|
||||
// Verifies that the pour proof is correct.
|
||||
// Verifies that the JoinSplit proof is correct.
|
||||
bool Verify(ZCJoinSplit& params, const uint256& pubKeyHash) const;
|
||||
|
||||
// Returns the calculated h_sig
|
||||
|
@ -348,7 +348,7 @@ public:
|
|||
// GetValueIn() is a method on CCoinsViewCache, because
|
||||
// inputs must be known to compute value in.
|
||||
|
||||
// Return sum of pour vpub_new
|
||||
// Return sum of JoinSplit vpub_new
|
||||
CAmount GetJoinSplitValueIn() const;
|
||||
|
||||
// Compute priority, given priority of inputs and (optionally) tx size
|
||||
|
|
|
@ -92,43 +92,43 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
|
|||
|
||||
Array vjoinsplit;
|
||||
for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) {
|
||||
const JSDescription& pourtx = tx.vjoinsplit[i];
|
||||
Object pour;
|
||||
const JSDescription& jsdescription = tx.vjoinsplit[i];
|
||||
Object joinsplit;
|
||||
|
||||
pour.push_back(Pair("anchor", pourtx.anchor.GetHex()));
|
||||
joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex()));
|
||||
|
||||
{
|
||||
Array nullifiers;
|
||||
BOOST_FOREACH(const uint256 serial, pourtx.nullifiers) {
|
||||
BOOST_FOREACH(const uint256 serial, jsdescription.nullifiers) {
|
||||
nullifiers.push_back(serial.GetHex());
|
||||
}
|
||||
pour.push_back(Pair("nullifiers", nullifiers));
|
||||
joinsplit.push_back(Pair("nullifiers", nullifiers));
|
||||
}
|
||||
|
||||
{
|
||||
Array commitments;
|
||||
BOOST_FOREACH(const uint256 commitment, pourtx.commitments) {
|
||||
BOOST_FOREACH(const uint256 commitment, jsdescription.commitments) {
|
||||
commitments.push_back(commitment.GetHex());
|
||||
}
|
||||
pour.push_back(Pair("commitments", commitments));
|
||||
joinsplit.push_back(Pair("commitments", commitments));
|
||||
}
|
||||
|
||||
{
|
||||
Array macs;
|
||||
BOOST_FOREACH(const uint256 mac, pourtx.macs) {
|
||||
BOOST_FOREACH(const uint256 mac, jsdescription.macs) {
|
||||
macs.push_back(mac.GetHex());
|
||||
}
|
||||
pour.push_back(Pair("macs", macs));
|
||||
joinsplit.push_back(Pair("macs", macs));
|
||||
}
|
||||
|
||||
pour.push_back(Pair("vpub_old", ValueFromAmount(pourtx.vpub_old)));
|
||||
pour.push_back(Pair("vpub_new", ValueFromAmount(pourtx.vpub_new)));
|
||||
joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old)));
|
||||
joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new)));
|
||||
|
||||
// TODO: #808
|
||||
uint256 pubKeyHash;
|
||||
pour.push_back(Pair("valid", pourtx.Verify(*pzcashParams, pubKeyHash)));
|
||||
joinsplit.push_back(Pair("valid", jsdescription.Verify(*pzcashParams, pubKeyHash)));
|
||||
|
||||
vjoinsplit.push_back(pour);
|
||||
vjoinsplit.push_back(joinsplit);
|
||||
}
|
||||
|
||||
entry.push_back(Pair("vjoinsplit", vjoinsplit));
|
||||
|
|
|
@ -379,7 +379,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||
{ "wallet", "walletpassphrase", &walletpassphrase, true },
|
||||
{ "wallet", "zcbenchmark", &zc_benchmark, true },
|
||||
{ "wallet", "zcrawkeygen", &zc_raw_keygen, true },
|
||||
{ "wallet", "zcrawpour", &zc_raw_pour, true },
|
||||
{ "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true },
|
||||
{ "wallet", "zcrawreceive", &zc_raw_receive, true }
|
||||
#endif // ENABLE_WALLET
|
||||
};
|
||||
|
|
|
@ -210,7 +210,7 @@ extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHe
|
|||
extern json_spirit::Value resendwallettransactions(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value zc_benchmark(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value zc_raw_keygen(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value zc_raw_pour(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value zc_raw_joinsplit(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value zc_raw_receive(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
|
||||
|
|
|
@ -291,9 +291,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
|||
return dummyTransactions;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_basic_pour_verification)
|
||||
BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
|
||||
{
|
||||
// We only check that pours are constructed properly
|
||||
// We only check that joinsplits are constructed properly
|
||||
// and verify properly here. libsnark tends to segfault
|
||||
// when our snarks or what-have-you are invalid, so
|
||||
// we can't really catch everything here.
|
||||
|
@ -342,17 +342,17 @@ BOOST_AUTO_TEST_CASE(test_basic_pour_verification)
|
|||
};
|
||||
|
||||
{
|
||||
JSDescription pourtx(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
|
||||
BOOST_CHECK(pourtx.Verify(*p, pubKeyHash));
|
||||
JSDescription jsdesc(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
|
||||
BOOST_CHECK(jsdesc.Verify(*p, pubKeyHash));
|
||||
|
||||
CDataStream ss(SER_DISK, CLIENT_VERSION);
|
||||
ss << pourtx;
|
||||
ss << jsdesc;
|
||||
|
||||
JSDescription pourtx_deserialized;
|
||||
ss >> pourtx_deserialized;
|
||||
JSDescription jsdesc_deserialized;
|
||||
ss >> jsdesc_deserialized;
|
||||
|
||||
BOOST_CHECK(pourtx_deserialized == pourtx);
|
||||
BOOST_CHECK(pourtx_deserialized.Verify(*p, pubKeyHash));
|
||||
BOOST_CHECK(jsdesc_deserialized == jsdesc);
|
||||
BOOST_CHECK(jsdesc_deserialized.Verify(*p, pubKeyHash));
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -371,20 +371,20 @@ BOOST_AUTO_TEST_CASE(test_basic_pour_verification)
|
|||
delete p;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
|
||||
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||
{
|
||||
CMutableTransaction tx;
|
||||
tx.nVersion = 2;
|
||||
{
|
||||
// Ensure that empty vin/vout remain invalid without
|
||||
// pours.
|
||||
// joinsplits.
|
||||
CMutableTransaction newTx(tx);
|
||||
CValidationState state;
|
||||
|
||||
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
||||
crypto_sign_keypair(newTx.joinSplitPubKey.begin(), joinSplitPrivKey);
|
||||
|
||||
// No pours, vin and vout, means it should be invalid.
|
||||
// No joinsplits, vin and vout, means it should be invalid.
|
||||
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vin-empty");
|
||||
|
||||
|
@ -394,10 +394,10 @@ BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
|
|||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vout-empty");
|
||||
|
||||
newTx.vjoinsplit.push_back(JSDescription());
|
||||
JSDescription *pourtx = &newTx.vjoinsplit[0];
|
||||
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||
|
||||
pourtx->nullifiers[0] = GetRandHash();
|
||||
pourtx->nullifiers[1] = GetRandHash();
|
||||
jsdesc->nullifiers[0] = GetRandHash();
|
||||
jsdesc->nullifiers[1] = GetRandHash();
|
||||
|
||||
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
|
||||
|
@ -418,40 +418,40 @@ BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
|
|||
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
||||
}
|
||||
{
|
||||
// Ensure that values within the pour are well-formed.
|
||||
// Ensure that values within the joinsplit are well-formed.
|
||||
CMutableTransaction newTx(tx);
|
||||
CValidationState state;
|
||||
|
||||
newTx.vjoinsplit.push_back(JSDescription());
|
||||
|
||||
JSDescription *pourtx = &newTx.vjoinsplit[0];
|
||||
pourtx->vpub_old = -1;
|
||||
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||
jsdesc->vpub_old = -1;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative");
|
||||
|
||||
pourtx->vpub_old = MAX_MONEY + 1;
|
||||
jsdesc->vpub_old = MAX_MONEY + 1;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge");
|
||||
|
||||
pourtx->vpub_old = 0;
|
||||
pourtx->vpub_new = -1;
|
||||
jsdesc->vpub_old = 0;
|
||||
jsdesc->vpub_new = -1;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative");
|
||||
|
||||
pourtx->vpub_new = MAX_MONEY + 1;
|
||||
jsdesc->vpub_new = MAX_MONEY + 1;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge");
|
||||
|
||||
pourtx->vpub_new = (MAX_MONEY / 2) + 10;
|
||||
jsdesc->vpub_new = (MAX_MONEY / 2) + 10;
|
||||
|
||||
newTx.vjoinsplit.push_back(JSDescription());
|
||||
|
||||
JSDescription *pourtx2 = &newTx.vjoinsplit[1];
|
||||
pourtx2->vpub_new = (MAX_MONEY / 2) + 10;
|
||||
JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
|
||||
jsdesc2->vpub_new = (MAX_MONEY / 2) + 10;
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-txouttotal-toolarge");
|
||||
|
@ -462,34 +462,34 @@ BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
|
|||
CValidationState state;
|
||||
|
||||
newTx.vjoinsplit.push_back(JSDescription());
|
||||
JSDescription *pourtx = &newTx.vjoinsplit[0];
|
||||
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||
|
||||
pourtx->nullifiers[0] = GetRandHash();
|
||||
pourtx->nullifiers[1] = pourtx->nullifiers[0];
|
||||
jsdesc->nullifiers[0] = GetRandHash();
|
||||
jsdesc->nullifiers[1] = jsdesc->nullifiers[0];
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-pours-nullifiers-duplicate");
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
|
||||
|
||||
pourtx->nullifiers[1] = GetRandHash();
|
||||
jsdesc->nullifiers[1] = GetRandHash();
|
||||
|
||||
newTx.vjoinsplit.push_back(JSDescription());
|
||||
JSDescription *pourtx2 = &newTx.vjoinsplit[1];
|
||||
JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
|
||||
|
||||
pourtx2->nullifiers[0] = GetRandHash();
|
||||
pourtx2->nullifiers[1] = pourtx->nullifiers[0];
|
||||
jsdesc2->nullifiers[0] = GetRandHash();
|
||||
jsdesc2->nullifiers[1] = jsdesc->nullifiers[0];
|
||||
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-pours-nullifiers-duplicate");
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
|
||||
}
|
||||
{
|
||||
// Ensure that coinbase transactions do not have pours.
|
||||
// Ensure that coinbase transactions do not have joinsplits.
|
||||
CMutableTransaction newTx(tx);
|
||||
CValidationState state;
|
||||
|
||||
newTx.vjoinsplit.push_back(JSDescription());
|
||||
JSDescription *pourtx = &newTx.vjoinsplit[0];
|
||||
pourtx->nullifiers[0] = GetRandHash();
|
||||
pourtx->nullifiers[1] = GetRandHash();
|
||||
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||
jsdesc->nullifiers[0] = GetRandHash();
|
||||
jsdesc->nullifiers[1] = GetRandHash();
|
||||
|
||||
newTx.vin.push_back(CTxIn(uint256(), -1));
|
||||
|
||||
|
@ -498,7 +498,7 @@ BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
|
|||
BOOST_CHECK(finalNewTx.IsCoinBase());
|
||||
}
|
||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-pours");
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,8 +99,8 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
|||
const CTransaction& tx = mapTx[hash].GetTx();
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.nullifiers) {
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, joinsplit.nullifiers) {
|
||||
mapNullifiers[serial] = &tx;
|
||||
}
|
||||
}
|
||||
|
@ -148,8 +148,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
|
|||
}
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
mapNextTx.erase(txin.prevout);
|
||||
BOOST_FOREACH(const JSDescription& pour, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256& serial, pour.nullifiers) {
|
||||
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256& serial, joinsplit.nullifiers) {
|
||||
mapNullifiers.erase(serial);
|
||||
}
|
||||
}
|
||||
|
@ -200,8 +200,8 @@ void CTxMemPool::removeWithAnchor(const uint256 &invalidRoot)
|
|||
|
||||
for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
|
||||
const CTransaction& tx = it->second.GetTx();
|
||||
BOOST_FOREACH(const JSDescription& pour, tx.vjoinsplit) {
|
||||
if (pour.anchor == invalidRoot) {
|
||||
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) {
|
||||
if (joinsplit.anchor == invalidRoot) {
|
||||
transactionsToRemove.push_back(tx);
|
||||
break;
|
||||
}
|
||||
|
@ -230,8 +230,8 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.nullifiers) {
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, joinsplit.nullifiers) {
|
||||
std::map<uint256, const CTransaction*>::iterator it = mapNullifiers.find(serial);
|
||||
if (it != mapNullifiers.end()) {
|
||||
const CTransaction &txConflict = *it->second;
|
||||
|
@ -317,20 +317,20 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
|||
|
||||
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
|
||||
|
||||
BOOST_FOREACH(const JSDescription &pour, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, pour.nullifiers) {
|
||||
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||
BOOST_FOREACH(const uint256 &serial, joinsplit.nullifiers) {
|
||||
assert(!pcoins->GetNullifier(serial));
|
||||
}
|
||||
|
||||
ZCIncrementalMerkleTree tree;
|
||||
auto it = intermediates.find(pour.anchor);
|
||||
auto it = intermediates.find(joinsplit.anchor);
|
||||
if (it != intermediates.end()) {
|
||||
tree = it->second;
|
||||
} else {
|
||||
assert(pcoins->GetAnchorAt(pour.anchor, tree));
|
||||
assert(pcoins->GetAnchorAt(joinsplit.anchor, tree));
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const uint256& commitment, pour.commitments)
|
||||
BOOST_FOREACH(const uint256& commitment, joinsplit.commitments)
|
||||
{
|
||||
tree.append(commitment);
|
||||
}
|
||||
|
|
|
@ -2521,7 +2521,7 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
|
|||
|
||||
|
||||
|
||||
Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||
Value zc_raw_joinsplit(const json_spirit::Array& params, bool fHelp)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(fHelp)) {
|
||||
return Value::null;
|
||||
|
@ -2529,11 +2529,11 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
|
||||
if (fHelp || params.size() != 5) {
|
||||
throw runtime_error(
|
||||
"zcrawpour rawtx inputs outputs vpub_old vpub_new\n"
|
||||
"zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
|
||||
" inputs: a JSON object mapping {bucket: zcsecretkey, ...}\n"
|
||||
" outputs: a JSON object mapping {zcaddr: value, ...}\n"
|
||||
"\n"
|
||||
"Splices a Pour into rawtx. Inputs are unilaterally confidential.\n"
|
||||
"Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
|
||||
"Outputs are confidential between sender/receiver. The vpub_old and\n"
|
||||
"vpub_new values are globally public and move transparent value into\n"
|
||||
"or out of the confidential value store, respectively.\n"
|
||||
|
@ -2569,8 +2569,8 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
if (params[4].get_real() != 0.0)
|
||||
vpub_new = AmountFromValue(params[4]);
|
||||
|
||||
std::vector<JSInput> vpourin;
|
||||
std::vector<JSOutput> vpourout;
|
||||
std::vector<JSInput> vjsin;
|
||||
std::vector<JSOutput> vjsout;
|
||||
std::vector<Note> notes;
|
||||
std::vector<SpendingKey> keys;
|
||||
std::vector<uint256> commitments;
|
||||
|
@ -2606,16 +2606,16 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
for (size_t i = 0; i < witnesses.size(); i++) {
|
||||
if (!witnesses[i]) {
|
||||
throw runtime_error(
|
||||
"pour input could not be found in tree"
|
||||
"joinsplit input could not be found in tree"
|
||||
);
|
||||
}
|
||||
|
||||
vpourin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
|
||||
vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
|
||||
}
|
||||
}
|
||||
|
||||
while (vpourin.size() < ZC_NUM_JS_INPUTS) {
|
||||
vpourin.push_back(JSInput());
|
||||
while (vjsin.size() < ZC_NUM_JS_INPUTS) {
|
||||
vjsin.push_back(JSInput());
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Pair& s, outputs)
|
||||
|
@ -2624,16 +2624,16 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
PaymentAddress addrTo = pubaddr.Get();
|
||||
CAmount nAmount = AmountFromValue(s.value_);
|
||||
|
||||
vpourout.push_back(JSOutput(addrTo, nAmount));
|
||||
vjsout.push_back(JSOutput(addrTo, nAmount));
|
||||
}
|
||||
|
||||
while (vpourout.size() < ZC_NUM_JS_OUTPUTS) {
|
||||
vpourout.push_back(JSOutput());
|
||||
while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
|
||||
vjsout.push_back(JSOutput());
|
||||
}
|
||||
|
||||
// TODO
|
||||
if (vpourout.size() != ZC_NUM_JS_INPUTS || vpourin.size() != ZC_NUM_JS_OUTPUTS) {
|
||||
throw runtime_error("unsupported pour input/output counts");
|
||||
if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
|
||||
throw runtime_error("unsupported joinsplit input/output counts");
|
||||
}
|
||||
|
||||
uint256 joinSplitPubKey;
|
||||
|
@ -2644,17 +2644,17 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
mtx.nVersion = 2;
|
||||
mtx.joinSplitPubKey = joinSplitPubKey;
|
||||
|
||||
JSDescription pourtx(*pzcashParams,
|
||||
JSDescription jsdescription(*pzcashParams,
|
||||
joinSplitPubKey,
|
||||
anchor,
|
||||
{vpourin[0], vpourin[1]},
|
||||
{vpourout[0], vpourout[1]},
|
||||
{vjsin[0], vjsin[1]},
|
||||
{vjsout[0], vjsout[1]},
|
||||
vpub_old,
|
||||
vpub_new);
|
||||
|
||||
assert(pourtx.Verify(*pzcashParams, joinSplitPubKey));
|
||||
assert(jsdescription.Verify(*pzcashParams, joinSplitPubKey));
|
||||
|
||||
mtx.vjoinsplit.push_back(pourtx);
|
||||
mtx.vjoinsplit.push_back(jsdescription);
|
||||
|
||||
// TODO: #966.
|
||||
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||
|
@ -2688,18 +2688,18 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
{
|
||||
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss2 << ((unsigned char) 0x00);
|
||||
ss2 << pourtx.ephemeralKey;
|
||||
ss2 << pourtx.ciphertexts[0];
|
||||
ss2 << pourtx.h_sig(*pzcashParams, joinSplitPubKey);
|
||||
ss2 << jsdescription.ephemeralKey;
|
||||
ss2 << jsdescription.ciphertexts[0];
|
||||
ss2 << jsdescription.h_sig(*pzcashParams, joinSplitPubKey);
|
||||
|
||||
encryptedBucket1 = HexStr(ss2.begin(), ss2.end());
|
||||
}
|
||||
{
|
||||
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss2 << ((unsigned char) 0x01);
|
||||
ss2 << pourtx.ephemeralKey;
|
||||
ss2 << pourtx.ciphertexts[1];
|
||||
ss2 << pourtx.h_sig(*pzcashParams, joinSplitPubKey);
|
||||
ss2 << jsdescription.ephemeralKey;
|
||||
ss2 << jsdescription.ciphertexts[1];
|
||||
ss2 << jsdescription.h_sig(*pzcashParams, joinSplitPubKey);
|
||||
|
||||
encryptedBucket2 = HexStr(ss2.begin(), ss2.end());
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ double benchmark_create_joinsplit()
|
|||
uint256 anchor = ZCIncrementalMerkleTree().root();
|
||||
|
||||
timer_start();
|
||||
JSDescription pourtx(*pzcashParams,
|
||||
JSDescription jsdescription(*pzcashParams,
|
||||
pubKeyHash,
|
||||
anchor,
|
||||
{JSInput(), JSInput()},
|
||||
|
@ -85,7 +85,7 @@ double benchmark_create_joinsplit()
|
|||
0);
|
||||
double ret = timer_stop();
|
||||
|
||||
assert(pourtx.Verify(*pzcashParams, pubKeyHash));
|
||||
assert(jsdescription.Verify(*pzcashParams, pubKeyHash));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue