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:
commit
4d459f93a4
|
@ -27,8 +27,8 @@ testScripts=(
|
||||||
'merkle_blocks.py'
|
'merkle_blocks.py'
|
||||||
'signrawtransactions.py'
|
'signrawtransactions.py'
|
||||||
'walletbackup.py'
|
'walletbackup.py'
|
||||||
'zcpour.py'
|
'zcjoinsplit.py'
|
||||||
'zcpourdoublespend.py'
|
'zcjoinsplitdoublespend.py'
|
||||||
);
|
);
|
||||||
testScriptsExt=(
|
testScriptsExt=(
|
||||||
'bipdersig-p2p.py'
|
'bipdersig-p2p.py'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
#
|
#
|
||||||
# Test Pour semantics
|
# Test joinsplit semantics
|
||||||
#
|
#
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
@ -11,7 +11,7 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
class PourTxTest(BitcoinTestFramework):
|
class JoinSplitTest(BitcoinTestFramework):
|
||||||
def setup_network(self):
|
def setup_network(self):
|
||||||
self.nodes = []
|
self.nodes = []
|
||||||
self.is_network_split = False
|
self.is_network_split = False
|
||||||
|
@ -24,27 +24,27 @@ class PourTxTest(BitcoinTestFramework):
|
||||||
|
|
||||||
(total_in, inputs) = gather_inputs(self.nodes[0], 40)
|
(total_in, inputs) = gather_inputs(self.nodes[0], 40)
|
||||||
protect_tx = self.nodes[0].createrawtransaction(inputs, {})
|
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)
|
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].sendrawtransaction(protect_tx["hex"])
|
||||||
self.nodes[0].generate(1)
|
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)
|
assert_equal(receive_result["exists"], True)
|
||||||
|
|
||||||
pour_tx = self.nodes[0].createrawtransaction([], {})
|
joinsplit_tx = self.nodes[0].createrawtransaction([], {})
|
||||||
pour_result = self.nodes[0].zcrawpour(pour_tx, {receive_result["bucket"] : zcsecretkey}, {zcaddress: 39.8}, 0, 0.1)
|
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)
|
self.nodes[0].generate(1)
|
||||||
|
|
||||||
print "Done!"
|
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)
|
assert_equal(receive_result["exists"], True)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
PourTxTest().main()
|
JoinSplitTest().main()
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python2
|
#!/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
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
@ -12,10 +12,10 @@ import shutil
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
class PourTxTest(BitcoinTestFramework):
|
class JoinSplitTest(BitcoinTestFramework):
|
||||||
def setup_network(self):
|
def setup_network(self):
|
||||||
# Start with split network:
|
# 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):
|
def txid_in_mempool(self, node, txid):
|
||||||
exception_triggered = False
|
exception_triggered = False
|
||||||
|
@ -27,7 +27,7 @@ class PourTxTest(BitcoinTestFramework):
|
||||||
|
|
||||||
return not exception_triggered
|
return not exception_triggered
|
||||||
|
|
||||||
def cannot_pour(self, node, txn):
|
def cannot_joinsplit(self, node, txn):
|
||||||
exception_triggered = False
|
exception_triggered = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -37,8 +37,8 @@ class PourTxTest(BitcoinTestFramework):
|
||||||
|
|
||||||
return exception_triggered
|
return exception_triggered
|
||||||
|
|
||||||
def expect_cannot_pour(self, node, txn):
|
def expect_cannot_joinsplit(self, node, txn):
|
||||||
assert_equal(self.cannot_pour(node, txn), True)
|
assert_equal(self.cannot_joinsplit(node, txn), True)
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# All nodes should start with 250 BTC:
|
# All nodes should start with 250 BTC:
|
||||||
|
@ -56,7 +56,7 @@ class PourTxTest(BitcoinTestFramework):
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
(total_in, inputs) = gather_inputs(self.nodes[i], 40)
|
(total_in, inputs) = gather_inputs(self.nodes[i], 40)
|
||||||
pool[i] = self.nodes[i].createrawtransaction(inputs, {})
|
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"])
|
signed = self.nodes[i].signrawtransaction(pool[i]["rawtxn"])
|
||||||
|
|
||||||
# send the tx to both halves of the network
|
# send the tx to both halves of the network
|
||||||
|
@ -64,54 +64,54 @@ class PourTxTest(BitcoinTestFramework):
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
self.nodes[2].sendrawtransaction(signed["hex"])
|
self.nodes[2].sendrawtransaction(signed["hex"])
|
||||||
self.nodes[2].generate(1)
|
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[0:2])
|
||||||
sync_blocks(self.nodes[2:4])
|
sync_blocks(self.nodes[2:4])
|
||||||
|
|
||||||
# Confirm that the protects have taken place
|
# Confirm that the protects have taken place
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
enc_bucket = pool[i]
|
enc_note = pool[i]
|
||||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, enc_bucket)
|
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, enc_note)
|
||||||
assert_equal(receive_result["exists"], True)
|
assert_equal(receive_result["exists"], True)
|
||||||
pool[i] = receive_result["bucket"]
|
pool[i] = receive_result["note"]
|
||||||
|
|
||||||
# Extra confirmations
|
# 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)
|
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)
|
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)
|
assert_equal(receive_result["exists"], True)
|
||||||
|
|
||||||
blank_tx = self.nodes[0].createrawtransaction([], {})
|
blank_tx = self.nodes[0].createrawtransaction([], {})
|
||||||
# Create pour {A, B}->{*}
|
# Create joinsplit {A, B}->{*}
|
||||||
pour_AB = self.nodes[0].zcrawpour(blank_tx,
|
joinsplit_AB = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||||
{pool[0] : zcsecretkey, pool[1] : zcsecretkey},
|
{pool[0] : zcsecretkey, pool[1] : zcsecretkey},
|
||||||
{zcaddress:(39.9*2)-0.1},
|
{zcaddress:(39.9*2)-0.1},
|
||||||
0, 0.1)
|
0, 0.1)
|
||||||
|
|
||||||
# Create pour {B, C}->{*}
|
# Create joinsplit {B, C}->{*}
|
||||||
pour_BC = self.nodes[0].zcrawpour(blank_tx,
|
joinsplit_BC = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||||
{pool[1] : zcsecretkey, pool[2] : zcsecretkey},
|
{pool[1] : zcsecretkey, pool[2] : zcsecretkey},
|
||||||
{zcaddress:(39.9*2)-0.1},
|
{zcaddress:(39.9*2)-0.1},
|
||||||
0, 0.1)
|
0, 0.1)
|
||||||
|
|
||||||
# Create pour {C, D}->{*}
|
# Create joinsplit {C, D}->{*}
|
||||||
pour_CD = self.nodes[0].zcrawpour(blank_tx,
|
joinsplit_CD = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||||
{pool[2] : zcsecretkey, pool[3] : zcsecretkey},
|
{pool[2] : zcsecretkey, pool[3] : zcsecretkey},
|
||||||
{zcaddress:(39.9*2)-0.1},
|
{zcaddress:(39.9*2)-0.1},
|
||||||
0, 0.1)
|
0, 0.1)
|
||||||
|
|
||||||
# Create pour {A, D}->{*}
|
# Create joinsplit {A, D}->{*}
|
||||||
pour_AD = self.nodes[0].zcrawpour(blank_tx,
|
joinsplit_AD = self.nodes[0].zcrawjoinsplit(blank_tx,
|
||||||
{pool[0] : zcsecretkey, pool[3] : zcsecretkey},
|
{pool[0] : zcsecretkey, pool[3] : zcsecretkey},
|
||||||
{zcaddress:(39.9*2)-0.1},
|
{zcaddress:(39.9*2)-0.1},
|
||||||
0, 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
|
# double-spend it with BC. It should fail before and
|
||||||
# after Node 0 mines blocks.
|
# after Node 0 mines blocks.
|
||||||
#
|
#
|
||||||
|
@ -126,9 +126,9 @@ class PourTxTest(BitcoinTestFramework):
|
||||||
|
|
||||||
# (a)
|
# (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
|
# Wait until node[1] receives AB before we attempt to double-spend
|
||||||
# with BC.
|
# with BC.
|
||||||
|
@ -139,17 +139,17 @@ class PourTxTest(BitcoinTestFramework):
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
print "Done!\n"
|
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
|
# Generate a block
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
sync_blocks(self.nodes[0:2])
|
sync_blocks(self.nodes[0:2])
|
||||||
|
|
||||||
self.expect_cannot_pour(self.nodes[0], pour_BC["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"])
|
||||||
self.expect_cannot_pour(self.nodes[1], pour_BC["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"])
|
||||||
|
|
||||||
# (b)
|
# (b)
|
||||||
self.nodes[2].sendrawtransaction(pour_BC["rawtxn"])
|
self.nodes[2].sendrawtransaction(joinsplit_BC["rawtxn"])
|
||||||
self.nodes[2].generate(5)
|
self.nodes[2].generate(5)
|
||||||
|
|
||||||
# Connect the two nodes
|
# Connect the two nodes
|
||||||
|
@ -158,26 +158,26 @@ class PourTxTest(BitcoinTestFramework):
|
||||||
sync_blocks(self.nodes)
|
sync_blocks(self.nodes)
|
||||||
|
|
||||||
# AB and CD should all be impossible to spend for each node.
|
# 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_joinsplit(self.nodes[0], joinsplit_AB["rawtxn"])
|
||||||
self.expect_cannot_pour(self.nodes[0], pour_CD["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[0], joinsplit_CD["rawtxn"])
|
||||||
|
|
||||||
self.expect_cannot_pour(self.nodes[1], pour_AB["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_AB["rawtxn"])
|
||||||
self.expect_cannot_pour(self.nodes[1], pour_CD["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[1], joinsplit_CD["rawtxn"])
|
||||||
|
|
||||||
self.expect_cannot_pour(self.nodes[2], pour_AB["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[2], joinsplit_AB["rawtxn"])
|
||||||
self.expect_cannot_pour(self.nodes[2], pour_CD["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[2], joinsplit_CD["rawtxn"])
|
||||||
|
|
||||||
self.expect_cannot_pour(self.nodes[3], pour_AB["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[3], joinsplit_AB["rawtxn"])
|
||||||
self.expect_cannot_pour(self.nodes[3], pour_CD["rawtxn"])
|
self.expect_cannot_joinsplit(self.nodes[3], joinsplit_CD["rawtxn"])
|
||||||
|
|
||||||
# (c)
|
# (c)
|
||||||
# AD should be possible to send due to the reorg that
|
# AD should be possible to send due to the reorg that
|
||||||
# tossed out AB.
|
# tossed out AB.
|
||||||
|
|
||||||
self.nodes[0].sendrawtransaction(pour_AD["rawtxn"])
|
self.nodes[0].sendrawtransaction(joinsplit_AD["rawtxn"])
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
|
||||||
sync_blocks(self.nodes)
|
sync_blocks(self.nodes)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
PourTxTest().main()
|
JoinSplitTest().main()
|
|
@ -41,7 +41,7 @@ bool CCoins::Spend(uint32_t nPos)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool CCoinsView::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; }
|
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::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
|
||||||
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
|
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
|
||||||
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
|
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
|
||||||
|
@ -50,14 +50,14 @@ bool CCoinsView::BatchWrite(CCoinsMap &mapCoins,
|
||||||
const uint256 &hashBlock,
|
const uint256 &hashBlock,
|
||||||
const uint256 &hashAnchor,
|
const uint256 &hashAnchor,
|
||||||
CAnchorsMap &mapAnchors,
|
CAnchorsMap &mapAnchors,
|
||||||
CSerialsMap &mapSerials) { return false; }
|
CNullifiersMap &mapNullifiers) { return false; }
|
||||||
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
|
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
|
||||||
|
|
||||||
|
|
||||||
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
|
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
|
||||||
|
|
||||||
bool CCoinsViewBacked::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetAnchorAt(rt, tree); }
|
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::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
|
||||||
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
|
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
|
||||||
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
|
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
|
||||||
|
@ -67,7 +67,7 @@ bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins,
|
||||||
const uint256 &hashBlock,
|
const uint256 &hashBlock,
|
||||||
const uint256 &hashAnchor,
|
const uint256 &hashAnchor,
|
||||||
CAnchorsMap &mapAnchors,
|
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); }
|
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
|
||||||
|
|
||||||
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
|
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
|
||||||
|
@ -82,7 +82,7 @@ CCoinsViewCache::~CCoinsViewCache()
|
||||||
size_t CCoinsViewCache::DynamicMemoryUsage() const {
|
size_t CCoinsViewCache::DynamicMemoryUsage() const {
|
||||||
return memusage::DynamicUsage(cacheCoins) +
|
return memusage::DynamicUsage(cacheCoins) +
|
||||||
memusage::DynamicUsage(cacheAnchors) +
|
memusage::DynamicUsage(cacheAnchors) +
|
||||||
memusage::DynamicUsage(cacheSerials) +
|
memusage::DynamicUsage(cacheNullifiers) +
|
||||||
cachedCoinsUsage;
|
cachedCoinsUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,16 +128,16 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCoinsViewCache::GetSerial(const uint256 &serial) const {
|
bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
|
||||||
CSerialsMap::iterator it = cacheSerials.find(serial);
|
CNullifiersMap::iterator it = cacheNullifiers.find(nullifier);
|
||||||
if (it != cacheSerials.end())
|
if (it != cacheNullifiers.end())
|
||||||
return it->second.entered;
|
return it->second.entered;
|
||||||
|
|
||||||
CSerialsCacheEntry entry;
|
CNullifiersCacheEntry entry;
|
||||||
bool tmp = base->GetSerial(serial);
|
bool tmp = base->GetNullifier(nullifier);
|
||||||
entry.entered = tmp;
|
entry.entered = tmp;
|
||||||
|
|
||||||
cacheSerials.insert(std::make_pair(serial, entry));
|
cacheNullifiers.insert(std::make_pair(nullifier, entry));
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) {
|
||||||
|
|
||||||
// We don't want to overwrite an anchor we already have.
|
// We don't want to overwrite an anchor we already have.
|
||||||
// This occurs when a block doesn't modify mapAnchors at all,
|
// 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)
|
// different way (make all blocks modify mapAnchors somehow)
|
||||||
// but this is simpler to reason about.
|
// but this is simpler to reason about.
|
||||||
if (currentRoot != newrt) {
|
if (currentRoot != newrt) {
|
||||||
|
@ -185,10 +185,10 @@ void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCoinsViewCache::SetSerial(const uint256 &serial, bool spent) {
|
void CCoinsViewCache::SetNullifier(const uint256 &nullifier, bool spent) {
|
||||||
std::pair<CSerialsMap::iterator, bool> ret = cacheSerials.insert(std::make_pair(serial, CSerialsCacheEntry()));
|
std::pair<CNullifiersMap::iterator, bool> ret = cacheNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry()));
|
||||||
ret.first->second.entered = spent;
|
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 {
|
bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
|
||||||
|
@ -260,7 +260,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
|
||||||
const uint256 &hashBlockIn,
|
const uint256 &hashBlockIn,
|
||||||
const uint256 &hashAnchorIn,
|
const uint256 &hashAnchorIn,
|
||||||
CAnchorsMap &mapAnchors,
|
CAnchorsMap &mapAnchors,
|
||||||
CSerialsMap &mapSerials) {
|
CNullifiersMap &mapNullifiers) {
|
||||||
assert(!hasModifier);
|
assert(!hasModifier);
|
||||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
|
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
|
||||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
|
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
|
||||||
|
@ -326,29 +326,29 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
|
||||||
mapAnchors.erase(itOld);
|
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).
|
if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
|
||||||
CSerialsMap::iterator parent_it = cacheSerials.find(child_it->first);
|
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
|
||||||
|
|
||||||
if (parent_it == cacheSerials.end()) {
|
if (parent_it == cacheNullifiers.end()) {
|
||||||
if (child_it->second.entered) {
|
if (child_it->second.entered) {
|
||||||
// Parent doesn't have an entry, but child has a SPENT serial.
|
// Parent doesn't have an entry, but child has a SPENT nullifier.
|
||||||
// Move the spent serial up.
|
// Move the spent nullifier up.
|
||||||
|
|
||||||
CSerialsCacheEntry& entry = cacheSerials[child_it->first];
|
CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
|
||||||
entry.entered = true;
|
entry.entered = true;
|
||||||
entry.flags = CSerialsCacheEntry::DIRTY;
|
entry.flags = CNullifiersCacheEntry::DIRTY;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (parent_it->second.entered != child_it->second.entered) {
|
if (parent_it->second.entered != child_it->second.entered) {
|
||||||
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++;
|
CNullifiersMap::iterator itOld = child_it++;
|
||||||
mapSerials.erase(itOld);
|
mapNullifiers.erase(itOld);
|
||||||
}
|
}
|
||||||
|
|
||||||
hashAnchor = hashAnchorIn;
|
hashAnchor = hashAnchorIn;
|
||||||
|
@ -357,10 +357,10 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCoinsViewCache::Flush() {
|
bool CCoinsViewCache::Flush() {
|
||||||
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheSerials);
|
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheNullifiers);
|
||||||
cacheCoins.clear();
|
cacheCoins.clear();
|
||||||
cacheAnchors.clear();
|
cacheAnchors.clear();
|
||||||
cacheSerials.clear();
|
cacheNullifiers.clear();
|
||||||
cachedCoinsUsage = 0;
|
cachedCoinsUsage = 0;
|
||||||
return fOk;
|
return fOk;
|
||||||
}
|
}
|
||||||
|
@ -385,35 +385,35 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
nResult += GetOutputFor(tx.vin[i]).nValue;
|
nResult += GetOutputFor(tx.vin[i]).nValue;
|
||||||
|
|
||||||
nResult += tx.GetPourValueIn();
|
nResult += tx.GetJoinSplitValueIn();
|
||||||
|
|
||||||
return nResult;
|
return nResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCoinsViewCache::HavePourRequirements(const CTransaction& tx) const
|
bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
|
||||||
{
|
{
|
||||||
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
|
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 (GetNullifier(nullifier)) {
|
||||||
// If the serial is set, this transaction
|
// If the nullifier is set, this transaction
|
||||||
// double-spends!
|
// double-spends!
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ZCIncrementalMerkleTree tree;
|
ZCIncrementalMerkleTree tree;
|
||||||
auto it = intermediates.find(pour.anchor);
|
auto it = intermediates.find(joinsplit.anchor);
|
||||||
if (it != intermediates.end()) {
|
if (it != intermediates.end()) {
|
||||||
tree = it->second;
|
tree = it->second;
|
||||||
} else if (!GetAnchorAt(pour.anchor, tree)) {
|
} else if (!GetAnchorAt(joinsplit.anchor, tree)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FOREACH(const uint256& commitment, pour.commitments)
|
BOOST_FOREACH(const uint256& commitment, joinsplit.commitments)
|
||||||
{
|
{
|
||||||
tree.append(commitment);
|
tree.append(commitment);
|
||||||
}
|
}
|
||||||
|
|
32
src/coins.h
32
src/coins.h
|
@ -309,21 +309,21 @@ struct CAnchorsCacheEntry
|
||||||
CAnchorsCacheEntry() : entered(false), flags(0) {}
|
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;
|
unsigned char flags;
|
||||||
|
|
||||||
enum Flags {
|
enum Flags {
|
||||||
DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
|
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, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
|
||||||
typedef boost::unordered_map<uint256, CAnchorsCacheEntry, CCoinsKeyHasher> CAnchorsMap;
|
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
|
struct CCoinsStats
|
||||||
{
|
{
|
||||||
|
@ -346,8 +346,8 @@ public:
|
||||||
//! Retrieve the tree at a particular anchored root in the chain
|
//! Retrieve the tree at a particular anchored root in the chain
|
||||||
virtual bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
|
virtual bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
|
||||||
|
|
||||||
//! Determine whether a serial is spent or not
|
//! Determine whether a nullifier is spent or not
|
||||||
virtual bool GetSerial(const uint256 &serial) const;
|
virtual bool GetNullifier(const uint256 &nullifier) const;
|
||||||
|
|
||||||
//! Retrieve the CCoins (unspent transaction outputs) for a given txid
|
//! Retrieve the CCoins (unspent transaction outputs) for a given txid
|
||||||
virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
|
virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
|
||||||
|
@ -368,7 +368,7 @@ public:
|
||||||
const uint256 &hashBlock,
|
const uint256 &hashBlock,
|
||||||
const uint256 &hashAnchor,
|
const uint256 &hashAnchor,
|
||||||
CAnchorsMap &mapAnchors,
|
CAnchorsMap &mapAnchors,
|
||||||
CSerialsMap &mapSerials);
|
CNullifiersMap &mapNullifiers);
|
||||||
|
|
||||||
//! Calculate statistics about the unspent transaction output set
|
//! Calculate statistics about the unspent transaction output set
|
||||||
virtual bool GetStats(CCoinsStats &stats) const;
|
virtual bool GetStats(CCoinsStats &stats) const;
|
||||||
|
@ -387,7 +387,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
CCoinsViewBacked(CCoinsView *viewIn);
|
CCoinsViewBacked(CCoinsView *viewIn);
|
||||||
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
|
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 GetCoins(const uint256 &txid, CCoins &coins) const;
|
||||||
bool HaveCoins(const uint256 &txid) const;
|
bool HaveCoins(const uint256 &txid) const;
|
||||||
uint256 GetBestBlock() const;
|
uint256 GetBestBlock() const;
|
||||||
|
@ -397,7 +397,7 @@ public:
|
||||||
const uint256 &hashBlock,
|
const uint256 &hashBlock,
|
||||||
const uint256 &hashAnchor,
|
const uint256 &hashAnchor,
|
||||||
CAnchorsMap &mapAnchors,
|
CAnchorsMap &mapAnchors,
|
||||||
CSerialsMap &mapSerials);
|
CNullifiersMap &mapNullifiers);
|
||||||
bool GetStats(CCoinsStats &stats) const;
|
bool GetStats(CCoinsStats &stats) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ protected:
|
||||||
mutable CCoinsMap cacheCoins;
|
mutable CCoinsMap cacheCoins;
|
||||||
mutable uint256 hashAnchor;
|
mutable uint256 hashAnchor;
|
||||||
mutable CAnchorsMap cacheAnchors;
|
mutable CAnchorsMap cacheAnchors;
|
||||||
mutable CSerialsMap cacheSerials;
|
mutable CNullifiersMap cacheNullifiers;
|
||||||
|
|
||||||
/* Cached dynamic memory usage for the inner CCoins objects. */
|
/* Cached dynamic memory usage for the inner CCoins objects. */
|
||||||
mutable size_t cachedCoinsUsage;
|
mutable size_t cachedCoinsUsage;
|
||||||
|
@ -451,7 +451,7 @@ public:
|
||||||
|
|
||||||
// Standard CCoinsView methods
|
// Standard CCoinsView methods
|
||||||
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
|
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 GetCoins(const uint256 &txid, CCoins &coins) const;
|
||||||
bool HaveCoins(const uint256 &txid) const;
|
bool HaveCoins(const uint256 &txid) const;
|
||||||
uint256 GetBestBlock() const;
|
uint256 GetBestBlock() const;
|
||||||
|
@ -461,7 +461,7 @@ public:
|
||||||
const uint256 &hashBlock,
|
const uint256 &hashBlock,
|
||||||
const uint256 &hashAnchor,
|
const uint256 &hashAnchor,
|
||||||
CAnchorsMap &mapAnchors,
|
CAnchorsMap &mapAnchors,
|
||||||
CSerialsMap &mapSerials);
|
CNullifiersMap &mapNullifiers);
|
||||||
|
|
||||||
|
|
||||||
// Adds the tree to mapAnchors and sets the current commitment
|
// Adds the tree to mapAnchors and sets the current commitment
|
||||||
|
@ -472,8 +472,8 @@ public:
|
||||||
// the new current root.
|
// the new current root.
|
||||||
void PopAnchor(const uint256 &rt);
|
void PopAnchor(const uint256 &rt);
|
||||||
|
|
||||||
// Marks a serial as spent or not.
|
// Marks a nullifier as spent or not.
|
||||||
void SetSerial(const uint256 &serial, bool spent);
|
void SetNullifier(const uint256 &nullifier, bool spent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a pointer to CCoins in the cache, or NULL if not found. This is
|
* 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
|
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
|
||||||
bool HaveInputs(const CTransaction& tx) const;
|
bool HaveInputs(const CTransaction& tx) const;
|
||||||
|
|
||||||
//! Check whether all pour requirements (anchors/serials) are satisfied
|
//! Check whether all joinsplit requirements (anchors/nullifiers) are satisfied
|
||||||
bool HavePourRequirements(const CTransaction& tx) const;
|
bool HaveJoinSplitRequirements(const CTransaction& tx) const;
|
||||||
|
|
||||||
//! Return priority of tx at height nHeight
|
//! Return priority of tx at height nHeight
|
||||||
double GetPriority(const CTransaction &tx, int nHeight) const;
|
double GetPriority(const CTransaction &tx, int nHeight) const;
|
||||||
|
|
|
@ -11,15 +11,15 @@ TEST(checktransaction_tests, check_vpub_not_both_nonzero) {
|
||||||
tx.nVersion = 2;
|
tx.nVersion = 2;
|
||||||
|
|
||||||
{
|
{
|
||||||
// Ensure that values within the pour are well-formed.
|
// Ensure that values within the joinsplit are well-formed.
|
||||||
CMutableTransaction newTx(tx);
|
CMutableTransaction newTx(tx);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
||||||
newTx.vpour.push_back(CPourTx());
|
newTx.vjoinsplit.push_back(JSDescription());
|
||||||
|
|
||||||
CPourTx *pourtx = &newTx.vpour[0];
|
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||||
pourtx->vpub_old = 1;
|
jsdesc->vpub_old = 1;
|
||||||
pourtx->vpub_new = 1;
|
jsdesc->vpub_new = 1;
|
||||||
|
|
||||||
EXPECT_FALSE(CheckTransactionWithoutProofVerification(newTx, state));
|
EXPECT_FALSE(CheckTransactionWithoutProofVerification(newTx, state));
|
||||||
EXPECT_EQ(state.GetRejectReason(), "bad-txns-vpubs-both-nonzero");
|
EXPECT_EQ(state.GetRejectReason(), "bad-txns-vpubs-both-nonzero");
|
||||||
|
@ -55,11 +55,11 @@ CMutableTransaction GetValidTransaction() {
|
||||||
// mtx.vout[0].scriptPubKey =
|
// mtx.vout[0].scriptPubKey =
|
||||||
mtx.vout[0].nValue = 0;
|
mtx.vout[0].nValue = 0;
|
||||||
mtx.vout[1].nValue = 0;
|
mtx.vout[1].nValue = 0;
|
||||||
mtx.vpour.resize(2);
|
mtx.vjoinsplit.resize(2);
|
||||||
mtx.vpour[0].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
mtx.vpour[0].serials.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
|
mtx.vjoinsplit[0].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
mtx.vpour[1].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
|
mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000002");
|
||||||
mtx.vpour[1].serials.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
|
mtx.vjoinsplit[1].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000003");
|
||||||
|
|
||||||
|
|
||||||
// Generate an ephemeral keypair.
|
// Generate an ephemeral keypair.
|
||||||
|
@ -96,7 +96,7 @@ TEST(checktransaction_tests, valid_transaction) {
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_vin_empty) {
|
TEST(checktransaction_tests, bad_txns_vin_empty) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour.resize(0);
|
mtx.vjoinsplit.resize(0);
|
||||||
mtx.vin.resize(0);
|
mtx.vin.resize(0);
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
@ -107,7 +107,7 @@ TEST(checktransaction_tests, bad_txns_vin_empty) {
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_vout_empty) {
|
TEST(checktransaction_tests, bad_txns_vout_empty) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour.resize(0);
|
mtx.vjoinsplit.resize(0);
|
||||||
mtx.vout.resize(0);
|
mtx.vout.resize(0);
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
@ -171,7 +171,7 @@ TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_outputs) {
|
||||||
TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_joinsplit) {
|
TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_joinsplit) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vout[0].nValue = 1;
|
mtx.vout[0].nValue = 1;
|
||||||
mtx.vpour[0].vpub_new = MAX_MONEY;
|
mtx.vjoinsplit[0].vpub_new = MAX_MONEY;
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_joinsplit) {
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_vpub_old_negative) {
|
TEST(checktransaction_tests, bad_txns_vpub_old_negative) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour[0].vpub_old = -1;
|
mtx.vjoinsplit[0].vpub_old = -1;
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ TEST(checktransaction_tests, bad_txns_vpub_old_negative) {
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_vpub_new_negative) {
|
TEST(checktransaction_tests, bad_txns_vpub_new_negative) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour[0].vpub_new = -1;
|
mtx.vjoinsplit[0].vpub_new = -1;
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ TEST(checktransaction_tests, bad_txns_vpub_new_negative) {
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_vpub_old_toolarge) {
|
TEST(checktransaction_tests, bad_txns_vpub_old_toolarge) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour[0].vpub_old = MAX_MONEY + 1;
|
mtx.vjoinsplit[0].vpub_old = MAX_MONEY + 1;
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ TEST(checktransaction_tests, bad_txns_vpub_old_toolarge) {
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_vpub_new_toolarge) {
|
TEST(checktransaction_tests, bad_txns_vpub_new_toolarge) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour[0].vpub_new = MAX_MONEY + 1;
|
mtx.vjoinsplit[0].vpub_new = MAX_MONEY + 1;
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
|
@ -226,8 +226,8 @@ TEST(checktransaction_tests, bad_txns_vpub_new_toolarge) {
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_vpubs_both_nonzero) {
|
TEST(checktransaction_tests, bad_txns_vpubs_both_nonzero) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour[0].vpub_old = 1;
|
mtx.vjoinsplit[0].vpub_old = 1;
|
||||||
mtx.vpour[0].vpub_new = 1;
|
mtx.vjoinsplit[0].vpub_new = 1;
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
|
@ -248,43 +248,43 @@ TEST(checktransaction_tests, bad_txns_inputs_duplicate) {
|
||||||
CheckTransactionWithoutProofVerification(tx, state);
|
CheckTransactionWithoutProofVerification(tx, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_pours_serials_duplicate_same_pour) {
|
TEST(checktransaction_tests, bad_joinsplits_nullifiers_duplicate_same_joinsplit) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour[0].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
mtx.vpour[0].serials.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
mtx.vjoinsplit[0].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
MockCValidationState state;
|
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);
|
CheckTransactionWithoutProofVerification(tx, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_pours_serials_duplicate_different_pour) {
|
TEST(checktransaction_tests, bad_joinsplits_nullifiers_duplicate_different_joinsplit) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.vpour[0].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
mtx.vjoinsplit[0].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
mtx.vpour[1].serials.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
MockCValidationState state;
|
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);
|
CheckTransactionWithoutProofVerification(tx, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_cb_has_pours) {
|
TEST(checktransaction_tests, bad_cb_has_joinsplits) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
// Make it a coinbase.
|
// Make it a coinbase.
|
||||||
mtx.vin.resize(1);
|
mtx.vin.resize(1);
|
||||||
mtx.vin[0].prevout.SetNull();
|
mtx.vin[0].prevout.SetNull();
|
||||||
|
|
||||||
mtx.vpour.resize(1);
|
mtx.vjoinsplit.resize(1);
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
EXPECT_TRUE(tx.IsCoinBase());
|
EXPECT_TRUE(tx.IsCoinBase());
|
||||||
|
|
||||||
MockCValidationState state;
|
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);
|
CheckTransactionWithoutProofVerification(tx, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ TEST(checktransaction_tests, bad_cb_empty_scriptsig) {
|
||||||
mtx.vin.resize(1);
|
mtx.vin.resize(1);
|
||||||
mtx.vin[0].prevout.SetNull();
|
mtx.vin[0].prevout.SetNull();
|
||||||
|
|
||||||
mtx.vpour.resize(0);
|
mtx.vjoinsplit.resize(0);
|
||||||
|
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
EXPECT_TRUE(tx.IsCoinBase());
|
EXPECT_TRUE(tx.IsCoinBase());
|
||||||
|
|
124
src/main.cpp
124
src/main.cpp
|
@ -876,10 +876,10 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// Ensure that zk-SNARKs verify
|
// Ensure that zk-SNARKs verify
|
||||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
|
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||||
if (!pour.Verify(*pzcashParams, tx.joinSplitPubKey)) {
|
if (!joinsplit.Verify(*pzcashParams, tx.joinSplitPubKey)) {
|
||||||
return state.DoS(100, error("CheckTransaction(): pour does not verify"),
|
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
|
||||||
REJECT_INVALID, "bad-txns-pour-verification-failed");
|
REJECT_INVALID, "bad-txns-joinsplit-verification-failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -891,11 +891,11 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
||||||
// Basic checks that don't depend on any context
|
// Basic checks that don't depend on any context
|
||||||
|
|
||||||
// Transactions can contain empty `vin` and `vout` so long as
|
// Transactions can contain empty `vin` and `vout` so long as
|
||||||
// `vpour` is non-empty.
|
// `vjoinsplit` is non-empty.
|
||||||
if (tx.vin.empty() && tx.vpour.empty())
|
if (tx.vin.empty() && tx.vjoinsplit.empty())
|
||||||
return state.DoS(10, error("CheckTransaction(): vin empty"),
|
return state.DoS(10, error("CheckTransaction(): vin empty"),
|
||||||
REJECT_INVALID, "bad-txns-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"),
|
return state.DoS(10, error("CheckTransaction(): vout empty"),
|
||||||
REJECT_INVALID, "bad-txns-vout-empty");
|
REJECT_INVALID, "bad-txns-vout-empty");
|
||||||
|
|
||||||
|
@ -920,35 +920,35 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
||||||
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that pour values are well-formed
|
// Ensure that joinsplit values are well-formed
|
||||||
BOOST_FOREACH(const CPourTx& pour, tx.vpour)
|
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit)
|
||||||
{
|
{
|
||||||
if (pour.vpub_old < 0) {
|
if (joinsplit.vpub_old < 0) {
|
||||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_old negative"),
|
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_old negative"),
|
||||||
REJECT_INVALID, "bad-txns-vpub_old-negative");
|
REJECT_INVALID, "bad-txns-vpub_old-negative");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pour.vpub_new < 0) {
|
if (joinsplit.vpub_new < 0) {
|
||||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_new negative"),
|
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new negative"),
|
||||||
REJECT_INVALID, "bad-txns-vpub_new-negative");
|
REJECT_INVALID, "bad-txns-vpub_new-negative");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pour.vpub_old > MAX_MONEY) {
|
if (joinsplit.vpub_old > MAX_MONEY) {
|
||||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_old too high"),
|
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_old too high"),
|
||||||
REJECT_INVALID, "bad-txns-vpub_old-toolarge");
|
REJECT_INVALID, "bad-txns-vpub_old-toolarge");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pour.vpub_new > MAX_MONEY) {
|
if (joinsplit.vpub_new > MAX_MONEY) {
|
||||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_new too high"),
|
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new too high"),
|
||||||
REJECT_INVALID, "bad-txns-vpub_new-toolarge");
|
REJECT_INVALID, "bad-txns-vpub_new-toolarge");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pour.vpub_new != 0 && pour.vpub_old != 0) {
|
if (joinsplit.vpub_new != 0 && joinsplit.vpub_old != 0) {
|
||||||
return state.DoS(100, error("CheckTransaction(): pour.vpub_new and pour.vpub_old both nonzero"),
|
return state.DoS(100, error("CheckTransaction(): joinsplit.vpub_new and joinsplit.vpub_old both nonzero"),
|
||||||
REJECT_INVALID, "bad-txns-vpubs-both-nonzero");
|
REJECT_INVALID, "bad-txns-vpubs-both-nonzero");
|
||||||
}
|
}
|
||||||
|
|
||||||
nValueOut += pour.vpub_new;
|
nValueOut += joinsplit.vpub_new;
|
||||||
if (!MoneyRange(nValueOut)) {
|
if (!MoneyRange(nValueOut)) {
|
||||||
return state.DoS(100, error("CheckTransaction(): txout total out of range"),
|
return state.DoS(100, error("CheckTransaction(): txout total out of range"),
|
||||||
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
REJECT_INVALID, "bad-txns-txouttotal-toolarge");
|
||||||
|
@ -966,26 +966,26 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
||||||
vInOutPoints.insert(txin.prevout);
|
vInOutPoints.insert(txin.prevout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate pour serials in this transaction
|
// Check for duplicate joinsplit nullifiers in this transaction
|
||||||
set<uint256> vPourSerials;
|
set<uint256> vJoinSplitNullifiers;
|
||||||
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& nf, joinsplit.nullifiers)
|
||||||
{
|
{
|
||||||
if (vPourSerials.count(serial))
|
if (vJoinSplitNullifiers.count(nf))
|
||||||
return state.DoS(100, error("CheckTransaction(): duplicate serials"),
|
return state.DoS(100, error("CheckTransaction(): duplicate nullifiers"),
|
||||||
REJECT_INVALID, "bad-pours-serials-duplicate");
|
REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate");
|
||||||
|
|
||||||
vPourSerials.insert(serial);
|
vJoinSplitNullifiers.insert(nf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.IsCoinBase())
|
if (tx.IsCoinBase())
|
||||||
{
|
{
|
||||||
// There should be no pours in a coinbase transaction
|
// There should be no joinsplits in a coinbase transaction
|
||||||
if (tx.vpour.size() > 0)
|
if (tx.vjoinsplit.size() > 0)
|
||||||
return state.DoS(100, error("CheckTransaction(): coinbase has pours"),
|
return state.DoS(100, error("CheckTransaction(): coinbase has joinsplits"),
|
||||||
REJECT_INVALID, "bad-cb-has-pours");
|
REJECT_INVALID, "bad-cb-has-joinsplits");
|
||||||
|
|
||||||
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
|
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
|
||||||
return state.DoS(100, error("CheckTransaction(): coinbase script size"),
|
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"),
|
return state.DoS(10, error("CheckTransaction(): prevout is null"),
|
||||||
REJECT_INVALID, "bad-txns-prevout-null");
|
REJECT_INVALID, "bad-txns-prevout-null");
|
||||||
|
|
||||||
if (tx.vpour.size() > 0) {
|
if (tx.vjoinsplit.size() > 0) {
|
||||||
// TODO: #966.
|
// TODO: #966.
|
||||||
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
|
@ -1104,9 +1104,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 &nf, joinsplit.nullifiers) {
|
||||||
if (pool.mapSerials.count(serial))
|
if (pool.mapNullifiers.count(nf))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1144,10 +1144,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||||
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),
|
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),
|
||||||
REJECT_DUPLICATE, "bad-txns-inputs-spent");
|
REJECT_DUPLICATE, "bad-txns-inputs-spent");
|
||||||
|
|
||||||
// are the pour's requirements met?
|
// are the joinsplit's requirements met?
|
||||||
if (!view.HavePourRequirements(tx))
|
if (!view.HaveJoinSplitRequirements(tx))
|
||||||
return state.Invalid(error("AcceptToMemoryPool: pour requirements not met"),
|
return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),
|
||||||
REJECT_DUPLICATE, "bad-txns-pour-requirements-not-met");
|
REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met");
|
||||||
|
|
||||||
// Bring the best block into scope
|
// Bring the best block into scope
|
||||||
view.GetBestBlock();
|
view.GetBestBlock();
|
||||||
|
@ -1585,10 +1585,10 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// spend serials
|
// spend nullifiers
|
||||||
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 &nf, joinsplit.nullifiers) {
|
||||||
inputs.SetSerial(serial, true);
|
inputs.SetNullifier(nf, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1622,9 +1622,9 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
|
||||||
if (!inputs.HaveInputs(tx))
|
if (!inputs.HaveInputs(tx))
|
||||||
return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString()));
|
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.HavePourRequirements(tx))
|
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 nValueIn = 0;
|
||||||
CAmount nFees = 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))
|
if (!MoneyRange(nValueIn))
|
||||||
return state.DoS(100, error("CheckInputs(): vpub_old values out of range"),
|
return state.DoS(100, error("CheckInputs(): vpub_old values out of range"),
|
||||||
REJECT_INVALID, "bad-txns-inputvalues-outofrange");
|
REJECT_INVALID, "bad-txns-inputvalues-outofrange");
|
||||||
|
@ -1907,10 +1907,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||||
outs->Clear();
|
outs->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// unspend serials
|
// unspend nullifiers
|
||||||
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 &nf, joinsplit.nullifiers) {
|
||||||
view.SetSerial(serial, false);
|
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"),
|
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
|
||||||
REJECT_INVALID, "bad-txns-inputs-missingorspent");
|
REJECT_INVALID, "bad-txns-inputs-missingorspent");
|
||||||
|
|
||||||
// are the pour's requirements met?
|
// are the JoinSplit's requirements met?
|
||||||
if (!view.HavePourRequirements(tx))
|
if (!view.HaveJoinSplitRequirements(tx))
|
||||||
return state.DoS(100, error("ConnectBlock(): pour requirements not met"),
|
return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"),
|
||||||
REJECT_INVALID, "bad-txns-pour-requirements-not-met");
|
REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met");
|
||||||
|
|
||||||
// Add in sigops done by pay-to-script-hash inputs;
|
// Add in sigops done by pay-to-script-hash inputs;
|
||||||
// this is to prevent a "rogue miner" from creating
|
// 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);
|
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
|
||||||
|
|
||||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
|
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
|
||||||
BOOST_FOREACH(const uint256 &bucket_commitment, pour.commitments) {
|
BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) {
|
||||||
// Insert the bucket commitments into our temporary tree.
|
// 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)
|
BOOST_FOREACH(uint256 hash, vEraseQueue)
|
||||||
EraseOrphanTx(hash);
|
EraseOrphanTx(hash);
|
||||||
}
|
}
|
||||||
// TODO: currently, prohibit pours from entering mapOrphans
|
// TODO: currently, prohibit joinsplits from entering mapOrphans
|
||||||
else if (fMissingInputs && tx.vpour.size() == 0)
|
else if (fMissingInputs && tx.vjoinsplit.size() == 0)
|
||||||
{
|
{
|
||||||
AddOrphanTx(tx, pfrom->GetId());
|
AddOrphanTx(tx, pfrom->GetId());
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "tinyformat.h"
|
#include "tinyformat.h"
|
||||||
#include "utilstrencodings.h"
|
#include "utilstrencodings.h"
|
||||||
|
|
||||||
CPourTx::CPourTx(ZCJoinSplit& params,
|
JSDescription::JSDescription(ZCJoinSplit& params,
|
||||||
const uint256& pubKeyHash,
|
const uint256& pubKeyHash,
|
||||||
const uint256& anchor,
|
const uint256& anchor,
|
||||||
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||||
|
@ -29,7 +29,7 @@ CPourTx::CPourTx(ZCJoinSplit& params,
|
||||||
pubKeyHash,
|
pubKeyHash,
|
||||||
randomSeed,
|
randomSeed,
|
||||||
macs,
|
macs,
|
||||||
serials,
|
nullifiers,
|
||||||
commitments,
|
commitments,
|
||||||
vpub_old,
|
vpub_old,
|
||||||
vpub_new,
|
vpub_new,
|
||||||
|
@ -37,7 +37,7 @@ CPourTx::CPourTx(ZCJoinSplit& params,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPourTx::Verify(
|
bool JSDescription::Verify(
|
||||||
ZCJoinSplit& params,
|
ZCJoinSplit& params,
|
||||||
const uint256& pubKeyHash
|
const uint256& pubKeyHash
|
||||||
) const {
|
) const {
|
||||||
|
@ -46,7 +46,7 @@ bool CPourTx::Verify(
|
||||||
pubKeyHash,
|
pubKeyHash,
|
||||||
randomSeed,
|
randomSeed,
|
||||||
macs,
|
macs,
|
||||||
serials,
|
nullifiers,
|
||||||
commitments,
|
commitments,
|
||||||
vpub_old,
|
vpub_old,
|
||||||
vpub_new,
|
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
|
std::string COutPoint::ToString() const
|
||||||
|
@ -111,7 +111,7 @@ std::string CTxOut::ToString() const
|
||||||
|
|
||||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
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),
|
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);
|
*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)
|
joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
|
||||||
{
|
{
|
||||||
UpdateHash();
|
UpdateHash();
|
||||||
|
@ -139,7 +139,7 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
|
||||||
*const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
|
*const_cast<std::vector<CTxIn>*>(&vin) = tx.vin;
|
||||||
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
|
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
|
||||||
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
|
*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<uint256*>(&joinSplitPubKey) = tx.joinSplitPubKey;
|
||||||
*const_cast<joinsplit_sig_t*>(&joinSplitSig) = tx.joinSplitSig;
|
*const_cast<joinsplit_sig_t*>(&joinSplitSig) = tx.joinSplitSig;
|
||||||
*const_cast<uint256*>(&hash) = tx.hash;
|
*const_cast<uint256*>(&hash) = tx.hash;
|
||||||
|
@ -156,7 +156,7 @@ CAmount CTransaction::GetValueOut() const
|
||||||
throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
|
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
|
// NB: vpub_old "takes" money from the value pool just as outputs do
|
||||||
nValueOut += it->vpub_old;
|
nValueOut += it->vpub_old;
|
||||||
|
@ -167,16 +167,16 @@ CAmount CTransaction::GetValueOut() const
|
||||||
return nValueOut;
|
return nValueOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CTransaction::GetPourValueIn() const
|
CAmount CTransaction::GetJoinSplitValueIn() const
|
||||||
{
|
{
|
||||||
CAmount nValue = 0;
|
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
|
// NB: vpub_new "gives" money to the value pool just as inputs do
|
||||||
nValue += it->vpub_new;
|
nValue += it->vpub_new;
|
||||||
|
|
||||||
if (!MoneyRange(it->vpub_new) || !MoneyRange(nValue))
|
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;
|
return nValue;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "zcash/Zcash.h"
|
#include "zcash/Zcash.h"
|
||||||
#include "zcash/JoinSplit.hpp"
|
#include "zcash/JoinSplit.hpp"
|
||||||
|
|
||||||
class CPourTx
|
class JSDescription
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// These values 'enter from' and 'exit to' the value
|
// These values 'enter from' and 'exit to' the value
|
||||||
|
@ -25,22 +25,22 @@ public:
|
||||||
CAmount vpub_old;
|
CAmount vpub_old;
|
||||||
CAmount vpub_new;
|
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
|
// commitment tree at some point in the blockchain
|
||||||
// history or in the history of the current
|
// history or in the history of the current
|
||||||
// transaction.
|
// transaction.
|
||||||
uint256 anchor;
|
uint256 anchor;
|
||||||
|
|
||||||
// Serials are used to prevent double-spends. They
|
// Nullifiers are used to prevent double-spends. They
|
||||||
// are derived from the secrets placed in the bucket
|
// are derived from the secrets placed in the note
|
||||||
// and the secret spend-authority key known by the
|
// and the secret spend-authority key known by the
|
||||||
// spender.
|
// 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
|
// 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
|
||||||
// commitment in the bucket commitment tree is required
|
// a commitment in the note commitment tree is required
|
||||||
// to spend it.
|
// to spend it.
|
||||||
boost::array<uint256, ZC_NUM_JS_OUTPUTS> commitments;
|
boost::array<uint256, ZC_NUM_JS_OUTPUTS> commitments;
|
||||||
|
|
||||||
|
@ -57,17 +57,17 @@ public:
|
||||||
uint256 randomSeed;
|
uint256 randomSeed;
|
||||||
|
|
||||||
// MACs
|
// MACs
|
||||||
// The verification of the pour requires these MACs
|
// The verification of the JoinSplit requires these MACs
|
||||||
// to be provided as an input.
|
// to be provided as an input.
|
||||||
boost::array<uint256, ZC_NUM_JS_INPUTS> macs;
|
boost::array<uint256, ZC_NUM_JS_INPUTS> macs;
|
||||||
|
|
||||||
// Pour proof
|
// JoinSplit proof
|
||||||
// This is a zk-SNARK which ensures that this pour is valid.
|
// This is a zk-SNARK which ensures that this JoinSplit is valid.
|
||||||
boost::array<unsigned char, ZKSNARK_PROOF_SIZE> proof;
|
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& pubKeyHash,
|
||||||
const uint256& rt,
|
const uint256& rt,
|
||||||
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
|
||||||
|
@ -76,7 +76,7 @@ public:
|
||||||
CAmount vpub_new
|
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;
|
bool Verify(ZCJoinSplit& params, const uint256& pubKeyHash) const;
|
||||||
|
|
||||||
// Returns the calculated h_sig
|
// Returns the calculated h_sig
|
||||||
|
@ -89,7 +89,7 @@ public:
|
||||||
READWRITE(vpub_old);
|
READWRITE(vpub_old);
|
||||||
READWRITE(vpub_new);
|
READWRITE(vpub_new);
|
||||||
READWRITE(anchor);
|
READWRITE(anchor);
|
||||||
READWRITE(serials);
|
READWRITE(nullifiers);
|
||||||
READWRITE(commitments);
|
READWRITE(commitments);
|
||||||
READWRITE(ephemeralKey);
|
READWRITE(ephemeralKey);
|
||||||
READWRITE(ciphertexts);
|
READWRITE(ciphertexts);
|
||||||
|
@ -98,13 +98,13 @@ public:
|
||||||
READWRITE(proof);
|
READWRITE(proof);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(const CPourTx& a, const CPourTx& b)
|
friend bool operator==(const JSDescription& a, const JSDescription& b)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
a.vpub_old == b.vpub_old &&
|
a.vpub_old == b.vpub_old &&
|
||||||
a.vpub_new == b.vpub_new &&
|
a.vpub_new == b.vpub_new &&
|
||||||
a.anchor == b.anchor &&
|
a.anchor == b.anchor &&
|
||||||
a.serials == b.serials &&
|
a.nullifiers == b.nullifiers &&
|
||||||
a.commitments == b.commitments &&
|
a.commitments == b.commitments &&
|
||||||
a.ephemeralKey == b.ephemeralKey &&
|
a.ephemeralKey == b.ephemeralKey &&
|
||||||
a.ciphertexts == b.ciphertexts &&
|
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);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,7 @@ public:
|
||||||
const std::vector<CTxIn> vin;
|
const std::vector<CTxIn> vin;
|
||||||
const std::vector<CTxOut> vout;
|
const std::vector<CTxOut> vout;
|
||||||
const uint32_t nLockTime;
|
const uint32_t nLockTime;
|
||||||
const std::vector<CPourTx> vpour;
|
const std::vector<JSDescription> vjoinsplit;
|
||||||
const uint256 joinSplitPubKey;
|
const uint256 joinSplitPubKey;
|
||||||
const joinsplit_sig_t joinSplitSig;
|
const joinsplit_sig_t joinSplitSig;
|
||||||
|
|
||||||
|
@ -325,8 +325,8 @@ public:
|
||||||
READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
|
READWRITE(*const_cast<std::vector<CTxOut>*>(&vout));
|
||||||
READWRITE(*const_cast<uint32_t*>(&nLockTime));
|
READWRITE(*const_cast<uint32_t*>(&nLockTime));
|
||||||
if (nVersion >= 2) {
|
if (nVersion >= 2) {
|
||||||
READWRITE(*const_cast<std::vector<CPourTx>*>(&vpour));
|
READWRITE(*const_cast<std::vector<JSDescription>*>(&vjoinsplit));
|
||||||
if (vpour.size() > 0) {
|
if (vjoinsplit.size() > 0) {
|
||||||
READWRITE(*const_cast<uint256*>(&joinSplitPubKey));
|
READWRITE(*const_cast<uint256*>(&joinSplitPubKey));
|
||||||
READWRITE(*const_cast<joinsplit_sig_t*>(&joinSplitSig));
|
READWRITE(*const_cast<joinsplit_sig_t*>(&joinSplitSig));
|
||||||
}
|
}
|
||||||
|
@ -348,8 +348,8 @@ public:
|
||||||
// GetValueIn() is a method on CCoinsViewCache, because
|
// GetValueIn() is a method on CCoinsViewCache, because
|
||||||
// inputs must be known to compute value in.
|
// inputs must be known to compute value in.
|
||||||
|
|
||||||
// Return sum of pour vpub_new
|
// Return sum of JoinSplit vpub_new
|
||||||
CAmount GetPourValueIn() const;
|
CAmount GetJoinSplitValueIn() const;
|
||||||
|
|
||||||
// Compute priority, given priority of inputs and (optionally) tx size
|
// Compute priority, given priority of inputs and (optionally) tx size
|
||||||
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
|
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
|
||||||
|
@ -382,7 +382,7 @@ struct CMutableTransaction
|
||||||
std::vector<CTxIn> vin;
|
std::vector<CTxIn> vin;
|
||||||
std::vector<CTxOut> vout;
|
std::vector<CTxOut> vout;
|
||||||
uint32_t nLockTime;
|
uint32_t nLockTime;
|
||||||
std::vector<CPourTx> vpour;
|
std::vector<JSDescription> vjoinsplit;
|
||||||
uint256 joinSplitPubKey;
|
uint256 joinSplitPubKey;
|
||||||
CTransaction::joinsplit_sig_t joinSplitSig;
|
CTransaction::joinsplit_sig_t joinSplitSig;
|
||||||
|
|
||||||
|
@ -399,8 +399,8 @@ struct CMutableTransaction
|
||||||
READWRITE(vout);
|
READWRITE(vout);
|
||||||
READWRITE(nLockTime);
|
READWRITE(nLockTime);
|
||||||
if (nVersion >= 2) {
|
if (nVersion >= 2) {
|
||||||
READWRITE(vpour);
|
READWRITE(vjoinsplit);
|
||||||
if (vpour.size() > 0) {
|
if (vjoinsplit.size() > 0) {
|
||||||
READWRITE(joinSplitPubKey);
|
READWRITE(joinSplitPubKey);
|
||||||
READWRITE(joinSplitSig);
|
READWRITE(joinSplitSig);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,10 +91,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
{ "estimatepriority", 0 },
|
{ "estimatepriority", 0 },
|
||||||
{ "prioritisetransaction", 1 },
|
{ "prioritisetransaction", 1 },
|
||||||
{ "prioritisetransaction", 2 },
|
{ "prioritisetransaction", 2 },
|
||||||
{ "zcrawpour", 1 },
|
{ "zcrawjoinsplit", 1 },
|
||||||
{ "zcrawpour", 2 },
|
{ "zcrawjoinsplit", 2 },
|
||||||
{ "zcrawpour", 3 },
|
{ "zcrawjoinsplit", 3 },
|
||||||
{ "zcrawpour", 4 },
|
{ "zcrawjoinsplit", 4 },
|
||||||
{ "zcbenchmark", 1 },
|
{ "zcbenchmark", 1 },
|
||||||
{ "getblocksubsidy", 0}
|
{ "getblocksubsidy", 0}
|
||||||
};
|
};
|
||||||
|
|
|
@ -90,48 +90,48 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
|
||||||
}
|
}
|
||||||
entry.push_back(Pair("vout", vout));
|
entry.push_back(Pair("vout", vout));
|
||||||
|
|
||||||
Array vpour;
|
Array vjoinsplit;
|
||||||
for (unsigned int i = 0; i < tx.vpour.size(); i++) {
|
for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) {
|
||||||
const CPourTx& pourtx = tx.vpour[i];
|
const JSDescription& jsdescription = tx.vjoinsplit[i];
|
||||||
Object pour;
|
Object joinsplit;
|
||||||
|
|
||||||
pour.push_back(Pair("anchor", pourtx.anchor.GetHex()));
|
joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex()));
|
||||||
|
|
||||||
{
|
{
|
||||||
Array serials;
|
Array nullifiers;
|
||||||
BOOST_FOREACH(const uint256 serial, pourtx.serials) {
|
BOOST_FOREACH(const uint256 nf, jsdescription.nullifiers) {
|
||||||
serials.push_back(serial.GetHex());
|
nullifiers.push_back(nf.GetHex());
|
||||||
}
|
}
|
||||||
pour.push_back(Pair("serials", serials));
|
joinsplit.push_back(Pair("nullifiers", nullifiers));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Array commitments;
|
Array commitments;
|
||||||
BOOST_FOREACH(const uint256 commitment, pourtx.commitments) {
|
BOOST_FOREACH(const uint256 commitment, jsdescription.commitments) {
|
||||||
commitments.push_back(commitment.GetHex());
|
commitments.push_back(commitment.GetHex());
|
||||||
}
|
}
|
||||||
pour.push_back(Pair("commitments", commitments));
|
joinsplit.push_back(Pair("commitments", commitments));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Array macs;
|
Array macs;
|
||||||
BOOST_FOREACH(const uint256 mac, pourtx.macs) {
|
BOOST_FOREACH(const uint256 mac, jsdescription.macs) {
|
||||||
macs.push_back(mac.GetHex());
|
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)));
|
joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old)));
|
||||||
pour.push_back(Pair("vpub_new", ValueFromAmount(pourtx.vpub_new)));
|
joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new)));
|
||||||
|
|
||||||
// TODO: #808
|
// TODO: #808
|
||||||
uint256 pubKeyHash;
|
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()) {
|
if (!hashBlock.IsNull()) {
|
||||||
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
|
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
|
||||||
|
|
|
@ -379,7 +379,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||||
{ "wallet", "walletpassphrase", &walletpassphrase, true },
|
{ "wallet", "walletpassphrase", &walletpassphrase, true },
|
||||||
{ "wallet", "zcbenchmark", &zc_benchmark, true },
|
{ "wallet", "zcbenchmark", &zc_benchmark, true },
|
||||||
{ "wallet", "zcrawkeygen", &zc_raw_keygen, 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 }
|
{ "wallet", "zcrawreceive", &zc_raw_receive, true }
|
||||||
#endif // ENABLE_WALLET
|
#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 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_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_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 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
|
extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
|
||||||
|
|
|
@ -1072,7 +1072,7 @@ public:
|
||||||
// Serialize nLockTime
|
// Serialize nLockTime
|
||||||
::Serialize(s, txTo.nLockTime, nType, nVersion);
|
::Serialize(s, txTo.nLockTime, nType, nVersion);
|
||||||
|
|
||||||
// Serialize vpour
|
// Serialize vjoinsplit
|
||||||
if (txTo.nVersion >= 2) {
|
if (txTo.nVersion >= 2) {
|
||||||
//
|
//
|
||||||
// SIGHASH_* functions will hash portions of
|
// SIGHASH_* functions will hash portions of
|
||||||
|
@ -1080,8 +1080,8 @@ public:
|
||||||
// keeps the JoinSplit cryptographically bound
|
// keeps the JoinSplit cryptographically bound
|
||||||
// to the transaction.
|
// to the transaction.
|
||||||
//
|
//
|
||||||
::Serialize(s, txTo.vpour, nType, nVersion);
|
::Serialize(s, txTo.vjoinsplit, nType, nVersion);
|
||||||
if (txTo.vpour.size() > 0) {
|
if (txTo.vjoinsplit.size() > 0) {
|
||||||
::Serialize(s, txTo.joinSplitPubKey, nType, nVersion);
|
::Serialize(s, txTo.joinSplitPubKey, nType, nVersion);
|
||||||
|
|
||||||
CTransaction::joinsplit_sig_t nullSig = {};
|
CTransaction::joinsplit_sig_t nullSig = {};
|
||||||
|
|
|
@ -24,7 +24,7 @@ class CCoinsViewTest : public CCoinsView
|
||||||
uint256 hashBestAnchor_;
|
uint256 hashBestAnchor_;
|
||||||
std::map<uint256, CCoins> map_;
|
std::map<uint256, CCoins> map_;
|
||||||
std::map<uint256, ZCIncrementalMerkleTree> mapAnchors_;
|
std::map<uint256, ZCIncrementalMerkleTree> mapAnchors_;
|
||||||
std::map<uint256, bool> mapSerials_;
|
std::map<uint256, bool> mapNullifiers_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CCoinsViewTest() {
|
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;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// The map shouldn't contain any false entries.
|
// The map shouldn't contain any false entries.
|
||||||
|
@ -88,7 +88,7 @@ public:
|
||||||
const uint256& hashBlock,
|
const uint256& hashBlock,
|
||||||
const uint256& hashAnchor,
|
const uint256& hashAnchor,
|
||||||
CAnchorsMap& mapAnchors,
|
CAnchorsMap& mapAnchors,
|
||||||
CSerialsMap& mapSerials)
|
CNullifiersMap& mapNullifiers)
|
||||||
{
|
{
|
||||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
|
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
|
||||||
map_[it->first] = it->second.coins;
|
map_[it->first] = it->second.coins;
|
||||||
|
@ -109,17 +109,17 @@ public:
|
||||||
}
|
}
|
||||||
mapAnchors.erase(it++);
|
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) {
|
if (it->second.entered) {
|
||||||
mapSerials_[it->first] = true;
|
mapNullifiers_[it->first] = true;
|
||||||
} else {
|
} else {
|
||||||
mapSerials_.erase(it->first);
|
mapNullifiers_.erase(it->first);
|
||||||
}
|
}
|
||||||
mapSerials.erase(it++);
|
mapNullifiers.erase(it++);
|
||||||
}
|
}
|
||||||
mapCoins.clear();
|
mapCoins.clear();
|
||||||
mapAnchors.clear();
|
mapAnchors.clear();
|
||||||
mapSerials.clear();
|
mapNullifiers.clear();
|
||||||
hashBestBlock_ = hashBlock;
|
hashBestBlock_ = hashBlock;
|
||||||
hashBestAnchor_ = hashAnchor;
|
hashBestAnchor_ = hashAnchor;
|
||||||
return true;
|
return true;
|
||||||
|
@ -138,7 +138,7 @@ public:
|
||||||
// Manually recompute the dynamic usage of the whole data, and compare it.
|
// Manually recompute the dynamic usage of the whole data, and compare it.
|
||||||
size_t ret = memusage::DynamicUsage(cacheCoins) +
|
size_t ret = memusage::DynamicUsage(cacheCoins) +
|
||||||
memusage::DynamicUsage(cacheAnchors) +
|
memusage::DynamicUsage(cacheAnchors) +
|
||||||
memusage::DynamicUsage(cacheSerials);
|
memusage::DynamicUsage(cacheNullifiers);
|
||||||
for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
|
for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
|
||||||
ret += memusage::DynamicUsage(it->second.coins);
|
ret += memusage::DynamicUsage(it->second.coins);
|
||||||
}
|
}
|
||||||
|
@ -163,28 +163,28 @@ uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree)
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(serials_test)
|
BOOST_AUTO_TEST_CASE(nullifiers_test)
|
||||||
{
|
{
|
||||||
CCoinsViewTest base;
|
CCoinsViewTest base;
|
||||||
CCoinsViewCacheTest cache(&base);
|
CCoinsViewCacheTest cache(&base);
|
||||||
|
|
||||||
uint256 myserial = GetRandHash();
|
uint256 nf = GetRandHash();
|
||||||
|
|
||||||
BOOST_CHECK(!cache.GetSerial(myserial));
|
BOOST_CHECK(!cache.GetNullifier(nf));
|
||||||
cache.SetSerial(myserial, true);
|
cache.SetNullifier(nf, true);
|
||||||
BOOST_CHECK(cache.GetSerial(myserial));
|
BOOST_CHECK(cache.GetNullifier(nf));
|
||||||
cache.Flush();
|
cache.Flush();
|
||||||
|
|
||||||
CCoinsViewCacheTest cache2(&base);
|
CCoinsViewCacheTest cache2(&base);
|
||||||
|
|
||||||
BOOST_CHECK(cache2.GetSerial(myserial));
|
BOOST_CHECK(cache2.GetNullifier(nf));
|
||||||
cache2.SetSerial(myserial, false);
|
cache2.SetNullifier(nf, false);
|
||||||
BOOST_CHECK(!cache2.GetSerial(myserial));
|
BOOST_CHECK(!cache2.GetNullifier(nf));
|
||||||
cache2.Flush();
|
cache2.Flush();
|
||||||
|
|
||||||
CCoinsViewCacheTest cache3(&base);
|
CCoinsViewCacheTest cache3(&base);
|
||||||
|
|
||||||
BOOST_CHECK(!cache3.GetSerial(myserial));
|
BOOST_CHECK(!cache3.GetNullifier(nf));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(anchors_flush_test)
|
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;
|
CCoinsViewTest base;
|
||||||
CCoinsViewCacheTest cache(&base);
|
CCoinsViewCacheTest cache(&base);
|
||||||
|
|
||||||
ZCIncrementalMerkleTree tree;
|
ZCIncrementalMerkleTree tree;
|
||||||
|
|
||||||
CPourTx ptx1;
|
JSDescription js1;
|
||||||
ptx1.anchor = tree.root();
|
js1.anchor = tree.root();
|
||||||
ptx1.commitments[0] = appendRandomCommitment(tree);
|
js1.commitments[0] = appendRandomCommitment(tree);
|
||||||
ptx1.commitments[1] = appendRandomCommitment(tree);
|
js1.commitments[1] = appendRandomCommitment(tree);
|
||||||
|
|
||||||
// Although it's not possible given our assumptions, if
|
// 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.
|
// still be able to anchor to it.
|
||||||
CPourTx ptx1b;
|
JSDescription js1b;
|
||||||
ptx1b.anchor = tree.root();
|
js1b.anchor = tree.root();
|
||||||
ptx1b.commitments[0] = ptx1.commitments[0];
|
js1b.commitments[0] = js1.commitments[0];
|
||||||
ptx1b.commitments[1] = ptx1.commitments[1];
|
js1b.commitments[1] = js1.commitments[1];
|
||||||
|
|
||||||
CPourTx ptx2;
|
JSDescription js2;
|
||||||
CPourTx ptx3;
|
JSDescription js3;
|
||||||
|
|
||||||
ptx2.anchor = tree.root();
|
js2.anchor = tree.root();
|
||||||
ptx3.anchor = tree.root();
|
js3.anchor = tree.root();
|
||||||
|
|
||||||
ptx2.commitments[0] = appendRandomCommitment(tree);
|
js2.commitments[0] = appendRandomCommitment(tree);
|
||||||
ptx2.commitments[1] = appendRandomCommitment(tree);
|
js2.commitments[1] = appendRandomCommitment(tree);
|
||||||
|
|
||||||
ptx3.commitments[0] = appendRandomCommitment(tree);
|
js3.commitments[0] = appendRandomCommitment(tree);
|
||||||
ptx3.commitments[1] = appendRandomCommitment(tree);
|
js3.commitments[1] = appendRandomCommitment(tree);
|
||||||
|
|
||||||
{
|
{
|
||||||
CMutableTransaction mtx;
|
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
|
// appears afterwards -- not a permitted ordering
|
||||||
CMutableTransaction mtx;
|
CMutableTransaction mtx;
|
||||||
mtx.vpour.push_back(ptx2);
|
mtx.vjoinsplit.push_back(js2);
|
||||||
mtx.vpour.push_back(ptx1);
|
mtx.vjoinsplit.push_back(js1);
|
||||||
|
|
||||||
BOOST_CHECK(!cache.HavePourRequirements(mtx));
|
BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CMutableTransaction mtx;
|
CMutableTransaction mtx;
|
||||||
mtx.vpour.push_back(ptx1);
|
mtx.vjoinsplit.push_back(js1);
|
||||||
mtx.vpour.push_back(ptx2);
|
mtx.vjoinsplit.push_back(js2);
|
||||||
|
|
||||||
BOOST_CHECK(cache.HavePourRequirements(mtx));
|
BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CMutableTransaction mtx;
|
CMutableTransaction mtx;
|
||||||
mtx.vpour.push_back(ptx1);
|
mtx.vjoinsplit.push_back(js1);
|
||||||
mtx.vpour.push_back(ptx2);
|
mtx.vjoinsplit.push_back(js2);
|
||||||
mtx.vpour.push_back(ptx3);
|
mtx.vjoinsplit.push_back(js3);
|
||||||
|
|
||||||
BOOST_CHECK(cache.HavePourRequirements(mtx));
|
BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CMutableTransaction mtx;
|
CMutableTransaction mtx;
|
||||||
mtx.vpour.push_back(ptx1);
|
mtx.vjoinsplit.push_back(js1);
|
||||||
mtx.vpour.push_back(ptx1b);
|
mtx.vjoinsplit.push_back(js1b);
|
||||||
mtx.vpour.push_back(ptx2);
|
mtx.vjoinsplit.push_back(js2);
|
||||||
mtx.vpour.push_back(ptx3);
|
mtx.vjoinsplit.push_back(js3);
|
||||||
|
|
||||||
BOOST_CHECK(cache.HavePourRequirements(mtx));
|
BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
|
||||||
tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0;
|
tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0;
|
||||||
int ins = (insecure_rand() % 4) + 1;
|
int ins = (insecure_rand() % 4) + 1;
|
||||||
int outs = fSingle ? 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++) {
|
for (int in = 0; in < ins; in++) {
|
||||||
tx.vin.push_back(CTxIn());
|
tx.vin.push_back(CTxIn());
|
||||||
CTxIn &txin = tx.vin.back();
|
CTxIn &txin = tx.vin.back();
|
||||||
|
@ -121,26 +121,26 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
|
||||||
RandomScript(txout.scriptPubKey);
|
RandomScript(txout.scriptPubKey);
|
||||||
}
|
}
|
||||||
if (tx.nVersion >= 2) {
|
if (tx.nVersion >= 2) {
|
||||||
for (int pour = 0; pour < pours; pour++) {
|
for (int js = 0; js < joinsplits; js++) {
|
||||||
CPourTx pourtx;
|
JSDescription jsdesc;
|
||||||
if (insecure_rand() % 2 == 0) {
|
if (insecure_rand() % 2 == 0) {
|
||||||
pourtx.vpub_old = insecure_rand() % 100000000;
|
jsdesc.vpub_old = insecure_rand() % 100000000;
|
||||||
} else {
|
} else {
|
||||||
pourtx.vpub_new = insecure_rand() % 100000000;
|
jsdesc.vpub_new = insecure_rand() % 100000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
pourtx.anchor = GetRandHash();
|
jsdesc.anchor = GetRandHash();
|
||||||
pourtx.serials[0] = GetRandHash();
|
jsdesc.nullifiers[0] = GetRandHash();
|
||||||
pourtx.serials[1] = GetRandHash();
|
jsdesc.nullifiers[1] = GetRandHash();
|
||||||
pourtx.ephemeralKey = GetRandHash();
|
jsdesc.ephemeralKey = GetRandHash();
|
||||||
pourtx.randomSeed = GetRandHash();
|
jsdesc.randomSeed = GetRandHash();
|
||||||
randombytes_buf(pourtx.ciphertexts[0].begin(), pourtx.ciphertexts[0].size());
|
randombytes_buf(jsdesc.ciphertexts[0].begin(), jsdesc.ciphertexts[0].size());
|
||||||
randombytes_buf(pourtx.ciphertexts[1].begin(), pourtx.ciphertexts[1].size());
|
randombytes_buf(jsdesc.ciphertexts[1].begin(), jsdesc.ciphertexts[1].size());
|
||||||
randombytes_buf(pourtx.proof.begin(), pourtx.proof.size());
|
randombytes_buf(jsdesc.proof.begin(), jsdesc.proof.size());
|
||||||
pourtx.macs[0] = GetRandHash();
|
jsdesc.macs[0] = GetRandHash();
|
||||||
pourtx.macs[1] = GetRandHash();
|
jsdesc.macs[1] = GetRandHash();
|
||||||
|
|
||||||
tx.vpour.push_back(pourtx);
|
tx.vjoinsplit.push_back(jsdesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
||||||
|
|
|
@ -291,9 +291,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
||||||
return dummyTransactions;
|
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
|
// and verify properly here. libsnark tends to segfault
|
||||||
// when our snarks or what-have-you are invalid, so
|
// when our snarks or what-have-you are invalid, so
|
||||||
// we can't really catch everything here.
|
// we can't really catch everything here.
|
||||||
|
@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE(test_basic_pour_verification)
|
||||||
|
|
||||||
auto witness = merkleTree.witness();
|
auto witness = merkleTree.witness();
|
||||||
|
|
||||||
// create CPourTx
|
// create JSDescription
|
||||||
uint256 pubKeyHash;
|
uint256 pubKeyHash;
|
||||||
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs = {
|
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs = {
|
||||||
libzcash::JSInput(witness, note, k),
|
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);
|
JSDescription jsdesc(*p, pubKeyHash, rt, inputs, outputs, 0, 0);
|
||||||
BOOST_CHECK(pourtx.Verify(*p, pubKeyHash));
|
BOOST_CHECK(jsdesc.Verify(*p, pubKeyHash));
|
||||||
|
|
||||||
CDataStream ss(SER_DISK, CLIENT_VERSION);
|
CDataStream ss(SER_DISK, CLIENT_VERSION);
|
||||||
ss << pourtx;
|
ss << jsdesc;
|
||||||
|
|
||||||
CPourTx pourtx_deserialized;
|
JSDescription jsdesc_deserialized;
|
||||||
ss >> pourtx_deserialized;
|
ss >> jsdesc_deserialized;
|
||||||
|
|
||||||
BOOST_CHECK(pourtx_deserialized == pourtx);
|
BOOST_CHECK(jsdesc_deserialized == jsdesc);
|
||||||
BOOST_CHECK(pourtx_deserialized.Verify(*p, pubKeyHash));
|
BOOST_CHECK(jsdesc_deserialized.Verify(*p, pubKeyHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Ensure that the balance equation is working.
|
// Ensure that the balance equation is working.
|
||||||
BOOST_CHECK_THROW(CPourTx(*p, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument);
|
BOOST_CHECK_THROW(JSDescription(*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, 0, 10), std::invalid_argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Ensure that it won't verify if the root is changed.
|
// 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();
|
test.anchor = GetRandHash();
|
||||||
BOOST_CHECK(!test.Verify(*p, pubKeyHash));
|
BOOST_CHECK(!test.Verify(*p, pubKeyHash));
|
||||||
}
|
}
|
||||||
|
@ -371,20 +371,20 @@ BOOST_AUTO_TEST_CASE(test_basic_pour_verification)
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
|
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||||
{
|
{
|
||||||
CMutableTransaction tx;
|
CMutableTransaction tx;
|
||||||
tx.nVersion = 2;
|
tx.nVersion = 2;
|
||||||
{
|
{
|
||||||
// Ensure that empty vin/vout remain invalid without
|
// Ensure that empty vin/vout remain invalid without
|
||||||
// pours.
|
// joinsplits.
|
||||||
CMutableTransaction newTx(tx);
|
CMutableTransaction newTx(tx);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
||||||
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
||||||
crypto_sign_keypair(newTx.joinSplitPubKey.begin(), joinSplitPrivKey);
|
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(!CheckTransactionWithoutProofVerification(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vin-empty");
|
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(!CheckTransactionWithoutProofVerification(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vout-empty");
|
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vout-empty");
|
||||||
|
|
||||||
newTx.vpour.push_back(CPourTx());
|
newTx.vjoinsplit.push_back(JSDescription());
|
||||||
CPourTx *pourtx = &newTx.vpour[0];
|
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||||
|
|
||||||
pourtx->serials[0] = GetRandHash();
|
jsdesc->nullifiers[0] = GetRandHash();
|
||||||
pourtx->serials[1] = GetRandHash();
|
jsdesc->nullifiers[1] = GetRandHash();
|
||||||
|
|
||||||
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state));
|
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
|
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));
|
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);
|
CMutableTransaction newTx(tx);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
||||||
newTx.vpour.push_back(CPourTx());
|
newTx.vjoinsplit.push_back(JSDescription());
|
||||||
|
|
||||||
CPourTx *pourtx = &newTx.vpour[0];
|
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||||
pourtx->vpub_old = -1;
|
jsdesc->vpub_old = -1;
|
||||||
|
|
||||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative");
|
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(!CheckTransaction(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge");
|
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge");
|
||||||
|
|
||||||
pourtx->vpub_old = 0;
|
jsdesc->vpub_old = 0;
|
||||||
pourtx->vpub_new = -1;
|
jsdesc->vpub_new = -1;
|
||||||
|
|
||||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative");
|
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(!CheckTransaction(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge");
|
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];
|
JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
|
||||||
pourtx2->vpub_new = (MAX_MONEY / 2) + 10;
|
jsdesc2->vpub_new = (MAX_MONEY / 2) + 10;
|
||||||
|
|
||||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-txouttotal-toolarge");
|
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);
|
CMutableTransaction newTx(tx);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
||||||
newTx.vpour.push_back(CPourTx());
|
newTx.vjoinsplit.push_back(JSDescription());
|
||||||
CPourTx *pourtx = &newTx.vpour[0];
|
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||||
|
|
||||||
pourtx->serials[0] = GetRandHash();
|
jsdesc->nullifiers[0] = GetRandHash();
|
||||||
pourtx->serials[1] = pourtx->serials[0];
|
jsdesc->nullifiers[1] = jsdesc->nullifiers[0];
|
||||||
|
|
||||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
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());
|
newTx.vjoinsplit.push_back(JSDescription());
|
||||||
CPourTx *pourtx2 = &newTx.vpour[1];
|
JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
|
||||||
|
|
||||||
pourtx2->serials[0] = GetRandHash();
|
jsdesc2->nullifiers[0] = GetRandHash();
|
||||||
pourtx2->serials[1] = pourtx->serials[0];
|
jsdesc2->nullifiers[1] = jsdesc->nullifiers[0];
|
||||||
|
|
||||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
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);
|
CMutableTransaction newTx(tx);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
||||||
newTx.vpour.push_back(CPourTx());
|
newTx.vjoinsplit.push_back(JSDescription());
|
||||||
CPourTx *pourtx = &newTx.vpour[0];
|
JSDescription *jsdesc = &newTx.vjoinsplit[0];
|
||||||
pourtx->serials[0] = GetRandHash();
|
jsdesc->nullifiers[0] = GetRandHash();
|
||||||
pourtx->serials[1] = GetRandHash();
|
jsdesc->nullifiers[1] = GetRandHash();
|
||||||
|
|
||||||
newTx.vin.push_back(CTxIn(uint256(), -1));
|
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(finalNewTx.IsCoinBase());
|
||||||
}
|
}
|
||||||
BOOST_CHECK(!CheckTransaction(newTx, state));
|
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-pours");
|
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
src/txdb.cpp
24
src/txdb.cpp
|
@ -18,7 +18,7 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static const char DB_ANCHOR = 'A';
|
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_COINS = 'c';
|
||||||
static const char DB_BLOCK_FILES = 'f';
|
static const char DB_BLOCK_FILES = 'f';
|
||||||
static const char DB_TXINDEX = 't';
|
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)
|
if (!entered)
|
||||||
batch.Erase(make_pair(DB_SERIAL, serial));
|
batch.Erase(make_pair(DB_NULLIFIER, nf));
|
||||||
else
|
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) {
|
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;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCoinsViewDB::GetSerial(const uint256 &serial) const {
|
bool CCoinsViewDB::GetNullifier(const uint256 &nf) const {
|
||||||
bool spent = false;
|
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;
|
return read;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
|
||||||
const uint256 &hashBlock,
|
const uint256 &hashBlock,
|
||||||
const uint256 &hashAnchor,
|
const uint256 &hashAnchor,
|
||||||
CAnchorsMap &mapAnchors,
|
CAnchorsMap &mapAnchors,
|
||||||
CSerialsMap &mapSerials) {
|
CNullifiersMap &mapNullifiers) {
|
||||||
CLevelDBBatch batch;
|
CLevelDBBatch batch;
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
size_t changed = 0;
|
size_t changed = 0;
|
||||||
|
@ -137,13 +137,13 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
|
||||||
mapAnchors.erase(itOld);
|
mapAnchors.erase(itOld);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (CSerialsMap::iterator it = mapSerials.begin(); it != mapSerials.end();) {
|
for (CNullifiersMap::iterator it = mapNullifiers.begin(); it != mapNullifiers.end();) {
|
||||||
if (it->second.flags & CSerialsCacheEntry::DIRTY) {
|
if (it->second.flags & CNullifiersCacheEntry::DIRTY) {
|
||||||
BatchWriteSerial(batch, it->first, it->second.entered);
|
BatchWriteNullifier(batch, it->first, it->second.entered);
|
||||||
// TODO: changed++?
|
// TODO: changed++?
|
||||||
}
|
}
|
||||||
CSerialsMap::iterator itOld = it++;
|
CNullifiersMap::iterator itOld = it++;
|
||||||
mapSerials.erase(itOld);
|
mapNullifiers.erase(itOld);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hashBlock.IsNull())
|
if (!hashBlock.IsNull())
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
||||||
|
|
||||||
bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
|
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 GetCoins(const uint256 &txid, CCoins &coins) const;
|
||||||
bool HaveCoins(const uint256 &txid) const;
|
bool HaveCoins(const uint256 &txid) const;
|
||||||
uint256 GetBestBlock() const;
|
uint256 GetBestBlock() const;
|
||||||
|
@ -44,7 +44,7 @@ public:
|
||||||
const uint256 &hashBlock,
|
const uint256 &hashBlock,
|
||||||
const uint256 &hashAnchor,
|
const uint256 &hashAnchor,
|
||||||
CAnchorsMap &mapAnchors,
|
CAnchorsMap &mapAnchors,
|
||||||
CSerialsMap &mapSerials);
|
CNullifiersMap &mapNullifiers);
|
||||||
bool GetStats(CCoinsStats &stats) const;
|
bool GetStats(CCoinsStats &stats) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -99,9 +99,9 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
||||||
const CTransaction& tx = mapTx[hash].GetTx();
|
const CTransaction& tx = mapTx[hash].GetTx();
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
|
mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
|
||||||
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 &nf, joinsplit.nullifiers) {
|
||||||
mapSerials[serial] = &tx;
|
mapNullifiers[nf] = &tx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nTransactionsUpdated++;
|
nTransactionsUpdated++;
|
||||||
|
@ -148,9 +148,9 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
|
||||||
}
|
}
|
||||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||||
mapNextTx.erase(txin.prevout);
|
mapNextTx.erase(txin.prevout);
|
||||||
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& nf, joinsplit.nullifiers) {
|
||||||
mapSerials.erase(serial);
|
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++) {
|
for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
|
||||||
const CTransaction& tx = it->second.GetTx();
|
const CTransaction& tx = it->second.GetTx();
|
||||||
BOOST_FOREACH(const CPourTx& pour, tx.vpour) {
|
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) {
|
||||||
if (pour.anchor == invalidRoot) {
|
if (joinsplit.anchor == invalidRoot) {
|
||||||
transactionsToRemove.push_back(tx);
|
transactionsToRemove.push_back(tx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -230,10 +230,10 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 &nf, joinsplit.nullifiers) {
|
||||||
std::map<uint256, const CTransaction*>::iterator it = mapSerials.find(serial);
|
std::map<uint256, const CTransaction*>::iterator it = mapNullifiers.find(nf);
|
||||||
if (it != mapSerials.end()) {
|
if (it != mapNullifiers.end()) {
|
||||||
const CTransaction &txConflict = *it->second;
|
const CTransaction &txConflict = *it->second;
|
||||||
if (txConflict != tx)
|
if (txConflict != tx)
|
||||||
{
|
{
|
||||||
|
@ -317,20 +317,20 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
||||||
|
|
||||||
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
|
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 &nf, joinsplit.nullifiers) {
|
||||||
assert(!pcoins->GetSerial(serial));
|
assert(!pcoins->GetNullifier(nf));
|
||||||
}
|
}
|
||||||
|
|
||||||
ZCIncrementalMerkleTree tree;
|
ZCIncrementalMerkleTree tree;
|
||||||
auto it = intermediates.find(pour.anchor);
|
auto it = intermediates.find(joinsplit.anchor);
|
||||||
if (it != intermediates.end()) {
|
if (it != intermediates.end()) {
|
||||||
tree = it->second;
|
tree = it->second;
|
||||||
} else {
|
} 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);
|
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);
|
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();
|
uint256 hash = it->second->GetHash();
|
||||||
map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(hash);
|
map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(hash);
|
||||||
const CTransaction& tx = it2->second.GetTx();
|
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) { }
|
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
|
||||||
|
|
||||||
bool CCoinsViewMemPool::GetSerial(const uint256 &serial) const {
|
bool CCoinsViewMemPool::GetNullifier(const uint256 &nf) const {
|
||||||
if (mempool.mapSerials.count(serial))
|
if (mempool.mapNullifiers.count(nf))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return base->GetSerial(serial);
|
return base->GetNullifier(nf);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
|
bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
|
||||||
|
|
|
@ -98,7 +98,7 @@ public:
|
||||||
mutable CCriticalSection cs;
|
mutable CCriticalSection cs;
|
||||||
std::map<uint256, CTxMemPoolEntry> mapTx;
|
std::map<uint256, CTxMemPoolEntry> mapTx;
|
||||||
std::map<COutPoint, CInPoint> mapNextTx;
|
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;
|
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
||||||
|
|
||||||
CTxMemPool(const CFeeRate& _minRelayFee);
|
CTxMemPool(const CFeeRate& _minRelayFee);
|
||||||
|
@ -177,7 +177,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn);
|
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 GetCoins(const uint256 &txid, CCoins &coins) const;
|
||||||
bool HaveCoins(const uint256 &txid) const;
|
bool HaveCoins(const uint256 &txid) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2393,12 +2393,12 @@ Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
|
||||||
pzcashParams->loadProvingKey();
|
pzcashParams->loadProvingKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
CPourTx* samplejoinsplit = NULL;
|
JSDescription* samplejoinsplit = NULL;
|
||||||
|
|
||||||
if (benchmarktype == "verifyjoinsplit") {
|
if (benchmarktype == "verifyjoinsplit") {
|
||||||
uint256 pubKeyHash;
|
uint256 pubKeyHash;
|
||||||
uint256 anchor = ZCIncrementalMerkleTree().root();
|
uint256 anchor = ZCIncrementalMerkleTree().root();
|
||||||
samplejoinsplit = new CPourTx(*pzcashParams,
|
samplejoinsplit = new JSDescription(*pzcashParams,
|
||||||
pubKeyHash,
|
pubKeyHash,
|
||||||
anchor,
|
anchor,
|
||||||
{JSInput(), JSInput()},
|
{JSInput(), JSInput()},
|
||||||
|
@ -2448,14 +2448,14 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
|
||||||
|
|
||||||
if (fHelp || params.size() != 2) {
|
if (fHelp || params.size() != 2) {
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
"zcrawreceive zcsecretkey encryptedbucket\n"
|
"zcrawreceive zcsecretkey encryptednote\n"
|
||||||
"\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"
|
"are in the blockchain as indicated by the \"exists\" result.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Output: {\n"
|
"Output: {\n"
|
||||||
" \"amount\": value,\n"
|
" \"amount\": value,\n"
|
||||||
" \"bucket\": cleartextbucket,\n"
|
" \"note\": noteplaintext,\n"
|
||||||
" \"exists\": exists\n"
|
" \"exists\": exists\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
);
|
);
|
||||||
|
@ -2474,7 +2474,7 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
|
||||||
uint256 h_sig;
|
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 {
|
try {
|
||||||
ssData >> nonce;
|
ssData >> nonce;
|
||||||
ssData >> epk;
|
ssData >> epk;
|
||||||
|
@ -2482,7 +2482,7 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
|
||||||
ssData >> h_sig;
|
ssData >> h_sig;
|
||||||
} catch(const std::exception &) {
|
} catch(const std::exception &) {
|
||||||
throw runtime_error(
|
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;
|
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
||||||
uint256 anchor;
|
uint256 anchor;
|
||||||
uint256 commitment = decrypted_note.cm();
|
uint256 commitment = decrypted_note.cm();
|
||||||
pwalletMain->WitnessBucketCommitment(
|
pwalletMain->WitnessNoteCommitment(
|
||||||
{commitment},
|
{commitment},
|
||||||
witnesses,
|
witnesses,
|
||||||
anchor
|
anchor
|
||||||
|
@ -2514,14 +2514,14 @@ Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
|
||||||
|
|
||||||
Object result;
|
Object result;
|
||||||
result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
|
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]));
|
result.push_back(Pair("exists", (bool) witnesses[0]));
|
||||||
return result;
|
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)) {
|
if (!EnsureWalletIsAvailable(fHelp)) {
|
||||||
return Value::null;
|
return Value::null;
|
||||||
|
@ -2529,11 +2529,11 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||||
|
|
||||||
if (fHelp || params.size() != 5) {
|
if (fHelp || params.size() != 5) {
|
||||||
throw runtime_error(
|
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"
|
" inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
|
||||||
" outputs: a JSON object mapping {zcaddr: value, ...}\n"
|
" outputs: a JSON object mapping {zcaddr: value, ...}\n"
|
||||||
"\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"
|
"Outputs are confidential between sender/receiver. The vpub_old and\n"
|
||||||
"vpub_new values are globally public and move transparent value into\n"
|
"vpub_new values are globally public and move transparent value into\n"
|
||||||
"or out of the confidential value store, respectively.\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"
|
"payments in-band on the blockchain.)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Output: {\n"
|
"Output: {\n"
|
||||||
" \"encryptedbucket1\": enc1,\n"
|
" \"encryptednote1\": enc1,\n"
|
||||||
" \"encryptedbucket2\": enc2,\n"
|
" \"encryptednote2\": enc2,\n"
|
||||||
" \"rawtxn\": rawtxout\n"
|
" \"rawtxn\": rawtxout\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
);
|
);
|
||||||
|
@ -2569,8 +2569,8 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||||
if (params[4].get_real() != 0.0)
|
if (params[4].get_real() != 0.0)
|
||||||
vpub_new = AmountFromValue(params[4]);
|
vpub_new = AmountFromValue(params[4]);
|
||||||
|
|
||||||
std::vector<JSInput> vpourin;
|
std::vector<JSInput> vjsin;
|
||||||
std::vector<JSOutput> vpourout;
|
std::vector<JSOutput> vjsout;
|
||||||
std::vector<Note> notes;
|
std::vector<Note> notes;
|
||||||
std::vector<SpendingKey> keys;
|
std::vector<SpendingKey> keys;
|
||||||
std::vector<uint256> commitments;
|
std::vector<uint256> commitments;
|
||||||
|
@ -2585,7 +2585,7 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||||
NotePlaintext npt;
|
NotePlaintext npt;
|
||||||
|
|
||||||
{
|
{
|
||||||
CDataStream ssData(ParseHexV(s.name_, "bucket"), SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ssData(ParseHexV(s.name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ssData >> npt;
|
ssData >> npt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2597,7 +2597,7 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||||
|
|
||||||
uint256 anchor;
|
uint256 anchor;
|
||||||
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
|
||||||
pwalletMain->WitnessBucketCommitment(commitments, witnesses, anchor);
|
pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
|
||||||
|
|
||||||
assert(witnesses.size() == notes.size());
|
assert(witnesses.size() == notes.size());
|
||||||
assert(notes.size() == keys.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++) {
|
for (size_t i = 0; i < witnesses.size(); i++) {
|
||||||
if (!witnesses[i]) {
|
if (!witnesses[i]) {
|
||||||
throw runtime_error(
|
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) {
|
while (vjsin.size() < ZC_NUM_JS_INPUTS) {
|
||||||
vpourin.push_back(JSInput());
|
vjsin.push_back(JSInput());
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FOREACH(const Pair& s, outputs)
|
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();
|
PaymentAddress addrTo = pubaddr.Get();
|
||||||
CAmount nAmount = AmountFromValue(s.value_);
|
CAmount nAmount = AmountFromValue(s.value_);
|
||||||
|
|
||||||
vpourout.push_back(JSOutput(addrTo, nAmount));
|
vjsout.push_back(JSOutput(addrTo, nAmount));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (vpourout.size() < ZC_NUM_JS_OUTPUTS) {
|
while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
|
||||||
vpourout.push_back(JSOutput());
|
vjsout.push_back(JSOutput());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
if (vpourout.size() != ZC_NUM_JS_INPUTS || vpourin.size() != ZC_NUM_JS_OUTPUTS) {
|
if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
|
||||||
throw runtime_error("unsupported pour input/output counts");
|
throw runtime_error("unsupported joinsplit input/output counts");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 joinSplitPubKey;
|
uint256 joinSplitPubKey;
|
||||||
|
@ -2644,17 +2644,17 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||||
mtx.nVersion = 2;
|
mtx.nVersion = 2;
|
||||||
mtx.joinSplitPubKey = joinSplitPubKey;
|
mtx.joinSplitPubKey = joinSplitPubKey;
|
||||||
|
|
||||||
CPourTx pourtx(*pzcashParams,
|
JSDescription jsdesc(*pzcashParams,
|
||||||
joinSplitPubKey,
|
joinSplitPubKey,
|
||||||
anchor,
|
anchor,
|
||||||
{vpourin[0], vpourin[1]},
|
{vjsin[0], vjsin[1]},
|
||||||
{vpourout[0], vpourout[1]},
|
{vjsout[0], vjsout[1]},
|
||||||
vpub_old,
|
vpub_old,
|
||||||
vpub_new);
|
vpub_new);
|
||||||
|
|
||||||
assert(pourtx.Verify(*pzcashParams, joinSplitPubKey));
|
assert(jsdesc.Verify(*pzcashParams, joinSplitPubKey));
|
||||||
|
|
||||||
mtx.vpour.push_back(pourtx);
|
mtx.vjoinsplit.push_back(jsdesc);
|
||||||
|
|
||||||
// TODO: #966.
|
// TODO: #966.
|
||||||
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
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);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << rawTx;
|
ss << rawTx;
|
||||||
|
|
||||||
std::string encryptedBucket1;
|
std::string encryptedNote1;
|
||||||
std::string encryptedBucket2;
|
std::string encryptedNote2;
|
||||||
{
|
{
|
||||||
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss2 << ((unsigned char) 0x00);
|
ss2 << ((unsigned char) 0x00);
|
||||||
ss2 << pourtx.ephemeralKey;
|
ss2 << jsdesc.ephemeralKey;
|
||||||
ss2 << pourtx.ciphertexts[0];
|
ss2 << jsdesc.ciphertexts[0];
|
||||||
ss2 << pourtx.h_sig(*pzcashParams, joinSplitPubKey);
|
ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
|
||||||
|
|
||||||
encryptedBucket1 = HexStr(ss2.begin(), ss2.end());
|
encryptedNote1 = HexStr(ss2.begin(), ss2.end());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss2 << ((unsigned char) 0x01);
|
ss2 << ((unsigned char) 0x01);
|
||||||
ss2 << pourtx.ephemeralKey;
|
ss2 << jsdesc.ephemeralKey;
|
||||||
ss2 << pourtx.ciphertexts[1];
|
ss2 << jsdesc.ciphertexts[1];
|
||||||
ss2 << pourtx.h_sig(*pzcashParams, joinSplitPubKey);
|
ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
|
||||||
|
|
||||||
encryptedBucket2 = HexStr(ss2.begin(), ss2.end());
|
encryptedNote2 = HexStr(ss2.begin(), ss2.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
Object result;
|
Object result;
|
||||||
result.push_back(Pair("encryptedbucket1", encryptedBucket1));
|
result.push_back(Pair("encryptednote1", encryptedNote1));
|
||||||
result.push_back(Pair("encryptedbucket2", encryptedBucket2));
|
result.push_back(Pair("encryptednote2", encryptedNote2));
|
||||||
result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
|
result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1051,7 +1051,7 @@ bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
|
||||||
return pwalletdb->WriteTx(GetHash(), *this);
|
return pwalletdb->WriteTx(GetHash(), *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::WitnessBucketCommitment(std::vector<uint256> commitments,
|
void CWallet::WitnessNoteCommitment(std::vector<uint256> commitments,
|
||||||
std::vector<boost::optional<ZCIncrementalWitness>>& witnesses,
|
std::vector<boost::optional<ZCIncrementalWitness>>& witnesses,
|
||||||
uint256 &final_anchor)
|
uint256 &final_anchor)
|
||||||
{
|
{
|
||||||
|
@ -1065,21 +1065,21 @@ void CWallet::WitnessBucketCommitment(std::vector<uint256> commitments,
|
||||||
|
|
||||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
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 ¬e_commitment, jsdesc.commitments)
|
||||||
{
|
{
|
||||||
tree.append(bucket_commitment);
|
tree.append(note_commitment);
|
||||||
|
|
||||||
BOOST_FOREACH(boost::optional<ZCIncrementalWitness>& wit, witnesses) {
|
BOOST_FOREACH(boost::optional<ZCIncrementalWitness>& wit, witnesses) {
|
||||||
if (wit) {
|
if (wit) {
|
||||||
wit->append(bucket_commitment);
|
wit->append(note_commitment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
BOOST_FOREACH(uint256& commitment, commitments) {
|
BOOST_FOREACH(uint256& commitment, commitments) {
|
||||||
if (bucket_commitment == commitment) {
|
if (note_commitment == commitment) {
|
||||||
witnesses.at(i) = tree.witness();
|
witnesses.at(i) = tree.witness();
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
|
|
|
@ -616,7 +616,7 @@ public:
|
||||||
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
|
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
|
||||||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
|
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
|
||||||
void EraseFromWallet(const uint256 &hash);
|
void EraseFromWallet(const uint256 &hash);
|
||||||
void WitnessBucketCommitment(
|
void WitnessNoteCommitment(
|
||||||
std::vector<uint256> commitments,
|
std::vector<uint256> commitments,
|
||||||
std::vector<boost::optional<ZCIncrementalWitness>>& witnesses,
|
std::vector<boost::optional<ZCIncrementalWitness>>& witnesses,
|
||||||
uint256 &final_anchor);
|
uint256 &final_anchor);
|
||||||
|
|
|
@ -76,7 +76,7 @@ double benchmark_create_joinsplit()
|
||||||
uint256 anchor = ZCIncrementalMerkleTree().root();
|
uint256 anchor = ZCIncrementalMerkleTree().root();
|
||||||
|
|
||||||
timer_start();
|
timer_start();
|
||||||
CPourTx pourtx(*pzcashParams,
|
JSDescription jsdesc(*pzcashParams,
|
||||||
pubKeyHash,
|
pubKeyHash,
|
||||||
anchor,
|
anchor,
|
||||||
{JSInput(), JSInput()},
|
{JSInput(), JSInput()},
|
||||||
|
@ -85,11 +85,11 @@ double benchmark_create_joinsplit()
|
||||||
0);
|
0);
|
||||||
double ret = timer_stop();
|
double ret = timer_stop();
|
||||||
|
|
||||||
assert(pourtx.Verify(*pzcashParams, pubKeyHash));
|
assert(jsdesc.Verify(*pzcashParams, pubKeyHash));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
double benchmark_verify_joinsplit(const CPourTx &joinsplit)
|
double benchmark_verify_joinsplit(const JSDescription &joinsplit)
|
||||||
{
|
{
|
||||||
timer_start();
|
timer_start();
|
||||||
uint256 pubKeyHash;
|
uint256 pubKeyHash;
|
||||||
|
|
|
@ -8,7 +8,7 @@ extern double benchmark_sleep();
|
||||||
extern double benchmark_parameter_loading();
|
extern double benchmark_parameter_loading();
|
||||||
extern double benchmark_create_joinsplit();
|
extern double benchmark_create_joinsplit();
|
||||||
extern double benchmark_solve_equihash();
|
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_verify_equihash();
|
||||||
extern double benchmark_large_tx();
|
extern double benchmark_large_tx();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue