Port PR93 from @denioD
This commit is contained in:
@@ -54,6 +54,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
|
|||||||
spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ]
|
spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ]
|
||||||
|
|
||||||
blocks.extend(self.nodes[0].generate(1))
|
blocks.extend(self.nodes[0].generate(1))
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
# mempool should be empty, all txns confirmed
|
# mempool should be empty, all txns confirmed
|
||||||
assert_equal(set(self.nodes[0].getrawmempool()), set())
|
assert_equal(set(self.nodes[0].getrawmempool()), set())
|
||||||
@@ -74,6 +75,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Generate another block, they should all get mined
|
# Generate another block, they should all get mined
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
# mempool should be empty, all txns confirmed
|
# mempool should be empty, all txns confirmed
|
||||||
assert_equal(set(self.nodes[0].getrawmempool()), set())
|
assert_equal(set(self.nodes[0].getrawmempool()), set())
|
||||||
for txid in spends1_id+spends2_id:
|
for txid in spends1_id+spends2_id:
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ def sync_blocks(rpc_connections, wait=1):
|
|||||||
break
|
break
|
||||||
time.sleep(wait)
|
time.sleep(wait)
|
||||||
|
|
||||||
|
# Now that the block counts are in sync, wait for the internal
|
||||||
|
# notifications to finish
|
||||||
|
while True:
|
||||||
|
notified = [ x.getblockchaininfo()['fullyNotified'] for x in rpc_connections ]
|
||||||
|
if notified == [ True ] * len(notified):
|
||||||
|
break
|
||||||
|
time.sleep(wait)
|
||||||
|
|
||||||
def sync_mempools(rpc_connections, wait=1):
|
def sync_mempools(rpc_connections, wait=1):
|
||||||
"""
|
"""
|
||||||
Wait until everybody has the same transactions in their memory
|
Wait until everybody has the same transactions in their memory
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class WalletTest (BitcoinTestFramework):
|
|||||||
print "Mining blocks..."
|
print "Mining blocks..."
|
||||||
|
|
||||||
self.nodes[0].generate(4)
|
self.nodes[0].generate(4)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
walletinfo = self.nodes[0].getwalletinfo()
|
walletinfo = self.nodes[0].getwalletinfo()
|
||||||
assert_equal(walletinfo['immature_balance'], 40)
|
assert_equal(walletinfo['immature_balance'], 40)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class Wallet1941RegressionTest (BitcoinTestFramework):
|
|||||||
|
|
||||||
self.nodes[0].setmocktime(starttime)
|
self.nodes[0].setmocktime(starttime)
|
||||||
self.nodes[0].generate(101)
|
self.nodes[0].generate(101)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
mytaddr = self.nodes[0].getnewaddress() # where coins were mined
|
mytaddr = self.nodes[0].getnewaddress() # where coins were mined
|
||||||
myzaddr = self.nodes[0].z_getnewaddress()
|
myzaddr = self.nodes[0].z_getnewaddress()
|
||||||
@@ -63,6 +64,7 @@ class Wallet1941RegressionTest (BitcoinTestFramework):
|
|||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
self.nodes[0].setmocktime(starttime + 9000)
|
self.nodes[0].setmocktime(starttime + 9000)
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
# Confirm the balance on node 0.
|
# Confirm the balance on node 0.
|
||||||
resp = self.nodes[0].z_getbalance(myzaddr)
|
resp = self.nodes[0].z_getbalance(myzaddr)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class WalletAnchorForkTest (BitcoinTestFramework):
|
|||||||
def run_test (self):
|
def run_test (self):
|
||||||
print "Mining blocks..."
|
print "Mining blocks..."
|
||||||
self.nodes[0].generate(4)
|
self.nodes[0].generate(4)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
walletinfo = self.nodes[0].getwalletinfo()
|
walletinfo = self.nodes[0].getwalletinfo()
|
||||||
assert_equal(walletinfo['immature_balance'], 40)
|
assert_equal(walletinfo['immature_balance'], 40)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework):
|
|||||||
print "Mining blocks..."
|
print "Mining blocks..."
|
||||||
|
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
self.sync_all()
|
||||||
do_not_shield_taddr = self.nodes[0].getnewaddress()
|
do_not_shield_taddr = self.nodes[0].getnewaddress()
|
||||||
|
|
||||||
self.nodes[0].generate(4)
|
self.nodes[0].generate(4)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class JoinSplitTest(BitcoinTestFramework):
|
|||||||
protect_tx = self.nodes[0].signrawtransaction(joinsplit_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)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
|
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
|
||||||
assert_equal(receive_result["exists"], True)
|
assert_equal(receive_result["exists"], True)
|
||||||
@@ -39,6 +40,7 @@ class JoinSplitTest(BitcoinTestFramework):
|
|||||||
addrtest = self.nodes[0].getnewaddress()
|
addrtest = self.nodes[0].getnewaddress()
|
||||||
for xx in range(0,10):
|
for xx in range(0,10):
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
self.sync_all()
|
||||||
for x in range(0,50):
|
for x in range(0,50):
|
||||||
self.nodes[0].sendtoaddress(addrtest, 0.01);
|
self.nodes[0].sendtoaddress(addrtest, 0.01);
|
||||||
|
|
||||||
@@ -47,6 +49,7 @@ class JoinSplitTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
self.nodes[0].sendrawtransaction(joinsplit_result["rawtxn"])
|
self.nodes[0].sendrawtransaction(joinsplit_result["rawtxn"])
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
|
self.sync_all()
|
||||||
|
|
||||||
print "Done!"
|
print "Done!"
|
||||||
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
|
receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"])
|
||||||
|
|||||||
@@ -37,15 +37,6 @@ class ZMQTest(BitcoinTestFramework):
|
|||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|
||||||
print "listen..."
|
print "listen..."
|
||||||
msg = self.zmqSubSocket.recv_multipart()
|
|
||||||
topic = msg[0]
|
|
||||||
assert_equal(topic, b"hashtx")
|
|
||||||
body = msg[1]
|
|
||||||
nseq = msg[2]
|
|
||||||
[nseq] # hush pyflakes
|
|
||||||
msgSequence = struct.unpack('<I', msg[-1])[-1]
|
|
||||||
assert_equal(msgSequence, 0) # must be sequence 0 on hashtx
|
|
||||||
|
|
||||||
msg = self.zmqSubSocket.recv_multipart()
|
msg = self.zmqSubSocket.recv_multipart()
|
||||||
topic = msg[0]
|
topic = msg[0]
|
||||||
body = msg[1]
|
body = msg[1]
|
||||||
@@ -55,6 +46,15 @@ class ZMQTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
assert_equal(genhashes[0], blkhash) #blockhash from generate must be equal to the hash received over zmq
|
assert_equal(genhashes[0], blkhash) #blockhash from generate must be equal to the hash received over zmq
|
||||||
|
|
||||||
|
msg = self.zmqSubSocket.recv_multipart()
|
||||||
|
topic = msg[0]
|
||||||
|
assert_equal(topic, b"hashtx")
|
||||||
|
body = msg[1]
|
||||||
|
nseq = msg[2]
|
||||||
|
[nseq] # hush pyflakes
|
||||||
|
msgSequence = struct.unpack('<I', msg[-1])[-1]
|
||||||
|
assert_equal(msgSequence, 0) # must be sequence 0 on hashtx
|
||||||
|
|
||||||
n = 10
|
n = 10
|
||||||
genhashes = self.nodes[1].generate(n)
|
genhashes = self.nodes[1].generate(n)
|
||||||
self.sync_all()
|
self.sync_all()
|
||||||
|
|||||||
31
src/init.cpp
31
src/init.cpp
@@ -736,22 +736,6 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadNotifyRecentlyAdded()
|
|
||||||
{
|
|
||||||
while (true) {
|
|
||||||
// Run the notifier on an integer second in the steady clock.
|
|
||||||
auto now = std::chrono::steady_clock::now().time_since_epoch();
|
|
||||||
auto nextFire = std::chrono::duration_cast<std::chrono::seconds>(
|
|
||||||
now + std::chrono::seconds(1));
|
|
||||||
std::this_thread::sleep_until(
|
|
||||||
std::chrono::time_point<std::chrono::steady_clock>(nextFire));
|
|
||||||
|
|
||||||
boost::this_thread::interruption_point();
|
|
||||||
|
|
||||||
mempool.NotifyRecentlyAdded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sanity checks
|
/** Sanity checks
|
||||||
* Ensure that Hush is running in a usable environment with all
|
* Ensure that Hush is running in a usable environment with all
|
||||||
* necessary library support.
|
* necessary library support.
|
||||||
@@ -2088,6 +2072,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
}
|
}
|
||||||
#endif // ENABLE_MINING
|
#endif // ENABLE_MINING
|
||||||
|
|
||||||
|
// Start the thread that notifies listeners of transactions that have been
|
||||||
|
// recently added to the mempool, or have been added to or removed from the
|
||||||
|
// chain. We perform this before step 10 (import blocks) so that the
|
||||||
|
// original value of chainActive.Tip(), which corresponds with the wallet's
|
||||||
|
// view of the chaintip, is passed to ThreadNotifyWallets before the chain
|
||||||
|
// tip changes again.
|
||||||
|
boost::function<void()> threadnotifywallets = boost::bind(&ThreadNotifyWallets, chainActive.Tip());
|
||||||
|
threadGroup.create_thread(
|
||||||
|
boost::bind(&TraceThread<boost::function<void()>>, "txnotify", threadnotifywallets)
|
||||||
|
);
|
||||||
|
|
||||||
// ********************************************************* Step 9: data directory maintenance
|
// ********************************************************* Step 9: data directory maintenance
|
||||||
|
|
||||||
// if pruning, unset the service bit and perform the initial blockstore prune
|
// if pruning, unset the service bit and perform the initial blockstore prune
|
||||||
@@ -2155,10 +2150,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
|
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Start the thread that notifies listeners of transactions that have been
|
|
||||||
// recently added to the mempool.
|
|
||||||
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "txnotify", &ThreadNotifyRecentlyAdded));
|
|
||||||
|
|
||||||
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
|
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
|
||||||
StartTorControl(threadGroup, scheduler);
|
StartTorControl(threadGroup, scheduler);
|
||||||
|
|
||||||
|
|||||||
83
src/main.cpp
83
src/main.cpp
@@ -4068,21 +4068,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
|
|||||||
// Update chainActive and related variables.
|
// Update chainActive and related variables.
|
||||||
UpdateTip(pindexDelete->pprev);
|
UpdateTip(pindexDelete->pprev);
|
||||||
|
|
||||||
// Get the current commitment tree
|
// Updates to connected wallets are triggered by ThreadNotifyWallets
|
||||||
SproutMerkleTree newSproutTree;
|
|
||||||
SaplingMerkleTree newSaplingTree;
|
|
||||||
assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), newSproutTree));
|
|
||||||
assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), newSaplingTree));
|
|
||||||
// Let wallets know transactions went from 1-confirmed to
|
|
||||||
// 0-confirmed or conflicted:
|
|
||||||
std::vector<uint256> TxToRemove;
|
|
||||||
for (int i = 0; i < block.vtx.size(); i++)
|
|
||||||
{
|
|
||||||
CTransaction &tx = block.vtx[i];
|
|
||||||
SyncWithWallets(tx, NULL);
|
|
||||||
}
|
|
||||||
// Update cached incremental witnesses
|
|
||||||
GetMainSignals().ChainTip(pindexDelete, &block, newSproutTree, newSaplingTree, false);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4156,6 +4143,11 @@ static int64_t nTimeFlush = 0;
|
|||||||
static int64_t nTimeChainState = 0;
|
static int64_t nTimeChainState = 0;
|
||||||
static int64_t nTimePostConnect = 0;
|
static int64_t nTimePostConnect = 0;
|
||||||
|
|
||||||
|
// Protected by cs_main
|
||||||
|
std::map<CBlockIndex*, std::list<CTransaction>> recentlyConflictedTxs;
|
||||||
|
uint64_t nRecentlyConflictedSequence = 0;
|
||||||
|
uint64_t nNotifiedSequence = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
|
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
|
||||||
* corresponding to pindexNew, to bypass loading it again from disk.
|
* corresponding to pindexNew, to bypass loading it again from disk.
|
||||||
@@ -4175,14 +4167,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
|
|||||||
}
|
}
|
||||||
KOMODO_CONNECTING = (int32_t)pindexNew->GetHeight();
|
KOMODO_CONNECTING = (int32_t)pindexNew->GetHeight();
|
||||||
//fprintf(stderr,"%s connecting ht.%d maxsize.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pindexNew->GetHeight(),MAX_BLOCK_SIZE(pindexNew->GetHeight()),(int32_t)::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
|
//fprintf(stderr,"%s connecting ht.%d maxsize.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pindexNew->GetHeight(),MAX_BLOCK_SIZE(pindexNew->GetHeight()),(int32_t)::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
|
||||||
// Get the current commitment tree
|
|
||||||
SproutMerkleTree oldSproutTree;
|
|
||||||
SaplingMerkleTree oldSaplingTree;
|
|
||||||
if ( KOMODO_NSPV_FULLNODE )
|
|
||||||
{
|
|
||||||
assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), oldSproutTree));
|
|
||||||
assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), oldSaplingTree));
|
|
||||||
}
|
|
||||||
// Apply the block atomically to the chain state.
|
// Apply the block atomically to the chain state.
|
||||||
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
|
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
|
||||||
int64_t nTime3;
|
int64_t nTime3;
|
||||||
@@ -4221,7 +4206,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
|
|||||||
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
|
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
|
||||||
LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
|
LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
|
||||||
// Remove conflicting transactions from the mempool.
|
// Remove conflicting transactions from the mempool.
|
||||||
list<CTransaction> txConflicted;
|
std::list<CTransaction> txConflicted;
|
||||||
mempool.removeForBlock(pblock->vtx, pindexNew->GetHeight(), txConflicted, !IsInitialBlockDownload());
|
mempool.removeForBlock(pblock->vtx, pindexNew->GetHeight(), txConflicted, !IsInitialBlockDownload());
|
||||||
|
|
||||||
// Remove transactions that expire at new block height from mempool
|
// Remove transactions that expire at new block height from mempool
|
||||||
@@ -4231,18 +4216,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
|
|||||||
UpdateTip(pindexNew);
|
UpdateTip(pindexNew);
|
||||||
if ( KOMODO_NSPV_FULLNODE )
|
if ( KOMODO_NSPV_FULLNODE )
|
||||||
{
|
{
|
||||||
// Tell wallet about transactions that went from mempool
|
|
||||||
// to conflicted:
|
// Cache the conflicted transactions for subsequent notification.
|
||||||
BOOST_FOREACH(const CTransaction &tx, txConflicted) {
|
// Updates to connected wallets are triggered by ThreadNotifyWallets
|
||||||
SyncWithWallets(tx, NULL);
|
recentlyConflictedTxs.insert(std::make_pair(pindexNew, txConflicted));
|
||||||
}
|
nRecentlyConflictedSequence += 1;
|
||||||
// ... and about transactions that got confirmed:
|
|
||||||
BOOST_FOREACH(const CTransaction &tx, pblock->vtx) {
|
|
||||||
SyncWithWallets(tx, pblock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update cached incremental witnesses
|
|
||||||
GetMainSignals().ChainTip(pindexNew, pblock, oldSproutTree, oldSaplingTree, true);
|
|
||||||
|
|
||||||
EnforceNodeDeprecation(pindexNew->GetHeight());
|
EnforceNodeDeprecation(pindexNew->GetHeight());
|
||||||
|
|
||||||
@@ -4278,6 +4256,31 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
|
|||||||
//fprintf(stderr,"%s: returning true\n", __FUNCTION__);
|
//fprintf(stderr,"%s: returning true\n", __FUNCTION__);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
std::pair<std::map<CBlockIndex*, std::list<CTransaction>>, uint64_t> DrainRecentlyConflicted()
|
||||||
|
{
|
||||||
|
uint64_t recentlyConflictedSequence;
|
||||||
|
std::map<CBlockIndex*, std::list<CTransaction>> txs;
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
recentlyConflictedSequence = nRecentlyConflictedSequence;
|
||||||
|
txs.swap(recentlyConflictedTxs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(txs, recentlyConflictedSequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetChainNotifiedSequence(uint64_t recentlyConflictedSequence) {
|
||||||
|
assert(Params().NetworkIDString() == "regtest");
|
||||||
|
LOCK(cs_main);
|
||||||
|
nNotifiedSequence = recentlyConflictedSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChainIsFullyNotified() {
|
||||||
|
assert(Params().NetworkIDString() == "regtest");
|
||||||
|
LOCK(cs_main);
|
||||||
|
return nRecentlyConflictedSequence == nNotifiedSequence;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the tip of the chain with the most work in it, that isn't
|
* Return the tip of the chain with the most work in it, that isn't
|
||||||
@@ -5316,10 +5319,10 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
|
|||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptx)
|
// if (ptx)
|
||||||
{
|
// {
|
||||||
SyncWithWallets(*ptx, &block);
|
// SyncWithWallets(*ptx, &block);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if ( ASSETCHAINS_CC != 0 )
|
if ( ASSETCHAINS_CC != 0 )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -949,4 +949,8 @@ uint64_t CalculateCurrentUsage();
|
|||||||
/** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */
|
/** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */
|
||||||
CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight);
|
CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight);
|
||||||
|
|
||||||
|
std::pair<std::map<CBlockIndex*, std::list<CTransaction>>, uint64_t> DrainRecentlyConflicted();
|
||||||
|
void SetChainNotifiedSequence(uint64_t recentlyConflictedSequence);
|
||||||
|
bool ChainIsFullyNotified();
|
||||||
|
|
||||||
#endif // BITCOIN_MAIN_H
|
#endif // BITCOIN_MAIN_H
|
||||||
|
|||||||
@@ -844,7 +844,7 @@ bool CTxMemPool::nullifierExists(const uint256& nullifier, ShieldedType type) co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTxMemPool::NotifyRecentlyAdded()
|
std::pair<std::vector<CTransaction>, uint64_t> CTxMemPool::DrainRecentlyAdded()
|
||||||
{
|
{
|
||||||
uint64_t recentlyAddedSequence;
|
uint64_t recentlyAddedSequence;
|
||||||
std::vector<CTransaction> txs;
|
std::vector<CTransaction> txs;
|
||||||
@@ -857,29 +857,13 @@ void CTxMemPool::NotifyRecentlyAdded()
|
|||||||
mapRecentlyAddedTx.clear();
|
mapRecentlyAddedTx.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// A race condition can occur here between these SyncWithWallets calls, and
|
return std::make_pair(txs, recentlyAddedSequence);
|
||||||
// the ones triggered by block logic (in ConnectTip and DisconnectTip). It
|
}
|
||||||
// is harmless because calling SyncWithWallets(_, NULL) does not alter the
|
|
||||||
// wallet transaction's block information.
|
|
||||||
for (auto tx : txs) {
|
|
||||||
try {
|
|
||||||
SyncWithWallets(tx, NULL);
|
|
||||||
} catch (const boost::thread_interrupted&) {
|
|
||||||
fprintf(stderr,"%s: thread interrupted\n", __FUNCTION__);
|
|
||||||
throw;
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
PrintExceptionContinue(&e, "CTxMemPool::NotifyRecentlyAdded()");
|
|
||||||
} catch (...) {
|
|
||||||
PrintExceptionContinue(NULL, "CTxMemPool::NotifyRecentlyAdded()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the notified sequence number. We only need this in regtest mode,
|
void CTxMemPool::SetNotifiedSequence(uint64_t recentlyAddedSequence) {
|
||||||
// and should not lock on cs after calling SyncWithWallets otherwise.
|
assert(Params().NetworkIDString() == "regtest");
|
||||||
if (Params().NetworkIDString() == "regtest") {
|
LOCK(cs);
|
||||||
LOCK(cs);
|
nNotifiedSequence = recentlyAddedSequence;
|
||||||
nNotifiedSequence = recentlyAddedSequence;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CTxMemPool::IsFullyNotified() {
|
bool CTxMemPool::IsFullyNotified() {
|
||||||
|
|||||||
@@ -240,7 +240,8 @@ public:
|
|||||||
|
|
||||||
bool nullifierExists(const uint256& nullifier, ShieldedType type) const;
|
bool nullifierExists(const uint256& nullifier, ShieldedType type) const;
|
||||||
|
|
||||||
void NotifyRecentlyAdded();
|
std::pair<std::vector<CTransaction>, uint64_t> DrainRecentlyAdded();
|
||||||
|
void SetNotifiedSequence(uint64_t recentlyAddedSequence);
|
||||||
bool IsFullyNotified();
|
bool IsFullyNotified();
|
||||||
|
|
||||||
unsigned long size()
|
unsigned long size()
|
||||||
|
|||||||
@@ -5,6 +5,17 @@
|
|||||||
|
|
||||||
#include "validationinterface.h"
|
#include "validationinterface.h"
|
||||||
|
|
||||||
|
#include "chainparams.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "txmempool.h"
|
||||||
|
#include "ui_interface.h"
|
||||||
|
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
static CMainSignals g_signals;
|
static CMainSignals g_signals;
|
||||||
|
|
||||||
CMainSignals& GetMainSignals()
|
CMainSignals& GetMainSignals()
|
||||||
@@ -18,7 +29,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
|||||||
g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
|
g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
|
||||||
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
||||||
g_signals.RescanWallet.connect(boost::bind(&CValidationInterface::RescanWallet, pwalletIn));
|
g_signals.RescanWallet.connect(boost::bind(&CValidationInterface::RescanWallet, pwalletIn));
|
||||||
g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5));
|
g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3));
|
||||||
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||||
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
||||||
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
|
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
|
||||||
@@ -29,7 +40,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
|||||||
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||||
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
|
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
|
||||||
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
||||||
g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5));
|
g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3));
|
||||||
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||||
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
||||||
g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
|
g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
|
||||||
@@ -55,10 +66,76 @@ void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) {
|
|||||||
g_signals.SyncTransaction(tx, pblock);
|
g_signals.SyncTransaction(tx, pblock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CachedBlockData {
|
||||||
|
CBlockIndex *pindex;
|
||||||
|
std::pair<SproutMerkleTree, SaplingMerkleTree> oldTrees;
|
||||||
|
std::list<CTransaction> txConflicted;
|
||||||
|
|
||||||
|
CachedBlockData(
|
||||||
|
CBlockIndex *pindex,
|
||||||
|
std::pair<SproutMerkleTree, SaplingMerkleTree> oldTrees,
|
||||||
|
std::list<CTransaction> txConflicted):
|
||||||
|
pindex(pindex), oldTrees(oldTrees), txConflicted(txConflicted) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
void ThreadNotifyWallets(CBlockIndex *pindexLastTip)
|
||||||
|
{
|
||||||
|
// If pindexLastTip == nullptr, the wallet is at genesis.
|
||||||
|
// However, the genesis block is not loaded synchronously.
|
||||||
|
// We need to wait for ThreadImport to finish.
|
||||||
|
while (pindexLastTip == nullptr) {
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
pindexLastTip = chainActive.Genesis();
|
||||||
|
}
|
||||||
|
MilliSleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Run the notifier on an integer second in the steady clock.
|
||||||
|
auto now = std::chrono::steady_clock::now().time_since_epoch();
|
||||||
|
auto nextFire = std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
|
now + std::chrono::seconds(1));
|
||||||
|
std::this_thread::sleep_until(
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock>(nextFire));
|
||||||
|
|
||||||
|
boost::this_thread::interruption_point();
|
||||||
|
|
||||||
|
auto chainParams = Params();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Collect all the state we require
|
||||||
|
//
|
||||||
|
|
||||||
|
// The common ancestor between the last chain tip we notified and the
|
||||||
|
// current chain tip.
|
||||||
|
const CBlockIndex *pindexFork;
|
||||||
|
// The stack of blocks we will notify as having been connected.
|
||||||
|
// Pushed in reverse, popped in order.
|
||||||
|
std::vector<CachedBlockData> blockStack;
|
||||||
|
// Transactions that have been recently conflicted out of the mempool.
|
||||||
|
std::pair<std::map<CBlockIndex*, std::list<CTransaction>>, uint64_t> recentlyConflicted;
|
||||||
|
// Transactions that have been recently added to the mempool.
|
||||||
|
std::pair<std::vector<CTransaction>, uint64_t> recentlyAdded;
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
|
||||||
|
// Figure out the path from the last block we notified to the
|
||||||
|
// current chain tip.
|
||||||
|
CBlockIndex *pindex = chainActive.Tip();
|
||||||
|
pindexFork = chainActive.FindFork(pindexLastTip);
|
||||||
|
|
||||||
|
// Fetch recently-conflicted transactions. These will include any
|
||||||
|
// block that has been connected since the last cycle, but we only
|
||||||
|
// notify for the conflicts created by the current active chain.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
void EraseFromWallets(const uint256 &hash) {
|
void EraseFromWallets(const uint256 &hash) {
|
||||||
g_signals.EraseTransaction(hash);
|
g_signals.EraseTransaction(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RescanWallets() {
|
void RescanWallets() {
|
||||||
g_signals.RescanWallet();
|
g_signals.RescanWallet();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn);
|
|||||||
void UnregisterValidationInterface(CValidationInterface* pwalletIn);
|
void UnregisterValidationInterface(CValidationInterface* pwalletIn);
|
||||||
/** Unregister all wallets from core */
|
/** Unregister all wallets from core */
|
||||||
void UnregisterAllValidationInterfaces();
|
void UnregisterAllValidationInterfaces();
|
||||||
/** Push an updated transaction to all registered wallets */
|
|
||||||
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL);
|
|
||||||
/** Erase a transaction from all registered wallets */
|
/** Erase a transaction from all registered wallets */
|
||||||
void EraseFromWallets(const uint256 &hash);
|
void EraseFromWallets(const uint256 &hash);
|
||||||
/** Rescan all registered wallets */
|
/** Rescan all registered wallets */
|
||||||
@@ -39,7 +37,7 @@ protected:
|
|||||||
virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {}
|
virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {}
|
||||||
virtual void EraseFromWallet(const uint256 &hash) {}
|
virtual void EraseFromWallet(const uint256 &hash) {}
|
||||||
virtual void RescanWallet() {}
|
virtual void RescanWallet() {}
|
||||||
virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added) {}
|
virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>> added) {}
|
||||||
virtual void SetBestChain(const CBlockLocator &locator) {}
|
virtual void SetBestChain(const CBlockLocator &locator) {}
|
||||||
virtual void UpdatedTransaction(const uint256 &hash) {}
|
virtual void UpdatedTransaction(const uint256 &hash) {}
|
||||||
virtual void Inventory(const uint256 &hash) {}
|
virtual void Inventory(const uint256 &hash) {}
|
||||||
@@ -62,7 +60,7 @@ struct CMainSignals {
|
|||||||
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
|
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
|
||||||
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
|
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
|
||||||
/** Notifies listeners of a change to the tip of the active block chain. */
|
/** Notifies listeners of a change to the tip of the active block chain. */
|
||||||
boost::signals2::signal<void (const CBlockIndex *, const CBlock *, SproutMerkleTree, SaplingMerkleTree, bool)> ChainTip;
|
boost::signals2::signal<void (const CBlockIndex *, const CBlock *, boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>>)> ChainTip;
|
||||||
/** Notifies listeners of a new active block chain. */
|
/** Notifies listeners of a new active block chain. */
|
||||||
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
|
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
|
||||||
/** Notifies listeners about an inventory item being seen on the network. */
|
/** Notifies listeners about an inventory item being seen on the network. */
|
||||||
@@ -75,4 +73,6 @@ struct CMainSignals {
|
|||||||
|
|
||||||
CMainSignals& GetMainSignals();
|
CMainSignals& GetMainSignals();
|
||||||
|
|
||||||
|
void ThreadNotifyWallets(CBlockIndex *pindexLastTip);
|
||||||
|
|
||||||
#endif // BITCOIN_VALIDATIONINTERFACE_H
|
#endif // BITCOIN_VALIDATIONINTERFACE_H
|
||||||
|
|||||||
@@ -588,9 +588,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
|
|||||||
|
|
||||||
void CWallet::ChainTip(const CBlockIndex *pindex,
|
void CWallet::ChainTip(const CBlockIndex *pindex,
|
||||||
const CBlock *pblock,
|
const CBlock *pblock,
|
||||||
SproutMerkleTree sproutTree,
|
boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>> added)
|
||||||
SaplingMerkleTree saplingTree,
|
|
||||||
bool added)
|
|
||||||
{
|
{
|
||||||
if (added) {
|
if (added) {
|
||||||
// Prevent witness cache building && consolidation transactions
|
// Prevent witness cache building && consolidation transactions
|
||||||
|
|||||||
@@ -1253,7 +1253,10 @@ public:
|
|||||||
CAmount GetCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const;
|
CAmount GetCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const;
|
||||||
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
||||||
CAmount GetChange(const CTransaction& tx) const;
|
CAmount GetChange(const CTransaction& tx) const;
|
||||||
void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added);
|
void ChainTip(
|
||||||
|
const CBlockIndex *pindex,
|
||||||
|
const CBlock *pblock,
|
||||||
|
boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>> added);
|
||||||
void RunSaplingConsolidation(int blockHeight);
|
void RunSaplingConsolidation(int blockHeight);
|
||||||
void CommitConsolidationTx(const CTransaction& tx);
|
void CommitConsolidationTx(const CTransaction& tx);
|
||||||
/** Saves witness caches and best block locator to disk. */
|
/** Saves witness caches and best block locator to disk. */
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ double benchmark_increment_note_witnesses(size_t nTxs)
|
|||||||
index1.SetHeight(1);
|
index1.SetHeight(1);
|
||||||
|
|
||||||
// Increment to get transactions witnessed
|
// Increment to get transactions witnessed
|
||||||
wallet.ChainTip(&index1, &block1, sproutTree, saplingTree, true);
|
wallet.ChainTip(&index1, &block1, std::make_pair(sproutTree, saplingTree));
|
||||||
|
|
||||||
// Second block
|
// Second block
|
||||||
CBlock block2;
|
CBlock block2;
|
||||||
@@ -333,7 +333,7 @@ double benchmark_increment_note_witnesses(size_t nTxs)
|
|||||||
|
|
||||||
struct timeval tv_start;
|
struct timeval tv_start;
|
||||||
timer_start(tv_start);
|
timer_start(tv_start);
|
||||||
wallet.ChainTip(&index2, &block2, sproutTree, saplingTree, true);
|
wallet.ChainTip(&index2, &block2, std::make_pair(sproutTree, saplingTree));
|
||||||
return timer_stop(tv_start);
|
return timer_stop(tv_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user