Auto merge of #1090 - ebfull:rename-pour-and-serial, r=ebfull

Rename things to match protocol specification

This is a pass through the code to eliminate usage of "pour" and "serial" and any other outdated terminology.

Closes #602
This commit is contained in:
zkbot 2016-07-18 19:58:25 +00:00
commit 4d459f93a4
26 changed files with 512 additions and 512 deletions

View File

@ -27,8 +27,8 @@ testScripts=(
'merkle_blocks.py'
'signrawtransactions.py'
'walletbackup.py'
'zcpour.py'
'zcpourdoublespend.py'
'zcjoinsplit.py'
'zcjoinsplitdoublespend.py'
);
testScriptsExt=(
'bipdersig-p2p.py'

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python2
#
# Test Pour semantics
# Test joinsplit semantics
#
from test_framework.test_framework import BitcoinTestFramework
@ -11,7 +11,7 @@ import os
import shutil
import sys
class PourTxTest(BitcoinTestFramework):
class JoinSplitTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
self.is_network_split = False
@ -24,27 +24,27 @@ 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)
joinsplit_result = self.nodes[0].zcrawjoinsplit(protect_tx, {}, {zcaddress:39.9}, 39.9, 0)
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, pour_result["encryptedbucket1"])
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
assert_equal(receive_result["exists"], False)
protect_tx = self.nodes[0].signrawtransaction(pour_result["rawtxn"])
protect_tx = self.nodes[0].signrawtransaction(joinsplit_result["rawtxn"])
self.nodes[0].sendrawtransaction(protect_tx["hex"])
self.nodes[0].generate(1)
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, pour_result["encryptedbucket1"])
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
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)
joinsplit_tx = self.nodes[0].createrawtransaction([], {})
joinsplit_result = self.nodes[0].zcrawjoinsplit(joinsplit_tx, {receive_result["note"] : zcsecretkey}, {zcaddress: 39.8}, 0, 0.1)
self.nodes[0].sendrawtransaction(pour_result["rawtxn"])
self.nodes[0].sendrawtransaction(joinsplit_result["rawtxn"])
self.nodes[0].generate(1)
print "Done!"
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, pour_result["encryptedbucket1"])
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
assert_equal(receive_result["exists"], True)
if __name__ == '__main__':
PourTxTest().main()
JoinSplitTest().main()

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python2
#
# Tests a Pour double-spend and a subsequent reorg.
# Tests a joinsplit double-spend and a subsequent reorg.
#
from test_framework.test_framework import BitcoinTestFramework
@ -12,10 +12,10 @@ import shutil
import sys
import time
class PourTxTest(BitcoinTestFramework):
class JoinSplitTest(BitcoinTestFramework):
def setup_network(self):
# Start with split network:
return super(PourTxTest, self).setup_network(True)
return super(JoinSplitTest, self).setup_network(True)
def txid_in_mempool(self, node, txid):
exception_triggered = False
@ -27,7 +27,7 @@ class PourTxTest(BitcoinTestFramework):
return not exception_triggered
def cannot_pour(self, node, txn):
def cannot_joinsplit(self, node, txn):
exception_triggered = False
try:
@ -37,8 +37,8 @@ class PourTxTest(BitcoinTestFramework):
return exception_triggered
def expect_cannot_pour(self, node, txn):
assert_equal(self.cannot_pour(node, txn), True)
def expect_cannot_joinsplit(self, node, txn):
assert_equal(self.cannot_joinsplit(node, txn), True)
def run_test(self):
# All nodes should start with 250 BTC:
@ -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
@ -64,54 +64,54 @@ class PourTxTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.nodes[2].sendrawtransaction(signed["hex"])
self.nodes[2].generate(1)
pool[i] = pool[i]["encryptedbucket1"]
pool[i] = pool[i]["encryptednote1"]
sync_blocks(self.nodes[0:2])
sync_blocks(self.nodes[2:4])
# Confirm that the protects have taken place
for i in range(4):
enc_bucket = pool[i]
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, enc_bucket)
enc_note = pool[i]
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, enc_note)
assert_equal(receive_result["exists"], True)
pool[i] = receive_result["bucket"]
pool[i] = receive_result["note"]
# Extra confirmations
receive_result = self.nodes[1].zcrawreceive(zcsecretkey, enc_bucket)
receive_result = self.nodes[1].zcrawreceive(zcsecretkey, enc_note)
assert_equal(receive_result["exists"], True)
receive_result = self.nodes[2].zcrawreceive(zcsecretkey, enc_bucket)
receive_result = self.nodes[2].zcrawreceive(zcsecretkey, enc_note)
assert_equal(receive_result["exists"], True)
receive_result = self.nodes[3].zcrawreceive(zcsecretkey, enc_bucket)
receive_result = self.nodes[3].zcrawreceive(zcsecretkey, enc_note)
assert_equal(receive_result["exists"], True)
blank_tx = self.nodes[0].createrawtransaction([], {})
# Create pour {A, B}->{*}
pour_AB = self.nodes[0].zcrawpour(blank_tx,
{pool[0] : zcsecretkey, pool[1] : zcsecretkey},
{zcaddress:(39.9*2)-0.1},
0, 0.1)
# Create joinsplit {A, B}->{*}
joinsplit_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,
{pool[1] : zcsecretkey, pool[2] : zcsecretkey},
{zcaddress:(39.9*2)-0.1},
0, 0.1)
# Create joinsplit {B, C}->{*}
joinsplit_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,
{pool[2] : zcsecretkey, pool[3] : zcsecretkey},
{zcaddress:(39.9*2)-0.1},
0, 0.1)
# Create joinsplit {C, D}->{*}
joinsplit_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,
{pool[0] : zcsecretkey, pool[3] : zcsecretkey},
{zcaddress:(39.9*2)-0.1},
0, 0.1)
# Create joinsplit {A, D}->{*}
joinsplit_AD = self.nodes[0].zcrawjoinsplit(blank_tx,
{pool[0] : zcsecretkey, pool[3] : zcsecretkey},
{zcaddress:(39.9*2)-0.1},
0, 0.1)
# (a) Node 0 will spend pour AB, then attempt to
# (a) Node 0 will spend joinsplit AB, then attempt to
# double-spend it with BC. It should fail before and
# after Node 0 mines blocks.
#
@ -126,9 +126,9 @@ class PourTxTest(BitcoinTestFramework):
# (a)
AB_txid = self.nodes[0].sendrawtransaction(pour_AB["rawtxn"])
AB_txid = self.nodes[0].sendrawtransaction(joinsplit_AB["rawtxn"])
self.expect_cannot_pour(self.nodes[0], pour_BC["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"])
# Wait until node[1] receives AB before we attempt to double-spend
# with BC.
@ -139,17 +139,17 @@ class PourTxTest(BitcoinTestFramework):
time.sleep(0.2)
print "Done!\n"
self.expect_cannot_pour(self.nodes[1], pour_BC["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"])
# Generate a block
self.nodes[0].generate(1)
sync_blocks(self.nodes[0:2])
self.expect_cannot_pour(self.nodes[0], pour_BC["rawtxn"])
self.expect_cannot_pour(self.nodes[1], pour_BC["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"])
# (b)
self.nodes[2].sendrawtransaction(pour_BC["rawtxn"])
self.nodes[2].sendrawtransaction(joinsplit_BC["rawtxn"])
self.nodes[2].generate(5)
# Connect the two nodes
@ -158,26 +158,26 @@ class PourTxTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# AB and CD should all be impossible to spend for each node.
self.expect_cannot_pour(self.nodes[0], pour_AB["rawtxn"])
self.expect_cannot_pour(self.nodes[0], pour_CD["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_AB["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_CD["rawtxn"])
self.expect_cannot_pour(self.nodes[1], pour_AB["rawtxn"])
self.expect_cannot_pour(self.nodes[1], pour_CD["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_AB["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_CD["rawtxn"])
self.expect_cannot_pour(self.nodes[2], pour_AB["rawtxn"])
self.expect_cannot_pour(self.nodes[2], pour_CD["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[2], joinsplit_AB["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[2], joinsplit_CD["rawtxn"])
self.expect_cannot_pour(self.nodes[3], pour_AB["rawtxn"])
self.expect_cannot_pour(self.nodes[3], pour_CD["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[3], joinsplit_AB["rawtxn"])
self.expect_cannot_joinsplit(self.nodes[3], joinsplit_CD["rawtxn"])
# (c)
# AD should be possible to send due to the reorg that
# tossed out AB.
self.nodes[0].sendrawtransaction(pour_AD["rawtxn"])
self.nodes[0].sendrawtransaction(joinsplit_AD["rawtxn"])
self.nodes[0].generate(1)
sync_blocks(self.nodes)
if __name__ == '__main__':
PourTxTest().main()
JoinSplitTest().main()

View File

@ -41,7 +41,7 @@ bool CCoins::Spend(uint32_t nPos)
return true;
}
bool CCoinsView::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; }
bool CCoinsView::GetSerial(const uint256 &serial) const { return false; }
bool CCoinsView::GetNullifier(const uint256 &nullifier) const { return false; }
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
@ -50,14 +50,14 @@ bool CCoinsView::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CSerialsMap &mapSerials) { return false; }
CNullifiersMap &mapNullifiers) { return false; }
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetSerial(const uint256 &serial) const { return base->GetSerial(serial); }
bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
@ -67,7 +67,7 @@ bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CSerialsMap &mapSerials) { return base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapSerials); }
CNullifiersMap &mapNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapNullifiers); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
@ -82,7 +82,7 @@ CCoinsViewCache::~CCoinsViewCache()
size_t CCoinsViewCache::DynamicMemoryUsage() const {
return memusage::DynamicUsage(cacheCoins) +
memusage::DynamicUsage(cacheAnchors) +
memusage::DynamicUsage(cacheSerials) +
memusage::DynamicUsage(cacheNullifiers) +
cachedCoinsUsage;
}
@ -128,16 +128,16 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr
return true;
}
bool CCoinsViewCache::GetSerial(const uint256 &serial) const {
CSerialsMap::iterator it = cacheSerials.find(serial);
if (it != cacheSerials.end())
bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
CNullifiersMap::iterator it = cacheNullifiers.find(nullifier);
if (it != cacheNullifiers.end())
return it->second.entered;
CSerialsCacheEntry entry;
bool tmp = base->GetSerial(serial);
CNullifiersCacheEntry entry;
bool tmp = base->GetNullifier(nullifier);
entry.entered = tmp;
cacheSerials.insert(std::make_pair(serial, entry));
cacheNullifiers.insert(std::make_pair(nullifier, entry));
return tmp;
}
@ -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) {
@ -185,10 +185,10 @@ void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
}
}
void CCoinsViewCache::SetSerial(const uint256 &serial, bool spent) {
std::pair<CSerialsMap::iterator, bool> ret = cacheSerials.insert(std::make_pair(serial, CSerialsCacheEntry()));
void CCoinsViewCache::SetNullifier(const uint256 &nullifier, bool spent) {
std::pair<CNullifiersMap::iterator, bool> ret = cacheNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry()));
ret.first->second.entered = spent;
ret.first->second.flags |= CSerialsCacheEntry::DIRTY;
ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
}
bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
@ -260,7 +260,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlockIn,
const uint256 &hashAnchorIn,
CAnchorsMap &mapAnchors,
CSerialsMap &mapSerials) {
CNullifiersMap &mapNullifiers) {
assert(!hasModifier);
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
@ -326,29 +326,29 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
mapAnchors.erase(itOld);
}
for (CSerialsMap::iterator child_it = mapSerials.begin(); child_it != mapSerials.end();)
for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();)
{
if (child_it->second.flags & CSerialsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
CSerialsMap::iterator parent_it = cacheSerials.find(child_it->first);
if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
if (parent_it == cacheSerials.end()) {
if (parent_it == cacheNullifiers.end()) {
if (child_it->second.entered) {
// Parent doesn't have an entry, but child has a SPENT serial.
// Move the spent serial up.
// Parent doesn't have an entry, but child has a SPENT nullifier.
// Move the spent nullifier up.
CSerialsCacheEntry& entry = cacheSerials[child_it->first];
CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
entry.entered = true;
entry.flags = CSerialsCacheEntry::DIRTY;
entry.flags = CNullifiersCacheEntry::DIRTY;
}
} else {
if (parent_it->second.entered != child_it->second.entered) {
parent_it->second.entered = child_it->second.entered;
parent_it->second.flags |= CSerialsCacheEntry::DIRTY;
parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
}
}
}
CSerialsMap::iterator itOld = child_it++;
mapSerials.erase(itOld);
CNullifiersMap::iterator itOld = child_it++;
mapNullifiers.erase(itOld);
}
hashAnchor = hashAnchorIn;
@ -357,10 +357,10 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
}
bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheSerials);
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheNullifiers);
cacheCoins.clear();
cacheAnchors.clear();
cacheSerials.clear();
cacheNullifiers.clear();
cachedCoinsUsage = 0;
return fOk;
}
@ -385,35 +385,35 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
for (unsigned int i = 0; i < tx.vin.size(); i++)
nResult += GetOutputFor(tx.vin[i]).nValue;
nResult += tx.GetPourValueIn();
nResult += tx.GetJoinSplitValueIn();
return nResult;
}
bool CCoinsViewCache::HavePourRequirements(const CTransaction& tx) const
bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
{
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
BOOST_FOREACH(const CPourTx &pour, tx.vpour)
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit)
{
BOOST_FOREACH(const uint256& serial, pour.serials)
BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers)
{
if (GetSerial(serial)) {
// If the serial is set, this transaction
if (GetNullifier(nullifier)) {
// If the nullifier is set, this transaction
// double-spends!
return false;
}
}
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);
}

View File

@ -309,21 +309,21 @@ struct CAnchorsCacheEntry
CAnchorsCacheEntry() : entered(false), flags(0) {}
};
struct CSerialsCacheEntry
struct CNullifiersCacheEntry
{
bool entered; // If the serial is spent or not
bool entered; // If the nullifier is spent or not
unsigned char flags;
enum Flags {
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
};
CSerialsCacheEntry() : entered(false), flags(0) {}
CNullifiersCacheEntry() : entered(false), flags(0) {}
};
typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
typedef boost::unordered_map<uint256, CAnchorsCacheEntry, CCoinsKeyHasher> CAnchorsMap;
typedef boost::unordered_map<uint256, CSerialsCacheEntry, CCoinsKeyHasher> CSerialsMap;
typedef boost::unordered_map<uint256, CNullifiersCacheEntry, CCoinsKeyHasher> CNullifiersMap;
struct CCoinsStats
{
@ -346,8 +346,8 @@ public:
//! Retrieve the tree at a particular anchored root in the chain
virtual bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
//! Determine whether a serial is spent or not
virtual bool GetSerial(const uint256 &serial) const;
//! Determine whether a nullifier is spent or not
virtual bool GetNullifier(const uint256 &nullifier) const;
//! Retrieve the CCoins (unspent transaction outputs) for a given txid
virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
@ -368,7 +368,7 @@ public:
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CSerialsMap &mapSerials);
CNullifiersMap &mapNullifiers);
//! Calculate statistics about the unspent transaction output set
virtual bool GetStats(CCoinsStats &stats) const;
@ -387,7 +387,7 @@ protected:
public:
CCoinsViewBacked(CCoinsView *viewIn);
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetSerial(const uint256 &serial) const;
bool GetNullifier(const uint256 &nullifier) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
@ -397,7 +397,7 @@ public:
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CSerialsMap &mapSerials);
CNullifiersMap &mapNullifiers);
bool GetStats(CCoinsStats &stats) const;
};
@ -440,7 +440,7 @@ protected:
mutable CCoinsMap cacheCoins;
mutable uint256 hashAnchor;
mutable CAnchorsMap cacheAnchors;
mutable CSerialsMap cacheSerials;
mutable CNullifiersMap cacheNullifiers;
/* Cached dynamic memory usage for the inner CCoins objects. */
mutable size_t cachedCoinsUsage;
@ -451,7 +451,7 @@ public:
// Standard CCoinsView methods
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetSerial(const uint256 &serial) const;
bool GetNullifier(const uint256 &nullifier) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
@ -461,7 +461,7 @@ public:
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CSerialsMap &mapSerials);
CNullifiersMap &mapNullifiers);
// Adds the tree to mapAnchors and sets the current commitment
@ -472,8 +472,8 @@ public:
// the new current root.
void PopAnchor(const uint256 &rt);
// Marks a serial as spent or not.
void SetSerial(const uint256 &serial, bool spent);
// Marks a nullifier as spent or not.
void SetNullifier(const uint256 &nullifier, bool spent);
/**
* Return a pointer to CCoins in the cache, or NULL if not found. This is
@ -515,8 +515,8 @@ 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
bool HavePourRequirements(const CTransaction& tx) const;
//! Check whether all joinsplit requirements (anchors/nullifiers) are satisfied
bool HaveJoinSplitRequirements(const CTransaction& tx) const;
//! Return priority of tx at height nHeight
double GetPriority(const CTransaction &tx, int nHeight) const;

View File

@ -11,15 +11,15 @@ TEST(checktransaction_tests, check_vpub_not_both_nonzero) {
tx.nVersion = 2;
{
// Ensure that values within the pour are well-formed.
// Ensure that values within the joinsplit are well-formed.
CMutableTransaction newTx(tx);
CValidationState state;
newTx.vpour.push_back(CPourTx());
newTx.vjoinsplit.push_back(JSDescription());
CPourTx *pourtx = &newTx.vpour[0];
pourtx->vpub_old = 1;
pourtx->vpub_new = 1;
JSDescription *jsdesc = &newTx.vjoinsplit[0];
jsdesc->vpub_old = 1;
jsdesc->vpub_new = 1;
EXPECT_FALSE(CheckTransactionWithoutProofVerification(newTx, state));
EXPECT_EQ(state.GetRejectReason(), "bad-txns-vpubs-both-nonzero");
@ -55,11 +55,11 @@ CMutableTransaction GetValidTransaction() {
// mtx.vout[0].scriptPubKey =
mtx.vout[0].nValue = 0;
mtx.vout[1].nValue = 0;
mtx.vpour.resize(2);
mtx.vpour[0].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
mtx.vpour[0].serials.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
mtx.vpour[1].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
mtx.vpour[1].serials.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
mtx.vjoinsplit.resize(2);
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
mtx.vjoinsplit[0].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
mtx.vjoinsplit[1].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
// Generate an ephemeral keypair.
@ -96,7 +96,7 @@ TEST(checktransaction_tests, valid_transaction) {
TEST(checktransaction_tests, bad_txns_vin_empty) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour.resize(0);
mtx.vjoinsplit.resize(0);
mtx.vin.resize(0);
CTransaction tx(mtx);
@ -107,7 +107,7 @@ TEST(checktransaction_tests, bad_txns_vin_empty) {
TEST(checktransaction_tests, bad_txns_vout_empty) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour.resize(0);
mtx.vjoinsplit.resize(0);
mtx.vout.resize(0);
CTransaction tx(mtx);
@ -171,7 +171,7 @@ TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_outputs) {
TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_joinsplit) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vout[0].nValue = 1;
mtx.vpour[0].vpub_new = MAX_MONEY;
mtx.vjoinsplit[0].vpub_new = MAX_MONEY;
CTransaction tx(mtx);
@ -182,7 +182,7 @@ TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_joinsplit) {
TEST(checktransaction_tests, bad_txns_vpub_old_negative) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour[0].vpub_old = -1;
mtx.vjoinsplit[0].vpub_old = -1;
CTransaction tx(mtx);
@ -193,7 +193,7 @@ TEST(checktransaction_tests, bad_txns_vpub_old_negative) {
TEST(checktransaction_tests, bad_txns_vpub_new_negative) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour[0].vpub_new = -1;
mtx.vjoinsplit[0].vpub_new = -1;
CTransaction tx(mtx);
@ -204,7 +204,7 @@ TEST(checktransaction_tests, bad_txns_vpub_new_negative) {
TEST(checktransaction_tests, bad_txns_vpub_old_toolarge) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour[0].vpub_old = MAX_MONEY + 1;
mtx.vjoinsplit[0].vpub_old = MAX_MONEY + 1;
CTransaction tx(mtx);
@ -215,7 +215,7 @@ TEST(checktransaction_tests, bad_txns_vpub_old_toolarge) {
TEST(checktransaction_tests, bad_txns_vpub_new_toolarge) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour[0].vpub_new = MAX_MONEY + 1;
mtx.vjoinsplit[0].vpub_new = MAX_MONEY + 1;
CTransaction tx(mtx);
@ -226,8 +226,8 @@ TEST(checktransaction_tests, bad_txns_vpub_new_toolarge) {
TEST(checktransaction_tests, bad_txns_vpubs_both_nonzero) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour[0].vpub_old = 1;
mtx.vpour[0].vpub_new = 1;
mtx.vjoinsplit[0].vpub_old = 1;
mtx.vjoinsplit[0].vpub_new = 1;
CTransaction tx(mtx);
@ -248,43 +248,43 @@ TEST(checktransaction_tests, bad_txns_inputs_duplicate) {
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, bad_pours_serials_duplicate_same_pour) {
TEST(checktransaction_tests, bad_joinsplits_nullifiers_duplicate_same_joinsplit) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour[0].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
mtx.vpour[0].serials.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
mtx.vjoinsplit[0].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-pours-serials-duplicate", false)).Times(1);
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, bad_pours_serials_duplicate_different_pour) {
TEST(checktransaction_tests, bad_joinsplits_nullifiers_duplicate_different_joinsplit) {
CMutableTransaction mtx = GetValidTransaction();
mtx.vpour[0].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
mtx.vpour[1].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-pours-serials-duplicate", false)).Times(1);
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
TEST(checktransaction_tests, bad_cb_has_pours) {
TEST(checktransaction_tests, bad_cb_has_joinsplits) {
CMutableTransaction mtx = GetValidTransaction();
// Make it a coinbase.
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vpour.resize(1);
mtx.vjoinsplit.resize(1);
CTransaction tx(mtx);
EXPECT_TRUE(tx.IsCoinBase());
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-has-pours", false)).Times(1);
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-has-joinsplits", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
}
@ -294,7 +294,7 @@ TEST(checktransaction_tests, bad_cb_empty_scriptsig) {
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vpour.resize(0);
mtx.vjoinsplit.resize(0);
CTransaction tx(mtx);
EXPECT_TRUE(tx.IsCoinBase());

View File

@ -876,10 +876,10 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return false;
} else {
// Ensure that zk-SNARKs verify
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
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;
@ -891,11 +891,11 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
// Basic checks that don't depend on any context
// Transactions can contain empty `vin` and `vout` so long as
// `vpour` is non-empty.
if (tx.vin.empty() && tx.vpour.empty())
// `vjoinsplit` is non-empty.
if (tx.vin.empty() && tx.vjoinsplit.empty())
return state.DoS(10, error("CheckTransaction(): vin empty"),
REJECT_INVALID, "bad-txns-vin-empty");
if (tx.vout.empty() && tx.vpour.empty())
if (tx.vout.empty() && tx.vjoinsplit.empty())
return state.DoS(10, error("CheckTransaction(): vout empty"),
REJECT_INVALID, "bad-txns-vout-empty");
@ -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 CPourTx& pour, tx.vpour)
// 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,26 +966,26 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
vInOutPoints.insert(txin.prevout);
}
// Check for duplicate pour serials in this transaction
set<uint256> vPourSerials;
BOOST_FOREACH(const CPourTx& pour, tx.vpour)
// Check for duplicate joinsplit nullifiers in this transaction
set<uint256> vJoinSplitNullifiers;
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit)
{
BOOST_FOREACH(const uint256& serial, pour.serials)
BOOST_FOREACH(const uint256& nf, joinsplit.nullifiers)
{
if (vPourSerials.count(serial))
return state.DoS(100, error("CheckTransaction(): duplicate serials"),
REJECT_INVALID, "bad-pours-serials-duplicate");
if (vJoinSplitNullifiers.count(nf))
return state.DoS(100, error("CheckTransaction(): duplicate nullifiers"),
REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate");
vPourSerials.insert(serial);
vJoinSplitNullifiers.insert(nf);
}
}
if (tx.IsCoinBase())
{
// There should be no pours in a coinbase transaction
if (tx.vpour.size() > 0)
return state.DoS(100, error("CheckTransaction(): coinbase has pours"),
REJECT_INVALID, "bad-cb-has-pours");
// There should be no joinsplits in a coinbase transaction
if (tx.vjoinsplit.size() > 0)
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"),
@ -998,7 +998,7 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
return state.DoS(10, error("CheckTransaction(): prevout is null"),
REJECT_INVALID, "bad-txns-prevout-null");
if (tx.vpour.size() > 0) {
if (tx.vjoinsplit.size() > 0) {
// TODO: #966.
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
// Empty output script.
@ -1104,9 +1104,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return false;
}
}
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
if (pool.mapSerials.count(serial))
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
if (pool.mapNullifiers.count(nf))
{
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?
if (!view.HavePourRequirements(tx))
return state.Invalid(error("AcceptToMemoryPool: pour requirements not met"),
REJECT_DUPLICATE, "bad-txns-pour-requirements-not-met");
// are the joinsplit's requirements met?
if (!view.HaveJoinSplitRequirements(tx))
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();
@ -1585,10 +1585,10 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
}
}
// spend serials
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
inputs.SetSerial(serial, true);
// spend nullifiers
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
inputs.SetNullifier(nf, 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?
if (!inputs.HavePourRequirements(tx))
return state.Invalid(error("CheckInputs(): %s pour requirements not met", tx.GetHash().ToString()));
// are the JoinSplit's requirements met?
if (!inputs.HaveJoinSplitRequirements(tx))
return state.Invalid(error("CheckInputs(): %s JoinSplit requirements not met", tx.GetHash().ToString()));
CAmount nValueIn = 0;
CAmount nFees = 0;
@ -1654,7 +1654,7 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
}
nValueIn += tx.GetPourValueIn();
nValueIn += tx.GetJoinSplitValueIn();
if (!MoneyRange(nValueIn))
return state.DoS(100, error("CheckInputs(): vpub_old values out of range"),
REJECT_INVALID, "bad-txns-inputvalues-outofrange");
@ -1907,10 +1907,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
outs->Clear();
}
// unspend serials
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
view.SetSerial(serial, false);
// unspend nullifiers
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
view.SetNullifier(nf, 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?
if (!view.HavePourRequirements(tx))
return state.DoS(100, error("ConnectBlock(): pour requirements not met"),
REJECT_INVALID, "bad-txns-pour-requirements-not-met");
// are the JoinSplit's requirements met?
if (!view.HaveJoinSplitRequirements(tx))
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,11 +2157,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
}
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &bucket_commitment, pour.commitments) {
// Insert the bucket commitments into our temporary tree.
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &note_commitment, joinsplit.commitments) {
// Insert the note commitments into our temporary tree.
tree.append(bucket_commitment);
tree.append(note_commitment);
}
}
@ -4733,8 +4733,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
BOOST_FOREACH(uint256 hash, vEraseQueue)
EraseOrphanTx(hash);
}
// TODO: currently, prohibit pours from entering mapOrphans
else if (fMissingInputs && tx.vpour.size() == 0)
// TODO: currently, prohibit joinsplits from entering mapOrphans
else if (fMissingInputs && tx.vjoinsplit.size() == 0)
{
AddOrphanTx(tx, pfrom->GetId());

View File

@ -9,7 +9,7 @@
#include "tinyformat.h"
#include "utilstrencodings.h"
CPourTx::CPourTx(ZCJoinSplit& params,
JSDescription::JSDescription(ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& anchor,
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
@ -29,7 +29,7 @@ CPourTx::CPourTx(ZCJoinSplit& params,
pubKeyHash,
randomSeed,
macs,
serials,
nullifiers,
commitments,
vpub_old,
vpub_new,
@ -37,7 +37,7 @@ CPourTx::CPourTx(ZCJoinSplit& params,
);
}
bool CPourTx::Verify(
bool JSDescription::Verify(
ZCJoinSplit& params,
const uint256& pubKeyHash
) const {
@ -46,7 +46,7 @@ bool CPourTx::Verify(
pubKeyHash,
randomSeed,
macs,
serials,
nullifiers,
commitments,
vpub_old,
vpub_new,
@ -54,9 +54,9 @@ bool CPourTx::Verify(
);
}
uint256 CPourTx::h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const
uint256 JSDescription::h_sig(ZCJoinSplit& params, const uint256& pubKeyHash) const
{
return params.h_sig(randomSeed, serials, pubKeyHash);
return params.h_sig(randomSeed, nullifiers, pubKeyHash);
}
std::string COutPoint::ToString() const
@ -111,7 +111,7 @@ std::string CTxOut::ToString() const
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
vpour(tx.vpour), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
{
}
@ -126,9 +126,9 @@ void CTransaction::UpdateHash() const
*const_cast<uint256*>(&hash) = SerializeHash(*this);
}
CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), vpour(), joinSplitPubKey(), joinSplitSig() { }
CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), vjoinsplit(), joinSplitPubKey(), joinSplitSig() { }
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vpour(tx.vpour),
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vjoinsplit(tx.vjoinsplit),
joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
{
UpdateHash();
@ -139,7 +139,7 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
*const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
*const_cast<std::vector<CPourTx>*>(&vpour) = tx.vpour;
*const_cast<std::vector<JSDescription>*>(&vjoinsplit) = tx.vjoinsplit;
*const_cast<uint256*>(&joinSplitPubKey) = tx.joinSplitPubKey;
*const_cast<joinsplit_sig_t*>(&joinSplitSig) = tx.joinSplitSig;
*const_cast<uint256*>(&hash) = tx.hash;
@ -156,7 +156,7 @@ CAmount CTransaction::GetValueOut() const
throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
}
for (std::vector<CPourTx>::const_iterator it(vpour.begin()); it != vpour.end(); ++it)
for (std::vector<JSDescription>::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it)
{
// NB: vpub_old "takes" money from the value pool just as outputs do
nValueOut += it->vpub_old;
@ -167,16 +167,16 @@ CAmount CTransaction::GetValueOut() const
return nValueOut;
}
CAmount CTransaction::GetPourValueIn() const
CAmount CTransaction::GetJoinSplitValueIn() const
{
CAmount nValue = 0;
for (std::vector<CPourTx>::const_iterator it(vpour.begin()); it != vpour.end(); ++it)
for (std::vector<JSDescription>::const_iterator it(vjoinsplit.begin()); it != vjoinsplit.end(); ++it)
{
// NB: vpub_new "gives" money to the value pool just as inputs do
nValue += it->vpub_new;
if (!MoneyRange(it->vpub_new) || !MoneyRange(nValue))
throw std::runtime_error("CTransaction::GetPourValueIn(): value out of range");
throw std::runtime_error("CTransaction::GetJoinSplitValueIn(): value out of range");
}
return nValue;

View File

@ -17,7 +17,7 @@
#include "zcash/Zcash.h"
#include "zcash/JoinSplit.hpp"
class CPourTx
class JSDescription
{
public:
// These values 'enter from' and 'exit to' the value
@ -25,22 +25,22 @@ 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 note
// commitment tree at some point in the blockchain
// history or in the history of the current
// transaction.
uint256 anchor;
// Serials are used to prevent double-spends. They
// are derived from the secrets placed in the bucket
// Nullifiers are used to prevent double-spends. They
// are derived from the secrets placed in the note
// and the secret spend-authority key known by the
// spender.
boost::array<uint256, ZC_NUM_JS_INPUTS> serials;
boost::array<uint256, ZC_NUM_JS_INPUTS> nullifiers;
// Bucket commitments are introduced into the commitment
// Note commitments are introduced into the commitment
// tree, blinding the public about the values and
// destinations involved in the Pour. The presence of a
// commitment in the bucket commitment tree is required
// destinations involved in the JoinSplit. The presence of
// a commitment in the note commitment tree is required
// to spend it.
boost::array<uint256, ZC_NUM_JS_OUTPUTS> commitments;
@ -57,17 +57,17 @@ 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;
CPourTx(): vpub_old(0), vpub_new(0) { }
JSDescription(): vpub_old(0), vpub_new(0) { }
CPourTx(ZCJoinSplit& params,
JSDescription(ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& rt,
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
@ -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
@ -89,7 +89,7 @@ public:
READWRITE(vpub_old);
READWRITE(vpub_new);
READWRITE(anchor);
READWRITE(serials);
READWRITE(nullifiers);
READWRITE(commitments);
READWRITE(ephemeralKey);
READWRITE(ciphertexts);
@ -98,13 +98,13 @@ public:
READWRITE(proof);
}
friend bool operator==(const CPourTx& a, const CPourTx& b)
friend bool operator==(const JSDescription& a, const JSDescription& b)
{
return (
a.vpub_old == b.vpub_old &&
a.vpub_new == b.vpub_new &&
a.anchor == b.anchor &&
a.serials == b.serials &&
a.nullifiers == b.nullifiers &&
a.commitments == b.commitments &&
a.ephemeralKey == b.ephemeralKey &&
a.ciphertexts == b.ciphertexts &&
@ -114,7 +114,7 @@ public:
);
}
friend bool operator!=(const CPourTx& a, const CPourTx& b)
friend bool operator!=(const JSDescription& a, const JSDescription& b)
{
return !(a == b);
}
@ -303,7 +303,7 @@ public:
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;
const uint32_t nLockTime;
const std::vector<CPourTx> vpour;
const std::vector<JSDescription> vjoinsplit;
const uint256 joinSplitPubKey;
const joinsplit_sig_t joinSplitSig;
@ -325,8 +325,8 @@ public:
READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
READWRITE(*const_cast<uint32_t*>(&nLockTime));
if (nVersion >= 2) {
READWRITE(*const_cast<std::vector<CPourTx>*>(&vpour));
if (vpour.size() > 0) {
READWRITE(*const_cast<std::vector<JSDescription>*>(&vjoinsplit));
if (vjoinsplit.size() > 0) {
READWRITE(*const_cast<uint256*>(&joinSplitPubKey));
READWRITE(*const_cast<joinsplit_sig_t*>(&joinSplitSig));
}
@ -348,8 +348,8 @@ public:
// GetValueIn() is a method on CCoinsViewCache, because
// inputs must be known to compute value in.
// Return sum of pour vpub_new
CAmount GetPourValueIn() const;
// Return sum of JoinSplit vpub_new
CAmount GetJoinSplitValueIn() const;
// Compute priority, given priority of inputs and (optionally) tx size
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
@ -382,7 +382,7 @@ struct CMutableTransaction
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
uint32_t nLockTime;
std::vector<CPourTx> vpour;
std::vector<JSDescription> vjoinsplit;
uint256 joinSplitPubKey;
CTransaction::joinsplit_sig_t joinSplitSig;
@ -399,8 +399,8 @@ struct CMutableTransaction
READWRITE(vout);
READWRITE(nLockTime);
if (nVersion >= 2) {
READWRITE(vpour);
if (vpour.size() > 0) {
READWRITE(vjoinsplit);
if (vjoinsplit.size() > 0) {
READWRITE(joinSplitPubKey);
READWRITE(joinSplitSig);
}

View File

@ -91,10 +91,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "estimatepriority", 0 },
{ "prioritisetransaction", 1 },
{ "prioritisetransaction", 2 },
{ "zcrawpour", 1 },
{ "zcrawpour", 2 },
{ "zcrawpour", 3 },
{ "zcrawpour", 4 },
{ "zcrawjoinsplit", 1 },
{ "zcrawjoinsplit", 2 },
{ "zcrawjoinsplit", 3 },
{ "zcrawjoinsplit", 4 },
{ "zcbenchmark", 1 },
{ "getblocksubsidy", 0}
};

View File

@ -90,48 +90,48 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
}
entry.push_back(Pair("vout", vout));
Array vpour;
for (unsigned int i = 0; i < tx.vpour.size(); i++) {
const CPourTx& pourtx = tx.vpour[i];
Object pour;
Array vjoinsplit;
for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) {
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 serials;
BOOST_FOREACH(const uint256 serial, pourtx.serials) {
serials.push_back(serial.GetHex());
Array nullifiers;
BOOST_FOREACH(const uint256 nf, jsdescription.nullifiers) {
nullifiers.push_back(nf.GetHex());
}
pour.push_back(Pair("serials", serials));
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)));
vpour.push_back(pour);
vjoinsplit.push_back(joinsplit);
}
entry.push_back(Pair("vpour", vpour));
entry.push_back(Pair("vjoinsplit", vjoinsplit));
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));

View File

@ -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
};

View File

@ -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

View File

@ -1072,7 +1072,7 @@ public:
// Serialize nLockTime
::Serialize(s, txTo.nLockTime, nType, nVersion);
// Serialize vpour
// Serialize vjoinsplit
if (txTo.nVersion >= 2) {
//
// SIGHASH_* functions will hash portions of
@ -1080,8 +1080,8 @@ public:
// keeps the JoinSplit cryptographically bound
// to the transaction.
//
::Serialize(s, txTo.vpour, nType, nVersion);
if (txTo.vpour.size() > 0) {
::Serialize(s, txTo.vjoinsplit, nType, nVersion);
if (txTo.vjoinsplit.size() > 0) {
::Serialize(s, txTo.joinSplitPubKey, nType, nVersion);
CTransaction::joinsplit_sig_t nullSig = {};

View File

@ -24,7 +24,7 @@ class CCoinsViewTest : public CCoinsView
uint256 hashBestAnchor_;
std::map<uint256, CCoins> map_;
std::map<uint256, ZCIncrementalMerkleTree> mapAnchors_;
std::map<uint256, bool> mapSerials_;
std::map<uint256, bool> mapNullifiers_;
public:
CCoinsViewTest() {
@ -47,11 +47,11 @@ public:
}
}
bool GetSerial(const uint256 &serial) const
bool GetNullifier(const uint256 &nf) const
{
std::map<uint256, bool>::const_iterator it = mapSerials_.find(serial);
std::map<uint256, bool>::const_iterator it = mapNullifiers_.find(nf);
if (it == mapSerials_.end()) {
if (it == mapNullifiers_.end()) {
return false;
} else {
// The map shouldn't contain any false entries.
@ -88,7 +88,7 @@ public:
const uint256& hashBlock,
const uint256& hashAnchor,
CAnchorsMap& mapAnchors,
CSerialsMap& mapSerials)
CNullifiersMap& mapNullifiers)
{
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
map_[it->first] = it->second.coins;
@ -109,17 +109,17 @@ public:
}
mapAnchors.erase(it++);
}
for (CSerialsMap::iterator it = mapSerials.begin(); it != mapSerials.end(); ) {
for (CNullifiersMap::iterator it = mapNullifiers.begin(); it != mapNullifiers.end(); ) {
if (it->second.entered) {
mapSerials_[it->first] = true;
mapNullifiers_[it->first] = true;
} else {
mapSerials_.erase(it->first);
mapNullifiers_.erase(it->first);
}
mapSerials.erase(it++);
mapNullifiers.erase(it++);
}
mapCoins.clear();
mapAnchors.clear();
mapSerials.clear();
mapNullifiers.clear();
hashBestBlock_ = hashBlock;
hashBestAnchor_ = hashAnchor;
return true;
@ -138,7 +138,7 @@ public:
// Manually recompute the dynamic usage of the whole data, and compare it.
size_t ret = memusage::DynamicUsage(cacheCoins) +
memusage::DynamicUsage(cacheAnchors) +
memusage::DynamicUsage(cacheSerials);
memusage::DynamicUsage(cacheNullifiers);
for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
ret += memusage::DynamicUsage(it->second.coins);
}
@ -163,28 +163,28 @@ uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree)
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(serials_test)
BOOST_AUTO_TEST_CASE(nullifiers_test)
{
CCoinsViewTest base;
CCoinsViewCacheTest cache(&base);
uint256 myserial = GetRandHash();
uint256 nf = GetRandHash();
BOOST_CHECK(!cache.GetSerial(myserial));
cache.SetSerial(myserial, true);
BOOST_CHECK(cache.GetSerial(myserial));
BOOST_CHECK(!cache.GetNullifier(nf));
cache.SetNullifier(nf, true);
BOOST_CHECK(cache.GetNullifier(nf));
cache.Flush();
CCoinsViewCacheTest cache2(&base);
BOOST_CHECK(cache2.GetSerial(myserial));
cache2.SetSerial(myserial, false);
BOOST_CHECK(!cache2.GetSerial(myserial));
BOOST_CHECK(cache2.GetNullifier(nf));
cache2.SetNullifier(nf, false);
BOOST_CHECK(!cache2.GetNullifier(nf));
cache2.Flush();
CCoinsViewCacheTest cache3(&base);
BOOST_CHECK(!cache3.GetSerial(myserial));
BOOST_CHECK(!cache3.GetNullifier(nf));
}
BOOST_AUTO_TEST_CASE(anchors_flush_test)
@ -217,80 +217,80 @@ BOOST_AUTO_TEST_CASE(anchors_flush_test)
}
}
BOOST_AUTO_TEST_CASE(chained_pours)
BOOST_AUTO_TEST_CASE(chained_joinsplits)
{
CCoinsViewTest base;
CCoinsViewCacheTest cache(&base);
ZCIncrementalMerkleTree tree;
CPourTx ptx1;
ptx1.anchor = tree.root();
ptx1.commitments[0] = appendRandomCommitment(tree);
ptx1.commitments[1] = appendRandomCommitment(tree);
JSDescription js1;
js1.anchor = tree.root();
js1.commitments[0] = appendRandomCommitment(tree);
js1.commitments[1] = appendRandomCommitment(tree);
// Although it's not possible given our assumptions, if
// two pours create the same treestate twice, we should
// two joinsplits create the same treestate twice, we should
// still be able to anchor to it.
CPourTx ptx1b;
ptx1b.anchor = tree.root();
ptx1b.commitments[0] = ptx1.commitments[0];
ptx1b.commitments[1] = ptx1.commitments[1];
JSDescription js1b;
js1b.anchor = tree.root();
js1b.commitments[0] = js1.commitments[0];
js1b.commitments[1] = js1.commitments[1];
CPourTx ptx2;
CPourTx ptx3;
JSDescription js2;
JSDescription js3;
ptx2.anchor = tree.root();
ptx3.anchor = tree.root();
js2.anchor = tree.root();
js3.anchor = tree.root();
ptx2.commitments[0] = appendRandomCommitment(tree);
ptx2.commitments[1] = appendRandomCommitment(tree);
js2.commitments[0] = appendRandomCommitment(tree);
js2.commitments[1] = appendRandomCommitment(tree);
ptx3.commitments[0] = appendRandomCommitment(tree);
ptx3.commitments[1] = appendRandomCommitment(tree);
js3.commitments[0] = appendRandomCommitment(tree);
js3.commitments[1] = appendRandomCommitment(tree);
{
CMutableTransaction mtx;
mtx.vpour.push_back(ptx2);
mtx.vjoinsplit.push_back(js2);
BOOST_CHECK(!cache.HavePourRequirements(mtx));
BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx));
}
{
// ptx2 is trying to anchor to ptx1 but ptx1
// js2 is trying to anchor to js1 but js1
// appears afterwards -- not a permitted ordering
CMutableTransaction mtx;
mtx.vpour.push_back(ptx2);
mtx.vpour.push_back(ptx1);
mtx.vjoinsplit.push_back(js2);
mtx.vjoinsplit.push_back(js1);
BOOST_CHECK(!cache.HavePourRequirements(mtx));
BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx));
}
{
CMutableTransaction mtx;
mtx.vpour.push_back(ptx1);
mtx.vpour.push_back(ptx2);
mtx.vjoinsplit.push_back(js1);
mtx.vjoinsplit.push_back(js2);
BOOST_CHECK(cache.HavePourRequirements(mtx));
BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
}
{
CMutableTransaction mtx;
mtx.vpour.push_back(ptx1);
mtx.vpour.push_back(ptx2);
mtx.vpour.push_back(ptx3);
mtx.vjoinsplit.push_back(js1);
mtx.vjoinsplit.push_back(js2);
mtx.vjoinsplit.push_back(js3);
BOOST_CHECK(cache.HavePourRequirements(mtx));
BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
}
{
CMutableTransaction mtx;
mtx.vpour.push_back(ptx1);
mtx.vpour.push_back(ptx1b);
mtx.vpour.push_back(ptx2);
mtx.vpour.push_back(ptx3);
mtx.vjoinsplit.push_back(js1);
mtx.vjoinsplit.push_back(js1b);
mtx.vjoinsplit.push_back(js2);
mtx.vjoinsplit.push_back(js3);
BOOST_CHECK(cache.HavePourRequirements(mtx));
BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
}
}

View File

@ -105,7 +105,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0;
int ins = (insecure_rand() % 4) + 1;
int outs = fSingle ? ins : (insecure_rand() % 4) + 1;
int pours = (insecure_rand() % 4);
int joinsplits = (insecure_rand() % 4);
for (int in = 0; in < ins; in++) {
tx.vin.push_back(CTxIn());
CTxIn &txin = tx.vin.back();
@ -121,26 +121,26 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
RandomScript(txout.scriptPubKey);
}
if (tx.nVersion >= 2) {
for (int pour = 0; pour < pours; pour++) {
CPourTx pourtx;
for (int js = 0; js < joinsplits; js++) {
JSDescription jsdesc;
if (insecure_rand() % 2 == 0) {
pourtx.vpub_old = insecure_rand() % 100000000;
jsdesc.vpub_old = insecure_rand() % 100000000;
} else {
pourtx.vpub_new = insecure_rand() % 100000000;
jsdesc.vpub_new = insecure_rand() % 100000000;
}
pourtx.anchor = GetRandHash();
pourtx.serials[0] = GetRandHash();
pourtx.serials[1] = GetRandHash();
pourtx.ephemeralKey = GetRandHash();
pourtx.randomSeed = GetRandHash();
randombytes_buf(pourtx.ciphertexts[0].begin(), pourtx.ciphertexts[0].size());
randombytes_buf(pourtx.ciphertexts[1].begin(), pourtx.ciphertexts[1].size());
randombytes_buf(pourtx.proof.begin(), pourtx.proof.size());
pourtx.macs[0] = GetRandHash();
pourtx.macs[1] = GetRandHash();
jsdesc.anchor = GetRandHash();
jsdesc.nullifiers[0] = GetRandHash();
jsdesc.nullifiers[1] = GetRandHash();
jsdesc.ephemeralKey = GetRandHash();
jsdesc.randomSeed = GetRandHash();
randombytes_buf(jsdesc.ciphertexts[0].begin(), jsdesc.ciphertexts[0].size());
randombytes_buf(jsdesc.ciphertexts[1].begin(), jsdesc.ciphertexts[1].size());
randombytes_buf(jsdesc.proof.begin(), jsdesc.proof.size());
jsdesc.macs[0] = GetRandHash();
jsdesc.macs[1] = GetRandHash();
tx.vpour.push_back(pourtx);
tx.vjoinsplit.push_back(jsdesc);
}
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];

View File

@ -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.
@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE(test_basic_pour_verification)
auto witness = merkleTree.witness();
// create CPourTx
// create JSDescription
uint256 pubKeyHash;
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs = {
libzcash::JSInput(witness, note, k),
@ -342,28 +342,28 @@ BOOST_AUTO_TEST_CASE(test_basic_pour_verification)
};
{
CPourTx 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;
CPourTx 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));
}
{
// Ensure that the balance equation is working.
BOOST_CHECK_THROW(CPourTx(*p, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument);
BOOST_CHECK_THROW(CPourTx(*p, pubKeyHash, rt, inputs, outputs, 0, 10), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(*p, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(*p, pubKeyHash, rt, inputs, outputs, 0, 10), std::invalid_argument);
}
{
// Ensure that it won't verify if the root is changed.
auto test = CPourTx(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
auto test = JSDescription(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
test.anchor = GetRandHash();
BOOST_CHECK(!test.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");
@ -393,11 +393,11 @@ BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vout-empty");
newTx.vpour.push_back(CPourTx());
CPourTx *pourtx = &newTx.vpour[0];
newTx.vjoinsplit.push_back(JSDescription());
JSDescription *jsdesc = &newTx.vjoinsplit[0];
pourtx->serials[0] = GetRandHash();
pourtx->serials[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,78 +418,78 @@ 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.vpour.push_back(CPourTx());
newTx.vjoinsplit.push_back(JSDescription());
CPourTx *pourtx = &newTx.vpour[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.vpour.push_back(CPourTx());
newTx.vjoinsplit.push_back(JSDescription());
CPourTx *pourtx2 = &newTx.vpour[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");
}
{
// Ensure that serials are never duplicated within a transaction.
// Ensure that nullifiers are never duplicated within a transaction.
CMutableTransaction newTx(tx);
CValidationState state;
newTx.vpour.push_back(CPourTx());
CPourTx *pourtx = &newTx.vpour[0];
newTx.vjoinsplit.push_back(JSDescription());
JSDescription *jsdesc = &newTx.vjoinsplit[0];
pourtx->serials[0] = GetRandHash();
pourtx->serials[1] = pourtx->serials[0];
jsdesc->nullifiers[0] = GetRandHash();
jsdesc->nullifiers[1] = jsdesc->nullifiers[0];
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(state.GetRejectReason() == "bad-pours-serials-duplicate");
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
pourtx->serials[1] = GetRandHash();
jsdesc->nullifiers[1] = GetRandHash();
newTx.vpour.push_back(CPourTx());
CPourTx *pourtx2 = &newTx.vpour[1];
newTx.vjoinsplit.push_back(JSDescription());
JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
pourtx2->serials[0] = GetRandHash();
pourtx2->serials[1] = pourtx->serials[0];
jsdesc2->nullifiers[0] = GetRandHash();
jsdesc2->nullifiers[1] = jsdesc->nullifiers[0];
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(state.GetRejectReason() == "bad-pours-serials-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.vpour.push_back(CPourTx());
CPourTx *pourtx = &newTx.vpour[0];
pourtx->serials[0] = GetRandHash();
pourtx->serials[1] = GetRandHash();
newTx.vjoinsplit.push_back(JSDescription());
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");
}
}

View File

@ -18,7 +18,7 @@
using namespace std;
static const char DB_ANCHOR = 'A';
static const char DB_SERIAL = 's';
static const char DB_NULLIFIER = 's';
static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_TXINDEX = 't';
@ -43,11 +43,11 @@ void static BatchWriteAnchor(CLevelDBBatch &batch,
}
}
void static BatchWriteSerial(CLevelDBBatch &batch, const uint256 &serial, const bool &entered) {
void static BatchWriteNullifier(CLevelDBBatch &batch, const uint256 &nf, const bool &entered) {
if (!entered)
batch.Erase(make_pair(DB_SERIAL, serial));
batch.Erase(make_pair(DB_NULLIFIER, nf));
else
batch.Write(make_pair(DB_SERIAL, serial), true);
batch.Write(make_pair(DB_NULLIFIER, nf), true);
}
void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
@ -81,9 +81,9 @@ bool CCoinsViewDB::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree)
return read;
}
bool CCoinsViewDB::GetSerial(const uint256 &serial) const {
bool CCoinsViewDB::GetNullifier(const uint256 &nf) const {
bool spent = false;
bool read = db.Read(make_pair(DB_SERIAL, serial), spent);
bool read = db.Read(make_pair(DB_NULLIFIER, nf), spent);
return read;
}
@ -114,7 +114,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CSerialsMap &mapSerials) {
CNullifiersMap &mapNullifiers) {
CLevelDBBatch batch;
size_t count = 0;
size_t changed = 0;
@ -137,13 +137,13 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
mapAnchors.erase(itOld);
}
for (CSerialsMap::iterator it = mapSerials.begin(); it != mapSerials.end();) {
if (it->second.flags & CSerialsCacheEntry::DIRTY) {
BatchWriteSerial(batch, it->first, it->second.entered);
for (CNullifiersMap::iterator it = mapNullifiers.begin(); it != mapNullifiers.end();) {
if (it->second.flags & CNullifiersCacheEntry::DIRTY) {
BatchWriteNullifier(batch, it->first, it->second.entered);
// TODO: changed++?
}
CSerialsMap::iterator itOld = it++;
mapSerials.erase(itOld);
CNullifiersMap::iterator itOld = it++;
mapNullifiers.erase(itOld);
}
if (!hashBlock.IsNull())

View File

@ -35,7 +35,7 @@ public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
bool GetSerial(const uint256 &serial) const;
bool GetNullifier(const uint256 &nf) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
@ -44,7 +44,7 @@ public:
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CSerialsMap &mapSerials);
CNullifiersMap &mapNullifiers);
bool GetStats(CCoinsStats &stats) const;
};

View File

@ -99,9 +99,9 @@ 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 CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
mapSerials[serial] = &tx;
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
mapNullifiers[nf] = &tx;
}
}
nTransactionsUpdated++;
@ -148,9 +148,9 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
}
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
BOOST_FOREACH(const CPourTx& pour, tx.vpour) {
BOOST_FOREACH(const uint256& serial, pour.serials) {
mapSerials.erase(serial);
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256& nf, joinsplit.nullifiers) {
mapNullifiers.erase(nf);
}
}
@ -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 CPourTx& pour, tx.vpour) {
if (pour.anchor == invalidRoot) {
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) {
if (joinsplit.anchor == invalidRoot) {
transactionsToRemove.push_back(tx);
break;
}
@ -230,10 +230,10 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
}
}
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
std::map<uint256, const CTransaction*>::iterator it = mapSerials.find(serial);
if (it != mapSerials.end()) {
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
std::map<uint256, const CTransaction*>::iterator it = mapNullifiers.find(nf);
if (it != mapNullifiers.end()) {
const CTransaction &txConflict = *it->second;
if (txConflict != tx)
{
@ -317,20 +317,20 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
BOOST_FOREACH(const uint256 &serial, pour.serials) {
assert(!pcoins->GetSerial(serial));
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) {
assert(!pcoins->GetNullifier(nf));
}
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);
}
@ -370,7 +370,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(it->first == it->second.ptx->vin[it->second.n].prevout);
}
for (std::map<uint256, const CTransaction*>::const_iterator it = mapSerials.begin(); it != mapSerials.end(); it++) {
for (std::map<uint256, const CTransaction*>::const_iterator it = mapNullifiers.begin(); it != mapNullifiers.end(); it++) {
uint256 hash = it->second->GetHash();
map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(hash);
const CTransaction& tx = it2->second.GetTx();
@ -484,11 +484,11 @@ bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
bool CCoinsViewMemPool::GetSerial(const uint256 &serial) const {
if (mempool.mapSerials.count(serial))
bool CCoinsViewMemPool::GetNullifier(const uint256 &nf) const {
if (mempool.mapNullifiers.count(nf))
return true;
return base->GetSerial(serial);
return base->GetNullifier(nf);
}
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {

View File

@ -98,7 +98,7 @@ public:
mutable CCriticalSection cs;
std::map<uint256, CTxMemPoolEntry> mapTx;
std::map<COutPoint, CInPoint> mapNextTx;
std::map<uint256, const CTransaction*> mapSerials;
std::map<uint256, const CTransaction*> mapNullifiers;
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
CTxMemPool(const CFeeRate& _minRelayFee);
@ -177,7 +177,7 @@ protected:
public:
CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn);
bool GetSerial(const uint256 &txid) const;
bool GetNullifier(const uint256 &txid) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
};

View File

@ -2393,18 +2393,18 @@ Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
pzcashParams->loadProvingKey();
}
CPourTx* samplejoinsplit = NULL;
JSDescription* samplejoinsplit = NULL;
if (benchmarktype == "verifyjoinsplit") {
uint256 pubKeyHash;
uint256 anchor = ZCIncrementalMerkleTree().root();
samplejoinsplit = new CPourTx(*pzcashParams,
pubKeyHash,
anchor,
{JSInput(), JSInput()},
{JSOutput(), JSOutput()},
0,
0);
samplejoinsplit = new JSDescription(*pzcashParams,
pubKeyHash,
anchor,
{JSInput(), JSInput()},
{JSOutput(), JSOutput()},
0,
0);
}
for (int i = 0; i < samplecount; i++) {
@ -2448,14 +2448,14 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
if (fHelp || params.size() != 2) {
throw runtime_error(
"zcrawreceive zcsecretkey encryptedbucket\n"
"zcrawreceive zcsecretkey encryptednote\n"
"\n"
"Decrypts encryptedbucket and checks if the coin commitments\n"
"Decrypts encryptednote and checks if the coin commitments\n"
"are in the blockchain as indicated by the \"exists\" result.\n"
"\n"
"Output: {\n"
" \"amount\": value,\n"
" \"bucket\": cleartextbucket,\n"
" \"note\": noteplaintext,\n"
" \"exists\": exists\n"
"}\n"
);
@ -2474,7 +2474,7 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
uint256 h_sig;
{
CDataStream ssData(ParseHexV(params[1], "encrypted_bucket"), SER_NETWORK, PROTOCOL_VERSION);
CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> nonce;
ssData >> epk;
@ -2482,7 +2482,7 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
ssData >> h_sig;
} catch(const std::exception &) {
throw runtime_error(
"encrypted_bucket could not be decoded"
"encrypted_note could not be decoded"
);
}
}
@ -2503,7 +2503,7 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
uint256 anchor;
uint256 commitment = decrypted_note.cm();
pwalletMain->WitnessBucketCommitment(
pwalletMain->WitnessNoteCommitment(
{commitment},
witnesses,
anchor
@ -2514,14 +2514,14 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
Object result;
result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
result.push_back(Pair("bucket", HexStr(ss.begin(), ss.end())));
result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
result.push_back(Pair("exists", (bool) witnesses[0]));
return result;
}
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"
" inputs: a JSON object mapping {bucket: zcsecretkey, ...}\n"
"zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
" inputs: a JSON object mapping {note: 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"
@ -2544,8 +2544,8 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
"payments in-band on the blockchain.)\n"
"\n"
"Output: {\n"
" \"encryptedbucket1\": enc1,\n"
" \"encryptedbucket2\": enc2,\n"
" \"encryptednote1\": enc1,\n"
" \"encryptednote2\": enc2,\n"
" \"rawtxn\": rawtxout\n"
"}\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;
@ -2585,7 +2585,7 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
NotePlaintext npt;
{
CDataStream ssData(ParseHexV(s.name_, "bucket"), SER_NETWORK, PROTOCOL_VERSION);
CDataStream ssData(ParseHexV(s.name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
ssData >> npt;
}
@ -2597,7 +2597,7 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
uint256 anchor;
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
pwalletMain->WitnessBucketCommitment(commitments, witnesses, anchor);
pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
assert(witnesses.size() == notes.size());
assert(notes.size() == keys.size());
@ -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;
CPourTx pourtx(*pzcashParams,
joinSplitPubKey,
anchor,
{vpourin[0], vpourin[1]},
{vpourout[0], vpourout[1]},
vpub_old,
vpub_new);
JSDescription jsdesc(*pzcashParams,
joinSplitPubKey,
anchor,
{vjsin[0], vjsin[1]},
{vjsout[0], vjsout[1]},
vpub_old,
vpub_new);
assert(pourtx.Verify(*pzcashParams, joinSplitPubKey));
assert(jsdesc.Verify(*pzcashParams, joinSplitPubKey));
mtx.vpour.push_back(pourtx);
mtx.vjoinsplit.push_back(jsdesc);
// TODO: #966.
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
@ -2683,30 +2683,30 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << rawTx;
std::string encryptedBucket1;
std::string encryptedBucket2;
std::string encryptedNote1;
std::string encryptedNote2;
{
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
ss2 << ((unsigned char) 0x00);
ss2 << pourtx.ephemeralKey;
ss2 << pourtx.ciphertexts[0];
ss2 << pourtx.h_sig(*pzcashParams, joinSplitPubKey);
ss2 << jsdesc.ephemeralKey;
ss2 << jsdesc.ciphertexts[0];
ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
encryptedBucket1 = HexStr(ss2.begin(), ss2.end());
encryptedNote1 = 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 << jsdesc.ephemeralKey;
ss2 << jsdesc.ciphertexts[1];
ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
encryptedBucket2 = HexStr(ss2.begin(), ss2.end());
encryptedNote2 = HexStr(ss2.begin(), ss2.end());
}
Object result;
result.push_back(Pair("encryptedbucket1", encryptedBucket1));
result.push_back(Pair("encryptedbucket2", encryptedBucket2));
result.push_back(Pair("encryptednote1", encryptedNote1));
result.push_back(Pair("encryptednote2", encryptedNote2));
result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
return result;
}

View File

@ -1051,9 +1051,9 @@ bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
return pwalletdb->WriteTx(GetHash(), *this);
}
void CWallet::WitnessBucketCommitment(std::vector<uint256> commitments,
std::vector<boost::optional<ZCIncrementalWitness>>& witnesses,
uint256 &final_anchor)
void CWallet::WitnessNoteCommitment(std::vector<uint256> commitments,
std::vector<boost::optional<ZCIncrementalWitness>>& witnesses,
uint256 &final_anchor)
{
witnesses.resize(commitments.size());
CBlockIndex* pindex = chainActive.Genesis();
@ -1065,21 +1065,21 @@ void CWallet::WitnessBucketCommitment(std::vector<uint256> commitments,
BOOST_FOREACH(const CTransaction& tx, block.vtx)
{
BOOST_FOREACH(const CPourTx& pour, tx.vpour)
BOOST_FOREACH(const JSDescription& jsdesc, tx.vjoinsplit)
{
BOOST_FOREACH(const uint256 &bucket_commitment, pour.commitments)
BOOST_FOREACH(const uint256 &note_commitment, jsdesc.commitments)
{
tree.append(bucket_commitment);
tree.append(note_commitment);
BOOST_FOREACH(boost::optional<ZCIncrementalWitness>& wit, witnesses) {
if (wit) {
wit->append(bucket_commitment);
wit->append(note_commitment);
}
}
size_t i = 0;
BOOST_FOREACH(uint256& commitment, commitments) {
if (bucket_commitment == commitment) {
if (note_commitment == commitment) {
witnesses.at(i) = tree.witness();
}
i++;

View File

@ -616,7 +616,7 @@ public:
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
void EraseFromWallet(const uint256 &hash);
void WitnessBucketCommitment(
void WitnessNoteCommitment(
std::vector<uint256> commitments,
std::vector<boost::optional<ZCIncrementalWitness>>& witnesses,
uint256 &final_anchor);

View File

@ -76,20 +76,20 @@ double benchmark_create_joinsplit()
uint256 anchor = ZCIncrementalMerkleTree().root();
timer_start();
CPourTx pourtx(*pzcashParams,
pubKeyHash,
anchor,
{JSInput(), JSInput()},
{JSOutput(), JSOutput()},
0,
0);
JSDescription jsdesc(*pzcashParams,
pubKeyHash,
anchor,
{JSInput(), JSInput()},
{JSOutput(), JSOutput()},
0,
0);
double ret = timer_stop();
assert(pourtx.Verify(*pzcashParams, pubKeyHash));
assert(jsdesc.Verify(*pzcashParams, pubKeyHash));
return ret;
}
double benchmark_verify_joinsplit(const CPourTx &joinsplit)
double benchmark_verify_joinsplit(const JSDescription &joinsplit)
{
timer_start();
uint256 pubKeyHash;

View File

@ -8,7 +8,7 @@ extern double benchmark_sleep();
extern double benchmark_parameter_loading();
extern double benchmark_create_joinsplit();
extern double benchmark_solve_equihash();
extern double benchmark_verify_joinsplit(const CPourTx &joinsplit);
extern double benchmark_verify_joinsplit(const JSDescription &joinsplit);
extern double benchmark_verify_equihash();
extern double benchmark_large_tx();