Skip to content

Commit 446bb70

Browse files
committed
Merge pull request bitcoin#5940
0f5954c Regression test for ResendWalletTransactions (Gavin Andresen)
2 parents d62fed1 + 0f5954c commit 446bb70

File tree

10 files changed

+88
-32
lines changed

10 files changed

+88
-32
lines changed

qa/rpc-tests/wallet.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# h) node0 should now have 2 unspent outputs; send these to node2 via raw tx broadcast by node1
1717
# i) have node1 mine a block
1818
# j) check balances - node0 should have 0, node2 should have 100
19+
# k) test ResendWalletTransactions - create transactions, startup fourth node, make sure it syncs
1920
#
2021

2122
from test_framework import BitcoinTestFramework
@@ -26,7 +27,7 @@ class WalletTest (BitcoinTestFramework):
2627

2728
def setup_chain(self):
2829
print("Initializing test directory "+self.options.tmpdir)
29-
initialize_chain_clean(self.options.tmpdir, 3)
30+
initialize_chain_clean(self.options.tmpdir, 4)
3031

3132
def setup_network(self, split=False):
3233
self.nodes = start_nodes(3, self.options.tmpdir)
@@ -132,5 +133,23 @@ def run_test (self):
132133
assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000'))
133134
assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000'))
134135

136+
# Test ResendWalletTransactions:
137+
# Create a couple of transactions, then start up a fourth
138+
# node (nodes[3]) and ask nodes[0] to rebroadcast.
139+
# EXPECT: nodes[3] should have those transactions in its mempool.
140+
txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
141+
txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
142+
sync_mempools(self.nodes)
143+
144+
self.nodes.append(start_node(3, self.options.tmpdir))
145+
connect_nodes_bi(self.nodes, 0, 3)
146+
sync_blocks(self.nodes)
147+
148+
relayed = self.nodes[0].resendwallettransactions()
149+
assert_equal(set(relayed), set([txid1, txid2]))
150+
sync_mempools(self.nodes)
151+
152+
assert(txid1 in self.nodes[3].getrawmempool())
153+
135154
if __name__ == '__main__':
136155
WalletTest ().main ()

src/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4475,7 +4475,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
44754475
// transactions become unconfirmed and spams other nodes.
44764476
if (!fReindex && !fImporting && !IsInitialBlockDownload())
44774477
{
4478-
GetMainSignals().Broadcast();
4478+
GetMainSignals().Broadcast(nTimeBestReceived);
44794479
}
44804480

44814481
//

src/main.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ extern BlockMap mapBlockIndex;
115115
extern uint64_t nLastBlockTx;
116116
extern uint64_t nLastBlockSize;
117117
extern const std::string strMessageMagic;
118-
extern int64_t nTimeBestReceived;
119118
extern CWaitableCriticalSection csBestBlock;
120119
extern CConditionVariable cvBlockChange;
121120
extern bool fImporting;

src/rpcserver.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ static const CRPCCommand vRPCCommands[] =
333333
{ "hidden", "invalidateblock", &invalidateblock, true, false },
334334
{ "hidden", "reconsiderblock", &reconsiderblock, true, false },
335335
{ "hidden", "setmocktime", &setmocktime, true, false },
336+
#ifdef ENABLE_WALLET
337+
{ "hidden", "resendwallettransactions", &resendwallettransactions, true, true },
338+
#endif
336339

337340
#ifdef ENABLE_WALLET
338341
/* Wallet */

src/rpcserver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ extern json_spirit::Value getwalletinfo(const json_spirit::Array& params, bool f
207207
extern json_spirit::Value getblockchaininfo(const json_spirit::Array& params, bool fHelp);
208208
extern json_spirit::Value getnetworkinfo(const json_spirit::Array& params, bool fHelp);
209209
extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHelp);
210+
extern json_spirit::Value resendwallettransactions(const json_spirit::Array& params, bool fHelp);
210211

211212
extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
212213
extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp);

src/validationinterface.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
1818
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
1919
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
2020
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
21-
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn));
21+
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
2222
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
2323
}
2424

2525
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
2626
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
27-
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn));
27+
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
2828
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
2929
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
3030
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));

src/validationinterface.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class CValidationInterface {
3333
virtual void SetBestChain(const CBlockLocator &locator) {};
3434
virtual void UpdatedTransaction(const uint256 &hash) {};
3535
virtual void Inventory(const uint256 &hash) {};
36-
virtual void ResendWalletTransactions() {};
36+
virtual void ResendWalletTransactions(int64_t nBestBlockTime) {};
3737
virtual void BlockChecked(const CBlock&, const CValidationState&) {};
3838
friend void ::RegisterValidationInterface(CValidationInterface*);
3939
friend void ::UnregisterValidationInterface(CValidationInterface*);
@@ -52,7 +52,7 @@ struct CMainSignals {
5252
/** Notifies listeners about an inventory item being seen on the network. */
5353
boost::signals2::signal<void (const uint256 &)> Inventory;
5454
/** Tells listeners to broadcast their data. */
55-
boost::signals2::signal<void ()> Broadcast;
55+
boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast;
5656
/** Notifies listeners of a block validation result */
5757
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
5858
};

src/wallet/rpcwallet.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,3 +2096,25 @@ Value getwalletinfo(const Array& params, bool fHelp)
20962096
obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
20972097
return obj;
20982098
}
2099+
2100+
Value resendwallettransactions(const Array& params, bool fHelp)
2101+
{
2102+
if (fHelp || params.size() != 0)
2103+
throw runtime_error(
2104+
"resendwallettransactions\n"
2105+
"Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2106+
"Intended only for testing; the wallet code periodically re-broadcasts\n"
2107+
"automatically.\n"
2108+
"Returns array of transaction ids that were re-broadcast.\n"
2109+
);
2110+
2111+
LOCK2(cs_main, pwalletMain->cs_wallet);
2112+
2113+
std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2114+
Array result;
2115+
BOOST_FOREACH(const uint256& txid, txids)
2116+
{
2117+
result.push_back(txid.ToString());
2118+
}
2119+
return result;
2120+
}

src/wallet/wallet.cpp

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,15 +1114,17 @@ void CWallet::ReacceptWalletTransactions()
11141114
}
11151115
}
11161116

1117-
void CWalletTx::RelayWalletTransaction()
1117+
bool CWalletTx::RelayWalletTransaction()
11181118
{
11191119
if (!IsCoinBase())
11201120
{
11211121
if (GetDepthInMainChain() == 0) {
11221122
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
11231123
RelayTransaction((CTransaction)*this);
1124+
return true;
11241125
}
11251126
}
1127+
return false;
11261128
}
11271129

11281130
set<uint256> CWalletTx::GetConflicts() const
@@ -1324,7 +1326,31 @@ bool CWalletTx::IsTrusted() const
13241326
return true;
13251327
}
13261328

1327-
void CWallet::ResendWalletTransactions()
1329+
std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
1330+
{
1331+
std::vector<uint256> result;
1332+
1333+
LOCK(cs_wallet);
1334+
// Sort them in chronological order
1335+
multimap<unsigned int, CWalletTx*> mapSorted;
1336+
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
1337+
{
1338+
CWalletTx& wtx = item.second;
1339+
// Don't rebroadcast if newer than nTime:
1340+
if (wtx.nTimeReceived > nTime)
1341+
continue;
1342+
mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
1343+
}
1344+
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
1345+
{
1346+
CWalletTx& wtx = *item.second;
1347+
if (wtx.RelayWalletTransaction())
1348+
result.push_back(wtx.GetHash());
1349+
}
1350+
return result;
1351+
}
1352+
1353+
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
13281354
{
13291355
// Do this infrequently and randomly to avoid giving away
13301356
// that these are our transactions.
@@ -1336,30 +1362,15 @@ void CWallet::ResendWalletTransactions()
13361362
return;
13371363

13381364
// Only do it if there's been a new block since last time
1339-
if (nTimeBestReceived < nLastResend)
1365+
if (nBestBlockTime < nLastResend)
13401366
return;
13411367
nLastResend = GetTime();
13421368

1343-
// Rebroadcast any of our txes that aren't in a block yet
1344-
LogPrintf("ResendWalletTransactions()\n");
1345-
{
1346-
LOCK(cs_wallet);
1347-
// Sort them in chronological order
1348-
multimap<unsigned int, CWalletTx*> mapSorted;
1349-
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
1350-
{
1351-
CWalletTx& wtx = item.second;
1352-
// Don't rebroadcast until it's had plenty of time that
1353-
// it should have gotten in already by now.
1354-
if (nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60)
1355-
mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
1356-
}
1357-
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
1358-
{
1359-
CWalletTx& wtx = *item.second;
1360-
wtx.RelayWalletTransaction();
1361-
}
1362-
}
1369+
// Rebroadcast unconfirmed txes older than 5 minutes before the last
1370+
// block was found:
1371+
std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60);
1372+
if (!relayed.empty())
1373+
LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
13631374
}
13641375

13651376
/** @} */ // end of mapWallet

src/wallet/wallet.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ class CWalletTx : public CMerkleTx
381381
int64_t GetTxTime() const;
382382
int GetRequestCount() const;
383383

384-
void RelayWalletTransaction();
384+
bool RelayWalletTransaction();
385385

386386
std::set<uint256> GetConflicts() const;
387387
};
@@ -614,7 +614,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
614614
void EraseFromWallet(const uint256 &hash);
615615
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
616616
void ReacceptWalletTransactions();
617-
void ResendWalletTransactions();
617+
void ResendWalletTransactions(int64_t nBestBlockTime);
618+
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime);
618619
CAmount GetBalance() const;
619620
CAmount GetUnconfirmedBalance() const;
620621
CAmount GetImmatureBalance() const;

0 commit comments

Comments
 (0)