Added mapAnchors consensus rules, finished zcrawpour/zcrawreceive.
Some specifics on consensus changes: * Transactions must be anchored to a real anchor in the chain. * Anchors are pushed and popped during ConnectBlock/DisconnectBlock as appropriate. * DisconnectTip triggers evictions, under some circumstances, of transactions in the mempool which are anchored to roots that are no longer valid. * Commitments append to the tree at the current best root during ConnectBlock.
This commit is contained in:
parent
e934af2404
commit
a8ac403db0
|
@ -2,8 +2,8 @@ package=libzerocash
|
|||
$(package)_download_path=https://github.com/Electric-Coin-Company/$(package)/archive/
|
||||
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
|
||||
$(package)_download_file=$($(package)_git_commit).tar.gz
|
||||
$(package)_sha256_hash=8000a2cdc276ab4ee3ad3cbd7361162424ab0c4794f17d425f25bfca46853af8
|
||||
$(package)_git_commit=1503312b1b340495c9f6a3254587c7fe2c3c87d7
|
||||
$(package)_sha256_hash=1364a739751bcdda86cfd66d3d019844d116c374d7a7634bfb3e1a47c085f3c0
|
||||
$(package)_git_commit=dd5db5815be70f0e4895784cc905df6f1c73cb17
|
||||
|
||||
$(package)_dependencies=libsnark crypto++ openssl boost libgmp
|
||||
$(package)_patches=
|
||||
|
|
|
@ -16,6 +16,35 @@ class PourTxTest(BitcoinTestFramework):
|
|||
# Start with split network:
|
||||
return super(PourTxTest, self).setup_network(True)
|
||||
|
||||
def send_pours_around(self):
|
||||
zckeypair = self.nodes[0].zcrawkeygen()
|
||||
zcsecretkey = zckeypair["zcsecretkey"]
|
||||
zcaddress = zckeypair["zcaddress"]
|
||||
|
||||
(total_in, inputs) = gather_inputs(self.nodes[1], 50)
|
||||
protect_tx = self.nodes[1].createrawtransaction(inputs, {})
|
||||
pour_result = self.nodes[1].zcrawpour(protect_tx, {}, {zcaddress:49.9}, 50, 0.1)
|
||||
|
||||
receive_result = self.nodes[1].zcrawreceive(zcsecretkey, pour_result["encryptedbucket1"])
|
||||
assert_equal(receive_result["exists"], False)
|
||||
|
||||
protect_tx = self.nodes[1].signrawtransaction(pour_result["rawtxn"])
|
||||
self.nodes[1].sendrawtransaction(protect_tx["hex"])
|
||||
self.nodes[1].generate(1)
|
||||
|
||||
receive_result = self.nodes[1].zcrawreceive(zcsecretkey, pour_result["encryptedbucket1"])
|
||||
assert_equal(receive_result["exists"], True)
|
||||
|
||||
pour_tx = self.nodes[1].createrawtransaction([], {})
|
||||
pour_result = self.nodes[1].zcrawpour(pour_tx, {receive_result["bucket"] : zcsecretkey}, {zcaddress: 49.8}, 0, 0.1)
|
||||
|
||||
self.nodes[1].sendrawtransaction(pour_result["rawtxn"])
|
||||
self.nodes[1].generate(1)
|
||||
sync_blocks(self.nodes)
|
||||
|
||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, pour_result["encryptedbucket1"])
|
||||
assert_equal(receive_result["exists"], True)
|
||||
|
||||
def run_test(self):
|
||||
# All nodes should start with 1,250 BTC:
|
||||
starting_balance = 1250
|
||||
|
@ -67,5 +96,7 @@ class PourTxTest(BitcoinTestFramework):
|
|||
|
||||
self.nodes[0].sendrawtransaction(signed_tx_pour["hex"])
|
||||
|
||||
self.send_pours_around()
|
||||
|
||||
if __name__ == '__main__':
|
||||
PourTxTest().main()
|
||||
|
|
|
@ -387,6 +387,21 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
|
|||
return nResult;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HavePourRequirements(const CTransaction& tx) const
|
||||
{
|
||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour)
|
||||
{
|
||||
libzerocash::IncrementalMerkleTree tree(INCREMENTAL_MERKLE_TREE_DEPTH);
|
||||
if (!GetAnchorAt(pour.anchor, tree)) {
|
||||
// If we do not have the anchor for the pour,
|
||||
// it is invalid.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
|
||||
{
|
||||
if (!tx.IsCoinBase()) {
|
||||
|
|
|
@ -517,6 +517,9 @@ public:
|
|||
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
|
||||
bool HaveInputs(const CTransaction& tx) const;
|
||||
|
||||
//! Check whether all pour requirements (anchors/serials) are satisfied
|
||||
bool HavePourRequirements(const CTransaction& tx) const;
|
||||
|
||||
//! Return priority of tx at height nHeight
|
||||
double GetPriority(const CTransaction &tx, int nHeight) const;
|
||||
|
||||
|
|
63
src/main.cpp
63
src/main.cpp
|
@ -1057,6 +1057,11 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),
|
||||
REJECT_DUPLICATE, "bad-txns-inputs-spent");
|
||||
|
||||
// are the pour's requirements met?
|
||||
if (!view.HavePourRequirements(tx))
|
||||
return state.Invalid(error("AcceptToMemoryPool: pour requirements not met"),
|
||||
REJECT_DUPLICATE, "bad-txns-pour-requirements-not-met");
|
||||
|
||||
// Bring the best block into scope
|
||||
view.GetBestBlock();
|
||||
|
||||
|
@ -1505,6 +1510,10 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||
if (!inputs.HaveInputs(tx))
|
||||
return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString()));
|
||||
|
||||
// are the pour's requirements met?
|
||||
if (!inputs.HavePourRequirements(tx))
|
||||
return state.Invalid(error("CheckInputs(): %s pour requirements not met", tx.GetHash().ToString()));
|
||||
|
||||
// While checking, GetBestBlock() refers to the parent block.
|
||||
// This is also true for mempool checks.
|
||||
CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
|
||||
|
@ -1766,6 +1775,9 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||
}
|
||||
}
|
||||
|
||||
// set the old best anchor back
|
||||
view.PopAnchor(blockUndo.old_tree_root);
|
||||
|
||||
// move best block pointer to prevout block
|
||||
view.SetBestBlock(pindex->pprev->GetBlockHash());
|
||||
|
||||
|
@ -1953,6 +1965,25 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
|
||||
vPos.reserve(block.vtx.size());
|
||||
blockundo.vtxundo.reserve(block.vtx.size() - 1);
|
||||
|
||||
// Construct the incremental merkle tree at the current
|
||||
// block position,
|
||||
auto old_tree_root = view.GetBestAnchor();
|
||||
libzerocash::IncrementalMerkleTree tree(INCREMENTAL_MERKLE_TREE_DEPTH);
|
||||
// This should never fail: we should always be able to get the root
|
||||
// that is on the tip of our chain
|
||||
assert(view.GetAnchorAt(old_tree_root, tree));
|
||||
|
||||
{
|
||||
// Consistency check: the root of the tree we're given should
|
||||
// match what we asked for.
|
||||
std::vector<unsigned char> newrt_v(32);
|
||||
tree.getRootValue(newrt_v);
|
||||
uint256 anchor_received = uint256(newrt_v);
|
||||
|
||||
assert(anchor_received == old_tree_root);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||
{
|
||||
const CTransaction &tx = block.vtx[i];
|
||||
|
@ -1969,6 +2000,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
|
||||
REJECT_INVALID, "bad-txns-inputs-missingorspent");
|
||||
|
||||
// are the pour's requirements met?
|
||||
if (!view.HavePourRequirements(tx))
|
||||
return state.DoS(100, error("ConnectBlock(): pour requirements not met"),
|
||||
REJECT_INVALID, "bad-txns-pour-requirements-not-met");
|
||||
|
||||
if (fStrictPayToScriptHash)
|
||||
{
|
||||
// Add in sigops done by pay-to-script-hash inputs;
|
||||
|
@ -1994,9 +2030,26 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
}
|
||||
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
|
||||
|
||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
|
||||
BOOST_FOREACH(const uint256 &bucket_commitment, pour.commitments) {
|
||||
// Insert the bucket commitments into our temporary tree.
|
||||
|
||||
std::vector<bool> index;
|
||||
std::vector<unsigned char> commitment_value(bucket_commitment.begin(), bucket_commitment.end());
|
||||
std::vector<bool> commitment_bv(ZC_CM_SIZE * 8);
|
||||
libzerocash::convertBytesVectorToVector(commitment_value, commitment_bv);
|
||||
tree.insertElement(commitment_bv, index);
|
||||
}
|
||||
}
|
||||
|
||||
vPos.push_back(std::make_pair(tx.GetHash(), pos));
|
||||
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
||||
}
|
||||
|
||||
tree.prune(); // prune it, so we don't cache intermediate states we don't need
|
||||
view.PushAnchor(tree);
|
||||
blockundo.old_tree_root = old_tree_root;
|
||||
|
||||
int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart;
|
||||
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001);
|
||||
|
||||
|
@ -2225,6 +2278,7 @@ bool static DisconnectTip(CValidationState &state) {
|
|||
if (!ReadBlockFromDisk(block, pindexDelete))
|
||||
return AbortNode(state, "Failed to read block");
|
||||
// Apply the block atomically to the chain state.
|
||||
uint256 anchorBeforeDisconnect = pcoinsTip->GetBestAnchor();
|
||||
int64_t nStart = GetTimeMicros();
|
||||
{
|
||||
CCoinsViewCache view(pcoinsTip);
|
||||
|
@ -2233,6 +2287,7 @@ bool static DisconnectTip(CValidationState &state) {
|
|||
assert(view.Flush());
|
||||
}
|
||||
LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
|
||||
uint256 anchorAfterDisconnect = pcoinsTip->GetBestAnchor();
|
||||
// Write the chain state to disk, if necessary.
|
||||
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
|
||||
return false;
|
||||
|
@ -2244,6 +2299,11 @@ bool static DisconnectTip(CValidationState &state) {
|
|||
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL))
|
||||
mempool.remove(tx, removed, true);
|
||||
}
|
||||
if (anchorBeforeDisconnect != anchorAfterDisconnect) {
|
||||
// The anchor may not change between block disconnects,
|
||||
// in which case we don't want to evict from the mempool yet!
|
||||
mempool.removeWithAnchor(anchorBeforeDisconnect);
|
||||
}
|
||||
mempool.removeCoinbaseSpends(pcoinsTip, pindexDelete->nHeight);
|
||||
mempool.check(pcoinsTip);
|
||||
// Update chainActive and related variables.
|
||||
|
@ -4536,7 +4596,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
BOOST_FOREACH(uint256 hash, vEraseQueue)
|
||||
EraseOrphanTx(hash);
|
||||
}
|
||||
else if (fMissingInputs)
|
||||
// TODO: currently, prohibit pours from entering mapOrphans
|
||||
else if (fMissingInputs && tx.vpour.size() == 0)
|
||||
{
|
||||
AddOrphanTx(tx, pfrom->GetId());
|
||||
|
||||
|
|
|
@ -378,6 +378,7 @@ static const CRPCCommand vRPCCommands[] =
|
|||
{ "wallet", "walletpassphrase", &walletpassphrase, true },
|
||||
{ "wallet", "zcrawkeygen", &zc_raw_keygen, true },
|
||||
{ "wallet", "zcrawpour", &zc_raw_pour, true },
|
||||
{ "wallet", "zcrawreceive", &zc_raw_receive, true }
|
||||
#endif // ENABLE_WALLET
|
||||
};
|
||||
|
||||
|
|
|
@ -210,6 +210,7 @@ extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHe
|
|||
extern json_spirit::Value resendwallettransactions(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value zc_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_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 listunspent(const json_spirit::Array& params, bool fHelp);
|
||||
|
|
|
@ -178,6 +178,32 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void CTxMemPool::removeWithAnchor(const uint256 &invalidRoot)
|
||||
{
|
||||
// If a block is disconnected from the tip, and the root changed,
|
||||
// we must invalidate transactions from the mempool which spend
|
||||
// from that root -- almost as though they were spending coinbases
|
||||
// which are no longer valid to spend due to coinbase maturity.
|
||||
LOCK(cs);
|
||||
list<CTransaction> transactionsToRemove;
|
||||
|
||||
for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
|
||||
const CTransaction& tx = it->second.GetTx();
|
||||
BOOST_FOREACH(const CPourTx& pour, tx.vpour) {
|
||||
if (pour.anchor == invalidRoot) {
|
||||
transactionsToRemove.push_back(tx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) {
|
||||
list<CTransaction> removed;
|
||||
remove(tx, removed, true);
|
||||
}
|
||||
}
|
||||
|
||||
void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed)
|
||||
{
|
||||
// Remove transactions which depend on inputs of tx, recursively
|
||||
|
|
|
@ -114,6 +114,7 @@ public:
|
|||
|
||||
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
|
||||
void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
|
||||
void removeWithAnchor(const uint256 &invalidRoot);
|
||||
void removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight);
|
||||
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);
|
||||
void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
|
||||
|
|
|
@ -73,12 +73,14 @@ class CBlockUndo
|
|||
{
|
||||
public:
|
||||
std::vector<CTxUndo> vtxundo; // for all but the coinbase
|
||||
uint256 old_tree_root;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(vtxundo);
|
||||
READWRITE(old_tree_root);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2344,13 +2344,68 @@ Value listunspent(const Array& params, bool fHelp)
|
|||
return results;
|
||||
}
|
||||
|
||||
Value zc_raw_receive(const json_spirit::Array& params, bool fHelp)
|
||||
{
|
||||
/*
|
||||
zcrawreceive <zcsecretkey> <encrypted_bucket>
|
||||
*/
|
||||
RPCTypeCheck(params, boost::assign::list_of(str_type)(str_type));
|
||||
LOCK(cs_main);
|
||||
|
||||
std::vector<unsigned char> a_sk;
|
||||
std::string sk_enc;
|
||||
|
||||
{
|
||||
CDataStream ssData(ParseHexV(params[0], "zcsecretkey"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
ssData >> a_sk;
|
||||
ssData >> sk_enc;
|
||||
} catch(const std::exception &) {
|
||||
throw runtime_error(
|
||||
"zcsecretkey could not be decoded"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
libzerocash::PrivateAddress zcsecretkey(a_sk, sk_enc);
|
||||
libzerocash::Address zcaddress(zcsecretkey);
|
||||
|
||||
auto encrypted_bucket_vec = ParseHexV(params[1], "encrypted_bucket");
|
||||
std::string encrypted_bucket(encrypted_bucket_vec.begin(), encrypted_bucket_vec.end());
|
||||
libzerocash::Coin decrypted_bucket(encrypted_bucket, zcaddress);
|
||||
|
||||
std::vector<unsigned char> commitment_v = decrypted_bucket.getCoinCommitment().getCommitmentValue();
|
||||
uint256 commitment = uint256(commitment_v);
|
||||
|
||||
assert(pwalletMain != NULL);
|
||||
libsnark::merkle_authentication_path path(INCREMENTAL_MERKLE_TREE_DEPTH); // We don't care during receive... yet! :)
|
||||
size_t path_index = 0;
|
||||
uint256 anchor;
|
||||
auto found_in_chain = pwalletMain->WitnessBucketCommitment(commitment, path, path_index, anchor);
|
||||
|
||||
CAmount value_of_bucket = decrypted_bucket.getValue();
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
{
|
||||
ss << decrypted_bucket.getValue();
|
||||
ss << decrypted_bucket.getRho();
|
||||
ss << decrypted_bucket.getR();
|
||||
}
|
||||
|
||||
Object result;
|
||||
result.push_back(Pair("amount", ValueFromAmount(value_of_bucket)));
|
||||
result.push_back(Pair("bucket", HexStr(ss.begin(), ss.end())));
|
||||
result.push_back(Pair("exists", found_in_chain));
|
||||
return result;
|
||||
}
|
||||
|
||||
Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||
{
|
||||
/*
|
||||
zcrawpour <rawtx> {<bucket>: <zcsecretkey>, ...} {<zcaddress>: <value>, ...} vpub_old vpub_new
|
||||
*/
|
||||
|
||||
//RPCTypeCheck(params, boost::assign::list_of(str_type)(obj_type)(obj_type)(int_type)(int_type));
|
||||
LOCK(cs_main);
|
||||
|
||||
CTransaction tx;
|
||||
if (!DecodeHexTx(tx, params[0].get_str()))
|
||||
|
@ -2371,24 +2426,61 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
std::vector<PourInput> vpourin;
|
||||
std::vector<PourOutput> vpourout;
|
||||
|
||||
/*
|
||||
uint256 anchor;
|
||||
|
||||
BOOST_FOREACH(const Pair& s, inputs)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
*/
|
||||
CDataStream ssData(ParseHexV(s.name_, "bucket"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
uint64_t value;
|
||||
std::vector<unsigned char> rho;
|
||||
std::vector<unsigned char> r;
|
||||
|
||||
// TODO
|
||||
vpourin.push_back(PourInput(INCREMENTAL_MERKLE_TREE_DEPTH));
|
||||
vpourin.push_back(PourInput(INCREMENTAL_MERKLE_TREE_DEPTH));
|
||||
ssData >> value;
|
||||
ssData >> rho;
|
||||
ssData >> r;
|
||||
|
||||
std::vector<unsigned char> a_sk;
|
||||
std::string sk_enc;
|
||||
|
||||
{
|
||||
CDataStream ssData2(ParseHexV(s.value_, "zcsecretkey"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
try {
|
||||
ssData2 >> a_sk;
|
||||
ssData2 >> sk_enc;
|
||||
} catch(const std::exception &) {
|
||||
throw runtime_error(
|
||||
"zcsecretkey could not be decoded"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
libzerocash::PrivateAddress zcsecretkey(a_sk, sk_enc);
|
||||
libzerocash::Address zcaddress(zcsecretkey);
|
||||
libzerocash::Coin input_coin(zcaddress.getPublicAddress(), value, rho, r);
|
||||
|
||||
std::vector<unsigned char> commitment_v = input_coin.getCoinCommitment().getCommitmentValue();
|
||||
uint256 commitment = uint256(commitment_v);
|
||||
|
||||
libsnark::merkle_authentication_path path(INCREMENTAL_MERKLE_TREE_DEPTH);
|
||||
size_t path_index = 0;
|
||||
assert(pwalletMain != NULL);
|
||||
if (!pwalletMain->WitnessBucketCommitment(commitment, path, path_index, anchor)) {
|
||||
throw std::runtime_error("Couldn't find bucket in the blockchain");
|
||||
}
|
||||
|
||||
vpourin.push_back(PourInput(input_coin, zcaddress, path_index, path));
|
||||
}
|
||||
|
||||
while (vpourin.size() < 2) {
|
||||
vpourin.push_back(PourInput(INCREMENTAL_MERKLE_TREE_DEPTH));
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const Pair& s, outputs)
|
||||
{
|
||||
libzerocash::PublicAddress addrTo;
|
||||
|
||||
{
|
||||
vector<unsigned char> decoded(ParseHex(s.name_));
|
||||
CDataStream ssData(decoded, SER_NETWORK, PROTOCOL_VERSION);
|
||||
CDataStream ssData(ParseHexV(s.name_, "to_address"), SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
std::vector<unsigned char> pubAddressSecret;
|
||||
std::string encryptionPublicKey;
|
||||
|
@ -2415,7 +2507,6 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
throw runtime_error("unsupported");
|
||||
}
|
||||
|
||||
uint256 anchor; // TODO
|
||||
CScript scriptPubKey;
|
||||
CPourTx pourtx(*pzerocashParams,
|
||||
scriptPubKey,
|
||||
|
@ -2425,6 +2516,8 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
|||
vpub_old,
|
||||
vpub_new);
|
||||
|
||||
assert(pourtx.Verify(*pzerocashParams));
|
||||
|
||||
CMutableTransaction mtx(tx);
|
||||
mtx.nVersion = 2;
|
||||
mtx.vpour.push_back(pourtx);
|
||||
|
|
|
@ -1051,6 +1051,68 @@ bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb)
|
|||
return pwalletdb->WriteTx(GetHash(), *this);
|
||||
}
|
||||
|
||||
bool CWallet::WitnessBucketCommitment(uint256 &commitment,
|
||||
libsnark::merkle_authentication_path& path,
|
||||
size_t &path_index,
|
||||
uint256 &final_anchor)
|
||||
{
|
||||
bool res = false;
|
||||
std::vector<bool> commitment_index;
|
||||
|
||||
CBlockIndex* pindex = chainActive.Genesis();
|
||||
libzerocash::IncrementalMerkleTree tree(INCREMENTAL_MERKLE_TREE_DEPTH);
|
||||
uint256 current_anchor;
|
||||
|
||||
while (pindex) {
|
||||
CBlock block;
|
||||
ReadBlockFromDisk(block, pindex);
|
||||
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
{
|
||||
BOOST_FOREACH(const CPourTx& pour, tx.vpour)
|
||||
{
|
||||
BOOST_FOREACH(const uint256 &bucket_commitment, pour.commitments)
|
||||
{
|
||||
std::vector<bool> commitment_bv(ZC_CM_SIZE * 8);
|
||||
std::vector<bool> index;
|
||||
std::vector<unsigned char> commitment_value(bucket_commitment.begin(), bucket_commitment.end());
|
||||
libzerocash::convertBytesVectorToVector(commitment_value, commitment_bv);
|
||||
tree.insertElement(commitment_bv, index);
|
||||
|
||||
if (bucket_commitment == commitment) {
|
||||
// We've found it! Now, we construct a witness.
|
||||
res = true;
|
||||
tree.prune();
|
||||
commitment_index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<unsigned char> newrt_v(32);
|
||||
tree.getRootValue(newrt_v);
|
||||
current_anchor = uint256(newrt_v);
|
||||
}
|
||||
|
||||
// Consistency check: we should be able to find the current tree
|
||||
// in our CCoins view.
|
||||
libzerocash::IncrementalMerkleTree dummy_tree(INCREMENTAL_MERKLE_TREE_DEPTH);
|
||||
assert(pcoinsTip->GetAnchorAt(current_anchor, dummy_tree));
|
||||
|
||||
pindex = chainActive.Next(pindex);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
assert(tree.getWitness(commitment_index, path));
|
||||
}
|
||||
|
||||
path_index = libzerocash::convertVectorToInt(commitment_index);
|
||||
final_anchor = current_anchor;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the block chain (starting in pindexStart) for transactions
|
||||
* from or to us. If fUpdate is true, found transactions that already
|
||||
|
|
|
@ -616,6 +616,7 @@ public:
|
|||
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
|
||||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
|
||||
void EraseFromWallet(const uint256 &hash);
|
||||
bool WitnessBucketCommitment(uint256 &commitment, libsnark::merkle_authentication_path& path, size_t &path_index, uint256 &final_anchor);
|
||||
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
|
||||
void ReacceptWalletTransactions();
|
||||
void ResendWalletTransactions(int64_t nBestBlockTime);
|
||||
|
|
Loading…
Reference in New Issue