upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-08-23 11:41:28 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-08-23 11:41:28 +0000
commit9d6fcb2058d90e3ecfb011e2168e4eee04e3a90a (patch)
tree334e7c0297c858c07f1f42037ac96752a4aede0e
parentd273a04ff89233f0f01431bd6e3c18d5261818b0 (diff)
payout: ask the wallet why a send failed instead of guessing from the balance
A payment that the pool could not fund was being recorded as a fault against the payment, and 1440 faults erased the debt with the coin still in the operator's wallet. The classifier read GetBalance() after the failure and asked whether it covered `amount + nTransactionFee + CENT`. Every term of that was wrong. nTransactionFee is 0 on this pool -- it is only ever assigned from the GUI preferences dialog, which a headless node does not have -- so the entire reserve was one CENT. The fee it is meant to reserve for is GetMinFee(fDiscount=true), which is a step function of the serialised size: 0 below 10,000 bytes and (1 + bytes/1000) * CENT at or above it. There is no required-fee value between 1 and 11 CENT, so a one-CENT reserve is never the right number -- below the step nothing needs reserving, at the step it is short by a factor of eleven. Worse, the trigger correlates with the failure. A pool wallet close to broke selects many small inputs BECAUSE it is close to broke, and about 56 signed P2PKH inputs is 10 KB, which a pool that has been paying out accumulates as change. So: balance of amount + 0.05, the pre-send gate passes, CreateTransaction builds a transaction over 10 KB, the fee becomes 0.11, SelectCoins(amount + 0.11) fails, SendMoney returns false -- and (amount + 0.05) < (amount + 0 + 0.01) is false, so "funded", so a fault. The condition is stable, so it recurred every 60 s until the budget ran out and ForfeitPayoutRecipient erased the miner's money. Three changes. The wallet now says what it did. CreateTransaction takes an optional WalletSendResult out-parameter and sets WALLET_SEND_INSUFFICIENT_FUNDS on the one return that means a funding shortfall -- SelectCoins failing to cover nValue plus whatever fee that pass is working with, which on the second and later passes is GetMinFee() of the transaction the first pass actually built. SendMoney gains a four-argument overload returning that plus the fee that was required. The three-argument SendMoney stays, as a separate declaration rather than a default argument, because gui.cpp declares it itself instead of including main.h; walletcmd.cpp and the GUI are unchanged. These are wallet functions, not consensus. ClassifyPayoutSendFailure() then classifies the answer rather than guessing: locked or short of coin defers, anything else is a fault. There is no reserve left to get wrong, and the size-dependent fee is accounted for exactly, because the wallet computed it. And the give-up branch is gone. 1440 failures is not a decidable state, it is a count of how long we have been asking, and this pool reached it by misclassifying a permanent funding shortfall. A payment that keeps failing now stays in flight, keeps its ledger entry, keeps being reported as owed in pool_status.json, and keeps retrying once a minute. A debt that is never written off cannot be written off wrongly. The remaining call to ForfeitPayoutRecipient is the one decidable case -- the ledger names a string that is not a valid address, so no transaction can pay it -- which previously only dropped the in-flight record and left the ledger and the round proof claiming the debt forever. Tested against a real wallet and the real CreateTransaction, not against injected values, because the honest question is whether a wallet holding many small coins reports the state this code assumes. 60 coins of 1 BTF, balance 60.00, amount 59.95: CreateTransaction returns false with WALLET_SEND_INSUFFICIENT_FUNDS and a required fee of 0.11 -- and since GetMinFee returns 0 below 10,000 bytes, a required fee of 11 CENT is itself the measurement that the transaction crossed the step. The same test asserts that the old reserve judged that state "funded", and that the same wallet pays a 3-input transaction with a required fee of 0.00, which is why no fixed reserve is right for both. Property: a send that failed because the wallet could not fund it is deferred, whatever the transaction's size, and no number of failures erases a debt.
-rw-r--r--src/main.cpp47
-rw-r--r--src/main.h45
-rw-r--r--src/rpc.cpp441
3 files changed, 454 insertions, 79 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 252911b..7b3e555 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4907,9 +4907,17 @@ bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
4907 4907
4908 4908
4909 4909
4910bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, int64& nFeeRequiredRet) 4910// presultRet, when given, says WHY this returned false: the caller cannot work
4911// it out afterwards. "Coin selection came up short" and "the wallet could not
4912// build the transaction" are indistinguishable from the outside -- both are
4913// just `false` -- and the difference decides whether a pool defers a payment
4914// or counts it against the payment's retry budget. See WalletSendResult.
4915bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, int64& nFeeRequiredRet,
4916 WalletSendResult* presultRet)
4911{ 4917{
4912 nFeeRequiredRet = 0; 4918 nFeeRequiredRet = 0;
4919 if (presultRet)
4920 *presultRet = WALLET_SEND_FAILED;
4913 CRITICAL_BLOCK(cs_main) 4921 CRITICAL_BLOCK(cs_main)
4914 { 4922 {
4915 // txdb must be opened before the mapWallet lock 4923 // txdb must be opened before the mapWallet lock
@@ -4940,10 +4948,21 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, in
4940 // fixed this in 107d9e288. 4948 // fixed this in 107d9e288.
4941 int64 nTotalValue = nValue + nFee; 4949 int64 nTotalValue = nValue + nFee;
4942 4950
4943 // Choose coins to use 4951 // Choose coins to use.
4952 //
4953 // Failing here is a funding shortfall and nothing else: there
4954 // is not enough spendable coin for nValue plus the fee this
4955 // pass is working with. On the second and later passes that
4956 // fee is GetMinFee() of the transaction the first pass built,
4957 // so this is also how a wallet that can afford the amount but
4958 // not the 11 * CENT charged at 10,000 bytes reports itself.
4944 set<CWalletTx*> setCoins; 4959 set<CWalletTx*> setCoins;
4945 if (!SelectCoins(nTotalValue, setCoins)) 4960 if (!SelectCoins(nTotalValue, setCoins))
4961 {
4962 if (presultRet)
4963 *presultRet = WALLET_SEND_INSUFFICIENT_FUNDS;
4946 return false; 4964 return false;
4965 }
4947 int64 nValueIn = 0; 4966 int64 nValueIn = 0;
4948 foreach(CWalletTx* pcoin, setCoins) 4967 foreach(CWalletTx* pcoin, setCoins)
4949 nValueIn += pcoin->GetCredit(); 4968 nValueIn += pcoin->GetCredit();
@@ -5013,6 +5032,8 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, in
5013 } 5032 }
5014 } 5033 }
5015 } 5034 }
5035 if (presultRet)
5036 *presultRet = WALLET_SEND_OK;
5016 return true; 5037 return true;
5017} 5038}
5018 5039
@@ -5075,13 +5096,24 @@ bool CommitTransactionSpent(const CWalletTx& wtxNew)
5075 5096
5076 5097
5077 5098
5078bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew) 5099// outcomeRet reports what happened rather than only whether it worked. A
5100// caller that has to decide what a failure MEANS -- the pool payout thread --
5101// cannot reconstruct it from a balance reading afterwards, because the fee
5102// that was actually required depends on the size of a transaction that was
5103// never built. See WalletSendResult.
5104bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
5105 SendMoneyOutcome& outcomeRet)
5079{ 5106{
5107 outcomeRet.result = WALLET_SEND_FAILED;
5108 outcomeRet.nFeeRequired = 0;
5080 CRITICAL_BLOCK(cs_main) 5109 CRITICAL_BLOCK(cs_main)
5081 { 5110 {
5082 int64 nFeeRequired; 5111 int64 nFeeRequired;
5083 if (!CreateTransaction(scriptPubKey, nValue, wtxNew, nFeeRequired)) 5112 WalletSendResult createResult = WALLET_SEND_FAILED;
5113 if (!CreateTransaction(scriptPubKey, nValue, wtxNew, nFeeRequired, &createResult))
5084 { 5114 {
5115 outcomeRet.result = createResult;
5116 outcomeRet.nFeeRequired = nFeeRequired;
5085 string strError; 5117 string strError;
5086 if (nValue + nFeeRequired > GetBalance()) 5118 if (nValue + nFeeRequired > GetBalance())
5087 // Not an oversized transaction -- this branch is simply "the 5119 // Not an oversized transaction -- this branch is simply "the
@@ -5119,6 +5151,13 @@ bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
5119 } 5151 }
5120 wtxNew.RelayWalletTransaction(); 5152 wtxNew.RelayWalletTransaction();
5121 } 5153 }
5154 outcomeRet.result = WALLET_SEND_OK;
5122 MainFrameRepaint(); 5155 MainFrameRepaint();
5123 return true; 5156 return true;
5124} 5157}
5158
5159bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
5160{
5161 SendMoneyOutcome ignored;
5162 return SendMoney(scriptPubKey, nValue, wtxNew, ignored);
5163}
diff --git a/src/main.h b/src/main.h
index 8bb536b..382dd9c 100644
--- a/src/main.h
+++ b/src/main.h
@@ -342,9 +342,52 @@ struct WalletRecoveryAudit
342 } 342 }
343}; 343};
344WalletRecoveryAudit GetWalletRecoveryAudit(); 344WalletRecoveryAudit GetWalletRecoveryAudit();
345bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& txNew, int64& nFeeRequiredRet); 345
346// Why a send did not go through.
347//
348// The pool's payout thread has to decide, on every failed SendMoney, whether
349// the failure was the wallet's condition (wait for it to change) or a fault
350// (something is wrong with this payment). It used to guess by re-reading
351// GetBalance() afterwards and allowing a fixed CENT of headroom for the fee.
352// That cannot work: the fee here is a step function of the SERIALISED SIZE of
353// a transaction that no longer exists, and the step is from 0 to 11 * CENT at
354// 10,000 bytes -- so a one-CENT allowance is either unnecessary or an order of
355// magnitude short, never right. A pool wallet close to broke selects many
356// small inputs BECAUSE it is close to broke, which is what pushes the
357// transaction over 10 KB, so the guess is wrong exactly when the money is
358// tight.
359//
360// The wallet already knows the answer; it just did not say. SelectCoins()
361// failing is "there is not enough spendable coin to cover the amount plus
362// whatever fee this size of transaction requires", and it is the only reason
363// CreateTransaction() can fail that is about funding rather than about the
364// wallet being broken.
365enum WalletSendResult
366{
367 WALLET_SEND_OK = 0,
368 WALLET_SEND_INSUFFICIENT_FUNDS, // coin selection could not cover amount+fee
369 WALLET_SEND_FAILED // anything else: could not build, sign or accept
370};
371
372// What the wallet did with a send request. nFeeRequired is the fee the
373// transaction turned out to need, which for a failed send is what coin
374// selection was asked for on top of the amount and could not find -- 0 if it
375// never got that far.
376struct SendMoneyOutcome
377{
378 WalletSendResult result = WALLET_SEND_OK;
379 int64 nFeeRequired = 0;
380};
381
382bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& txNew, int64& nFeeRequiredRet,
383 WalletSendResult* presultRet=NULL);
346bool CommitTransactionSpent(const CWalletTx& wtxNew); 384bool CommitTransactionSpent(const CWalletTx& wtxNew);
385// The three-argument form is kept, and kept as a distinct declaration rather
386// than a defaulted argument, because gui.cpp declares SendMoney itself instead
387// of including this header.
347bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew); 388bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew);
389bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
390 SendMoneyOutcome& outcomeRet);
348 391
349 392
350 393
diff --git a/src/rpc.cpp b/src/rpc.cpp
index 403cb14..06de7f2 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -1700,8 +1700,11 @@ static void ForgetPayment(const PayingRecord& r)
1700 1700
1701 // When the last record for a round is gone the round is no longer in 1701 // When the last record for a round is gone the round is no longer in
1702 // flight, so a later flush may explode it again if the ledger still 1702 // flight, so a later flush may explode it again if the ledger still
1703 // shows recipients owed (a give-up, for instance, leaves the entry 1703 // shows recipients owed. That is the intended behaviour and it is now
1704 // standing). 1704 // the only way a stalled payment ever leaves this list: a payment that
1705 // keeps failing is retried forever rather than given up on, so its
1706 // record stays here, and the flush that would re-explode it is stopped
1707 // by PaymentInFlightLocked.
1705 bool stillInFlight = false; 1708 bool stillInFlight = false;
1706 for (const auto& e : gPaying) 1709 for (const auto& e : gPaying)
1707 if (SamePayoutRound(e.blockHeight, e.blockHash, 1710 if (SamePayoutRound(e.blockHeight, e.blockHash,
@@ -1776,9 +1779,16 @@ static void RecordPayoutTxid(const PayingRecord& r, const std::string& txid)
1776 LogPrint("payout", "[payout] block %d fully settled\n", r.blockHeight); 1779 LogPrint("payout", "[payout] block %d fully settled\n", r.blockHeight);
1777} 1780}
1778 1781
1779// Write a recipient off. Only reached after a full budget of failures that 1782// Write a recipient off.
1780// were NOT the wallet being locked or short of coin -- see the classification 1783//
1781// in PayoutThreadFn -- against a block still on the main chain. 1784// Only ever called for a state that is DECIDABLE -- currently one: the ledger
1785// names an address that is not a valid address, so no transaction paying it
1786// can be constructed by this or any other build. It is not called, and must
1787// not be, because a payment has failed some number of times. "The wallet said
1788// no N times" is not a decidable state, it is a description of how long we
1789// have been asking; a debt written off on the strength of it is a debt the
1790// operator keeps, and the arithmetic that decided WHY the wallet said no was
1791// wrong for a year (see PayoutThreadFn).
1782// 1792//
1783// The amount is removed from the entry rather than marked paid, so the money 1793// The amount is removed from the entry rather than marked paid, so the money
1784// is not reported as sent. Once nothing is left owed the entry retires. The 1794// is not reported as sent. Once nothing is left owed the entry retires. The
@@ -1810,6 +1820,60 @@ static void ForfeitPayoutRecipient(const PayingRecord& r, const std::string& rea
1810 r.address, reason); 1820 r.address, reason);
1811} 1821}
1812 1822
1823// What a failed send means for the payment's retry budget.
1824//
1825// A deferral is "the wallet's condition is temporarily wrong": wait, and do
1826// not hold it against this payment. A fault is "the wallet is funded and
1827// unlocked and still would not do it", which is worth logging loudly and
1828// retrying with backoff.
1829//
1830// This used to be decided by re-reading GetBalance() after the failure and
1831// comparing it against `amount + nTransactionFee + CENT`. Every term of that
1832// was wrong:
1833//
1834// * nTransactionFee is 0 in production. It is only ever assigned from the
1835// GUI preferences dialog (gui.cpp), which a headless pool node does not
1836// have, so the whole reserve was the CENT.
1837//
1838// * The fee the reserve is for is GetMinFee(fDiscount=true), a STEP
1839// function of the serialised size: 0 below 10,000 bytes, and
1840// (1 + bytes/1000) * CENT at or above it -- so 11 * CENT at the step.
1841// There is no required-fee value between 1 and 11 CENT. A one-CENT
1842// reserve is therefore never the right number: below the step nothing
1843// needs reserving, and at the step it is short by a factor of eleven.
1844//
1845// * A pool wallet close to broke selects many small inputs BECAUSE it is
1846// close to broke, and ~56 signed P2PKH inputs is 10 KB. The trigger and
1847// the failure are positively correlated: the guess is wrong precisely
1848// when the pool is nearly out of money.
1849//
1850// Concretely, with a balance of amount + 0.05: the pre-send gate passes,
1851// CreateTransaction builds a >10 KB transaction, the fee becomes 0.11,
1852// SelectCoins(amount + 0.11) fails, SendMoney returns false -- and the old
1853// arithmetic said (amount + 0.05) < (amount + 0.01) is false, so "funded",
1854// so a fault. The condition is stable, so it recurred every 60 s, and 1440 of
1855// them erased the debt with the coin still in the operator's wallet.
1856//
1857// So stop guessing. The wallet is asked to say what it did, and this only
1858// classifies the answer. WALLET_SEND_INSUFFICIENT_FUNDS is coin selection
1859// failing to cover amount plus whatever fee that size of transaction
1860// required, whatever that turned out to be -- no reserve to get wrong.
1861enum PayoutFailureClass {
1862 PAYOUT_FAILURE_DEFER = 0, // conditions are wrong; wait for them to change
1863 PAYOUT_FAILURE_FAULT // funded and unlocked, and it still would not go
1864};
1865
1866static PayoutFailureClass ClassifyPayoutSendFailure(WalletSendResult result,
1867 bool fWalletLocked)
1868{
1869 // A locked wallet cannot sign. Nothing about this payment is wrong.
1870 if (fWalletLocked)
1871 return PAYOUT_FAILURE_DEFER;
1872 if (result == WALLET_SEND_INSUFFICIENT_FUNDS)
1873 return PAYOUT_FAILURE_DEFER;
1874 return PAYOUT_FAILURE_FAULT;
1875}
1876
1813// Payout execution thread: works through gPaying, calls SendMoney. 1877// Payout execution thread: works through gPaying, calls SendMoney.
1814// Runs independently of the event loop so slow wallet operations 1878// Runs independently of the event loop so slow wallet operations
1815// (SendMoney takes cs_main) never stall miner I/O. 1879// (SendMoney takes cs_main) never stall miner I/O.
@@ -1867,9 +1931,24 @@ static void PayoutThreadFn(void*)
1867 1931
1868 uint160 h160; 1932 uint160 h160;
1869 if (!AddressToHash160(r.address, h160)) { 1933 if (!AddressToHash160(r.address, h160)) {
1870 // Should not happen -- bad addresses are filtered in QueuePayouts 1934 // Should not happen -- bad addresses are filtered in
1871 LogPrint("payout", "[payout] SKIPPED bad address '%s'\n", 1935 // QueuePayouts. If one is here anyway it is decidable and
1872 r.address.c_str()); 1936 // permanent: there is no transaction that pays a string which
1937 // is not an address, so retrying is not waiting for anything.
1938 //
1939 // This used to only ForgetPayment(), which drops the in-flight
1940 // record and leaves the ledger entry claiming the debt and
1941 // pool_rounds.json advertising the recipient as unpaid
1942 // forever, with the next flush re-exploding it. Write it off
1943 // properly and say why.
1944 const std::string reason =
1945 strprintf("'%s' is not a valid address, so no transaction"
1946 " can pay it", r.address.c_str());
1947 LogPrint("payout", "[payout] SKIPPED bad address '%s' --"
1948 " %s owed for block %d cannot be paid\n",
1949 r.address.c_str(), FormatMoney(r.amount).c_str(),
1950 r.blockHeight);
1951 ForfeitPayoutRecipient(r, reason);
1873 ForgetPayment(r); 1952 ForgetPayment(r);
1874 continue; 1953 continue;
1875 } 1954 }
@@ -1926,13 +2005,17 @@ static void PayoutThreadFn(void*)
1926 // the operator's wallet and nothing on disk saying it was owed. 2005 // the operator's wallet and nothing on disk saying it was owed.
1927 // 2006 //
1928 // nTransactionFee is the part of the fee that can be known before 2007 // nTransactionFee is the part of the fee that can be known before
1929 // the transaction exists. The rest is GetMinFee(), a function of 2008 // the transaction exists, and in production it is 0 -- it is only
1930 // the serialised size and therefore of how many inputs SelectCoins 2009 // ever assigned from the GUI preferences dialog, which a pool node
1931 // ends up picking, which cannot be predicted from here -- so this 2010 // does not have -- so including it here changes nothing on this
1932 // gate deliberately does NOT try to reserve it. Refusing to attempt 2011 // pool and is kept only because a GUI operator can set it. The
1933 // a payment the wallet could actually have made would be its own 2012 // rest is GetMinFee(), a function of the serialised size and
1934 // way of not paying a miner. That residual is handled after the 2013 // therefore of how many inputs SelectCoins ends up picking, which
1935 // fact, by classifying the failure below. 2014 // cannot be predicted from here -- so this gate deliberately does
2015 // NOT try to reserve it. Refusing to attempt a payment the wallet
2016 // could actually have made would be its own way of not paying a
2017 // miner. That residual is handled after the fact, by asking the
2018 // wallet why it refused -- see ClassifyPayoutSendFailure.
1936 int64 nSpendable = GetBalance(); 2019 int64 nSpendable = GetBalance();
1937 if (nSpendable < r.amount + nTransactionFee) { 2020 if (nSpendable < r.amount + nTransactionFee) {
1938 r.deferrals++; 2021 r.deferrals++;
@@ -1977,7 +2060,8 @@ static void PayoutThreadFn(void*)
1977 wtx.mapValue["pool_payout_address"] = r.address; 2060 wtx.mapValue["pool_payout_address"] = r.address;
1978 wtx.mapValue["pool_payout_amount"] = strprintf("%lld", r.amount); 2061 wtx.mapValue["pool_payout_amount"] = strprintf("%lld", r.amount);
1979 2062
1980 if (SendMoney(sc, r.amount, wtx)) { 2063 SendMoneyOutcome outcome;
2064 if (SendMoney(sc, r.amount, wtx, outcome)) {
1981 // The wallet holds the transaction before this returns, so a 2065 // The wallet holds the transaction before this returns, so a
1982 // crash between here and the ledger write is recoverable: the 2066 // crash between here and the ledger write is recoverable: the
1983 // probe above finds it by id+address+amount and does not 2067 // probe above finds it by id+address+amount and does not
@@ -1989,74 +2073,67 @@ static void PayoutThreadFn(void*)
1989 FormatMoney(r.amount).c_str(), r.address.c_str(), 2073 FormatMoney(r.amount).c_str(), r.address.c_str(),
1990 wtx.GetHash().ToString().substr(0, 12).c_str()); 2074 wtx.GetHash().ToString().substr(0, 12).c_str());
1991 } else { 2075 } else {
1992 // Why did it fail? The answer decides whether this costs a 2076 // Why did it fail? The answer used to decide whether the
1993 // retry, and the retry budget is what eventually erases a 2077 // payment eventually got erased, and it was decided by
1994 // miner's money -- so guessing here is how a pool keeps coin 2078 // guessing from a balance snapshot -- see
1995 // it owes. 2079 // ClassifyPayoutSendFailure for the arithmetic and what it
2080 // cost. The wallet now says what it did, and nothing here
2081 // erases anything.
1996 // 2082 //
1997 // Re-read the conditions rather than trusting the ones checked 2083 // The lock state is re-read rather than trusted from before
1998 // before the attempt: SendMoney takes cs_main and can block for 2084 // the attempt: SendMoney takes cs_main and can block for a
1999 // a long time, so the balance and the lock state may both have 2085 // long time, so it may have moved underneath us. The funding
2000 // moved underneath it. 2086 // answer does not need re-reading -- it is a statement about
2001 // 2087 // the attempt that was actually made.
2002 // Short of coin covers the size-dependent part of the fee that 2088 bool fLocked = IsWalletLocked();
2003 // the gate above deliberately does not reserve: if the balance 2089 int64 nAfter = GetBalance();
2004 // no longer covers amount + configured fee + one fee tier, the 2090
2005 // failure is a funding shortfall, not a fault. 2091 if (ClassifyPayoutSendFailure(outcome.result, fLocked)
2006 int64 nAfter = GetBalance(); 2092 == PAYOUT_FAILURE_DEFER) {
2007 bool fLocked = IsWalletLocked(); 2093 // Conditions are temporarily wrong. Wait.
2008 bool fUnfunded = nAfter < r.amount + nTransactionFee + CENT;
2009
2010 if (fLocked || fUnfunded) {
2011 // Conditions are temporarily wrong. Wait; do not spend the
2012 // budget that leads to a permanent write-off.
2013 r.deferrals++; 2094 r.deferrals++;
2014 r.retryAfter = GetTime() + 60; 2095 r.retryAfter = GetTime() + 60;
2015 if (r.deferrals == 1 || r.deferrals % 60 == 0) 2096 if (r.deferrals == 1 || r.deferrals % 60 == 0)
2016 LogPrint("payout", "[payout] deferring %s to %s -- send" 2097 LogPrint("payout", "[payout] deferring %s to %s -- send"
2017 " failed with %s (%s spendable, %s needed with" 2098 " failed with %s (%s spendable; the wallet"
2018 " fee headroom); waiting %d min so far\n", 2099 " needed a fee of %s for a transaction this"
2100 " size); waiting %d min so far\n",
2019 FormatMoney(r.amount).c_str(), r.address.c_str(), 2101 FormatMoney(r.amount).c_str(), r.address.c_str(),
2020 fLocked ? "the wallet locked" : "too little coin", 2102 fLocked ? "the wallet locked" : "too little coin",
2021 FormatMoney(nAfter).c_str(), 2103 FormatMoney(nAfter).c_str(),
2022 FormatMoney(r.amount + nTransactionFee + CENT).c_str(), 2104 FormatMoney(outcome.nFeeRequired).c_str(),
2023 r.deferrals); 2105 r.deferrals);
2024 ReschedulePayment(r); 2106 ReschedulePayment(r);
2025 } else if (r.retries < 1440) { 2107 } else {
2026 // A genuine fault: funded, unlocked, block on the main 2108 // Funded, unlocked, block on the main chain, and the
2027 // chain, and the wallet still would not build or accept 2109 // wallet still would not build, sign or accept the
2028 // the transaction. Retry with backoff. 2110 // transaction. That is worth shouting about; it is not
2111 // grounds to keep the money.
2112 //
2113 // There is deliberately no give-up branch. It used to
2114 // forfeit the debt after 1440 of these, which is not a
2115 // decidable state -- it is a count of how long we have
2116 // been asking, and it was reached by misclassifying a
2117 // funding shortfall as a fault. A debt that is never
2118 // written off cannot be written off wrongly. The payment
2119 // stays in flight, keeps its ledger entry, keeps being
2120 // reported in pool_status.json as owed, and keeps
2121 // retrying once a minute until the operator or the wallet
2122 // makes it possible.
2029 r.retries++; 2123 r.retries++;
2030 r.retryAfter = GetTime() + 60; 2124 r.retryAfter = GetTime() + 60;
2031 ReschedulePayment(r); 2125 ReschedulePayment(r);
2032 LogPrint("payout", "[payout] FAILED to pay %s to %s" 2126 // Every minute at first, then hourly: a fault that is not
2033 " (%s spendable, wallet unlocked) -- retry %d/1440" 2127 // going away must not turn the log into one line a minute
2034 " in 60s\n", 2128 // forever, and must not go quiet either.
2035 FormatMoney(r.amount).c_str(), r.address.c_str(), 2129 if (r.retries <= 5 || r.retries % 60 == 0)
2036 FormatMoney(nAfter).c_str(), r.retries); 2130 LogPrint("payout", "[payout] FAILED to pay %s to %s"
2037 } else { 2131 " (%s spendable, wallet unlocked, block %d on"
2038 // 1440 failures that were each individually impossible to 2132 " the main chain) -- attempt %d, retrying in"
2039 // explain by maturity, funding, the wallet being locked, or 2133 " 60s; this debt stands until it is paid\n",
2040 // a reorg. That is the only state in which this payment can 2134 FormatMoney(r.amount).c_str(), r.address.c_str(),
2041 // be called impossible rather than merely blocked. 2135 FormatMoney(nAfter).c_str(), r.blockHeight,
2042 const std::string reason = strprintf( 2136 r.retries);
2043 "wallet refused this payment %d times while funded"
2044 " (%s spendable), unlocked, and block %d on the main"
2045 " chain", r.retries, FormatMoney(nAfter).c_str(),
2046 r.blockHeight);
2047 LogPrint("payout", "[payout] GIVING UP on %s to %s: %s"
2048 " -- payment forfeited\n",
2049 FormatMoney(r.amount).c_str(), r.address.c_str(),
2050 reason.c_str());
2051 // Write the debt off in the ledger as well as dropping the
2052 // in-flight record. Under the survives-until-fully-paid
2053 // model the entry would otherwise never complete, and every
2054 // later flush would explode it again -- a forfeit that
2055 // silently becomes an infinite retry. The round proof is
2056 // told too, so the public record does not keep claiming the
2057 // address is owed.
2058 ForfeitPayoutRecipient(r, reason);
2059 ForgetPayment(r);
2060 } 2137 }
2061 } 2138 }
2062 } 2139 }
@@ -2850,13 +2927,19 @@ static void PayoutTestRemoveDir(const std::string& dir)
2850 } 2927 }
2851 RemoveDirectoryA(dir.c_str()); 2928 RemoveDirectoryA(dir.c_str());
2852#else 2929#else
2930 // One level of recursion, because CreateTransaction() opens a Berkeley DB
2931 // environment and BDB puts its logs in a "database" subdirectory. Without
2932 // this the scratch directory cannot be removed and the test leaves one
2933 // behind on every run, which is what d5b3503 was for.
2853 DIR* d = opendir(dir.c_str()); 2934 DIR* d = opendir(dir.c_str());
2854 if (d) { 2935 if (d) {
2855 struct dirent* ent; 2936 struct dirent* ent;
2856 while ((ent = readdir(d)) != NULL) { 2937 while ((ent = readdir(d)) != NULL) {
2857 std::string name = ent->d_name; 2938 std::string name = ent->d_name;
2858 if (name == "." || name == "..") continue; 2939 if (name == "." || name == "..") continue;
2859 unlink((dir + "/" + name).c_str()); 2940 const std::string path = dir + "/" + name;
2941 if (unlink(path.c_str()) != 0)
2942 PayoutTestRemoveDir(path);
2860 } 2943 }
2861 closedir(d); 2944 closedir(d);
2862 } 2945 }
@@ -2942,6 +3025,48 @@ static std::string PayoutTestAddWalletTx(const std::string& comment,
2942 return hash.GetHex(); 3025 return hash.GetHex();
2943} 3026}
2944 3027
3028// A real key, in the keystore, so a test wallet's outputs are IsMine() and can
3029// actually be signed -- both are needed for CreateTransaction to build the
3030// large transaction the fee schedule is being tested against. Inserted
3031// straight into the key maps rather than through AddKey(), which would also
3032// write it to a wallet.dat.
3033static std::string PayoutTestAddSpendableKey()
3034{
3035 CKey key;
3036 key.MakeNewKey();
3037 std::vector<unsigned char> vchPubKey = key.GetPubKey();
3038 CRITICAL_BLOCK(cs_mapKeys)
3039 {
3040 mapKeys[vchPubKey] = key.GetPrivKey();
3041 mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
3042 }
3043 return Hash160ToAddress(Hash160(vchPubKey));
3044}
3045
3046// Give the wallet `n` spendable outputs of `each`, one transaction apiece --
3047// which is the granularity SelectCoins works at, and therefore the number of
3048// inputs the transaction spending them will carry.
3049//
3050// Deliberately not coinbases: a null prevout would make CWalletTx::GetCredit
3051// return 0 until COINBASE_SPENDABLE_DEPTH, and there is no chain here.
3052static void PayoutTestFundWallet(int n, int64 each, const std::string& address)
3053{
3054 const CScript sc = PayoutTestScriptFor(address);
3055 CRITICAL_BLOCK(cs_mapWallet)
3056 {
3057 for (int i = 0; i < n; i++) {
3058 CWalletTx wtx;
3059 wtx.vin.resize(1);
3060 wtx.vin[0].prevout.hash = (uint64)(i + 1);
3061 wtx.vin[0].prevout.n = 0;
3062 wtx.vout.resize(1);
3063 wtx.vout[0].nValue = each;
3064 wtx.vout[0].scriptPubKey = sc;
3065 mapWallet[wtx.GetHash()] = wtx;
3066 }
3067 }
3068}
3069
2945// Defined below with the event loop; the status-file publication test drives 3070// Defined below with the event loop; the status-file publication test drives
2946// it directly. 3071// it directly.
2947static void RefreshStats(int blocksFoundThisSession, uint64 roundShareTotal); 3072static void RefreshStats(int blocksFoundThisSession, uint64 roundShareTotal);
@@ -2967,11 +3092,32 @@ int RunPayoutLedgerSelfTest()
2967#else 3092#else
2968 unsigned long pid = (unsigned long)getpid(); 3093 unsigned long pid = (unsigned long)getpid();
2969#endif 3094#endif
2970 std::string dir = strprintf("payout_selftest_%d_%lu", (int)GetTime(), pid); 3095 // Absolute, and the process moves into it.
3096 //
3097 // Both are needed by the CreateTransaction section: Berkeley DB resolves
3098 // its log directory relative to the environment home, so a relative
3099 // datadir makes dbenv.open() fail with DB_RUNRECOVERY; and BDB opens
3100 // db.log relative to the working directory, which is src/ during `make
3101 // tests`. Moving in puts it inside the scratch directory, where it dies
3102 // with everything else.
3103 std::string cwd = ".";
3104 {
3105#ifdef _WIN32
3106 char buf[MAX_PATH];
3107 if (GetCurrentDirectoryA(MAX_PATH, buf) > 0) cwd = buf;
3108#else
3109 char buf[4096];
3110 if (getcwd(buf, sizeof(buf)) != NULL) cwd = buf;
3111#endif
3112 }
3113 std::string dir = cwd + "/" +
3114 strprintf("payout_selftest_%d_%lu", (int)GetTime(), pid);
2971#ifdef _WIN32 3115#ifdef _WIN32
2972 CreateDirectoryA(dir.c_str(), NULL); 3116 CreateDirectoryA(dir.c_str(), NULL);
3117 SetCurrentDirectoryA(dir.c_str());
2973#else 3118#else
2974 mkdir(dir.c_str(), 0700); 3119 mkdir(dir.c_str(), 0700);
3120 if (chdir(dir.c_str()) != 0) { /* stay put; the paths are absolute anyway */ }
2975#endif 3121#endif
2976 strSetDataDir = dir; 3122 strSetDataDir = dir;
2977 fprintf(stdout, " scratch datadir: %s\n", dir.c_str()); 3123 fprintf(stdout, " scratch datadir: %s\n", dir.c_str());
@@ -3494,7 +3640,141 @@ int RunPayoutLedgerSelfTest()
3494 strPoolRoundsFile = savedRoundsFile; 3640 strPoolRoundsFile = savedRoundsFile;
3495 } 3641 }
3496 3642
3497 // -- 11. No payout mutex is held across the status-file write ------------ 3643 // -- 11. A send that failed for want of coin is not a fault --------------
3644 //
3645 // The defect this replaces: the classifier decided "was this a funding
3646 // problem?" by re-reading GetBalance() and allowing amount +
3647 // nTransactionFee + CENT. nTransactionFee is 0 on a headless node, and
3648 // GetMinFee() is a step function -- 0 below 10,000 bytes, 11 * CENT at it
3649 // -- so the allowance was either unnecessary or eleven times too small,
3650 // and the ledger's own retry budget then wrote the debt off after 1440
3651 // repeats of the same stable condition.
3652 //
3653 // This is tested against a real wallet and the real CreateTransaction, not
3654 // against injected values: the honest question is not "does my enum
3655 // switch work" but "does a wallet holding many small coins actually report
3656 // the state I think it does". 60 outputs of 1 BTF give ~180 signed P2PKH
3657 // bytes each, which is where the fee schedule steps. Nothing is committed
3658 // or broadcast -- CreateTransaction only builds.
3659 {
3660 PayoutTestResetState();
3661 CRITICAL_BLOCK(cs_mapWallet)
3662 mapWallet.clear();
3663
3664 // CreateTransaction opens CTxDB("r"), which throws if blkindex.dat is
3665 // not there. Create it in the scratch datadir first.
3666 bool dbOk = true;
3667 try {
3668 CTxDB txdb("cr");
3669 } catch (const std::exception&) {
3670 dbOk = false;
3671 }
3672 check(dbOk, "a scratch block index exists for CreateTransaction to open");
3673
3674 const std::string walletAddr = PayoutTestAddSpendableKey();
3675 const std::string payee = PayoutTestAddress(0x77);
3676 const CScript payeeScript = PayoutTestScriptFor(payee);
3677
3678 // -- the >= 10 KB case: 60 small coins, balance = amount + 0.05 ------
3679 PayoutTestFundWallet(60, 1 * COIN, walletAddr);
3680 const int64 balance = GetBalance();
3681 check(balance == 60 * COIN,
3682 "the test wallet holds 60 separately spendable coins");
3683
3684 const int64 amount = balance - 5 * CENT;
3685 // The pre-send gate in PayoutThreadFn passes: the balance covers the
3686 // amount and the only fee that can be known in advance.
3687 check(balance >= amount + nTransactionFee,
3688 "the pre-send gate would let this payment through");
3689
3690 CWalletTx wtx;
3691 SendMoneyOutcome outcome;
3692 int64 feeRequired = 0;
3693 WalletSendResult result = WALLET_SEND_OK;
3694 bool built = true;
3695 if (dbOk) {
3696 try {
3697 built = CreateTransaction(payeeScript, amount, wtx, feeRequired,
3698 &result);
3699 } catch (const std::exception&) {
3700 built = true; // report as a failure below
3701 }
3702 }
3703 check(dbOk && !built,
3704 "a wallet of many small coins cannot fund amount + the fee its"
3705 " own size demands");
3706 check(dbOk && result == WALLET_SEND_INSUFFICIENT_FUNDS,
3707 "the wallet reports that as a funding shortfall, not as a"
3708 " failure to build");
3709 // GetMinFee(fDiscount) returns 0 below 10,000 bytes and
3710 // (1 + bytes/1000) * CENT at or above, so a required fee of 11 CENT or
3711 // more IS the statement that the transaction crossed 10 KB. Measured
3712 // through the real serialiser rather than asserted.
3713 check(dbOk && feeRequired >= 11 * CENT,
3714 "the transaction it built crossed 10,000 bytes, so the fee"
3715 " stepped from 0 to at least 11 CENT");
3716
3717 // The defect, stated as arithmetic. The old classifier asked whether
3718 // the balance covered amount + nTransactionFee + CENT; it did, so it
3719 // called a permanent funding shortfall a fault and started counting
3720 // towards a write-off.
3721 check(!(balance < amount + nTransactionFee + CENT),
3722 "the reserve this replaces would have judged this send a fault");
3723 check(balance < amount + feeRequired,
3724 "while the fee actually required was more than the balance had");
3725
3726 outcome.result = result;
3727 outcome.nFeeRequired = feeRequired;
3728 check(dbOk && ClassifyPayoutSendFailure(outcome.result, false)
3729 == PAYOUT_FAILURE_DEFER,
3730 "a >= 10 KB send that ran out of coin is deferred, not counted"
3731 " against the payment");
3732
3733 // -- the < 10 KB case: no reserve is needed at all -------------------
3734 //
3735 // The other half of the arithmetic. Below the step the required fee is
3736 // 0, so a reserve of any size is a reason to refuse a payment the
3737 // wallet could have made -- which is its own way of not paying a
3738 // miner.
3739 CRITICAL_BLOCK(cs_mapWallet)
3740 mapWallet.clear();
3741 PayoutTestFundWallet(3, 1 * COIN, walletAddr);
3742 const int64 smallAmount = 3 * COIN - 5 * CENT;
3743 CWalletTx smallTx;
3744 int64 smallFee = -1;
3745 WalletSendResult smallResult = WALLET_SEND_FAILED;
3746 bool smallBuilt = false;
3747 if (dbOk) {
3748 try {
3749 smallBuilt = CreateTransaction(payeeScript, smallAmount, smallTx,
3750 smallFee, &smallResult);
3751 } catch (const std::exception&) {
3752 smallBuilt = false;
3753 }
3754 }
3755 check(dbOk && smallBuilt && smallResult == WALLET_SEND_OK,
3756 "the same balance pays a small transaction with no headroom at"
3757 " all");
3758 check(dbOk && smallFee == 0,
3759 "because below 10,000 bytes the required fee is zero");
3760
3761 // -- and the classification of every other answer --------------------
3762 check(ClassifyPayoutSendFailure(WALLET_SEND_INSUFFICIENT_FUNDS, false)
3763 == PAYOUT_FAILURE_DEFER &&
3764 ClassifyPayoutSendFailure(WALLET_SEND_INSUFFICIENT_FUNDS, true)
3765 == PAYOUT_FAILURE_DEFER &&
3766 ClassifyPayoutSendFailure(WALLET_SEND_FAILED, true)
3767 == PAYOUT_FAILURE_DEFER,
3768 "short of coin or unable to sign is always a deferral");
3769 check(ClassifyPayoutSendFailure(WALLET_SEND_FAILED, false)
3770 == PAYOUT_FAILURE_FAULT,
3771 "funded and unlocked and still refused is a fault");
3772
3773 CRITICAL_BLOCK(cs_mapWallet)
3774 mapWallet.clear();
3775 }
3776
3777 // -- 12. No payout mutex is held across the status-file write ------------
3498 // 3778 //
3499 // RefreshStats runs on the event loop -- the thread that owns every 3779 // RefreshStats runs on the event loop -- the thread that owns every
3500 // miner's socket -- and used to hold gStatsMutex and gPayoutLedgerMutex at 3780 // miner's socket -- and used to hold gStatsMutex and gPayoutLedgerMutex at
@@ -3628,6 +3908,19 @@ int RunPayoutLedgerSelfTest()
3628 PayoutTestResetState(); 3908 PayoutTestResetState();
3629 CRITICAL_BLOCK(cs_mapWallet) 3909 CRITICAL_BLOCK(cs_mapWallet)
3630 mapWallet.clear(); 3910 mapWallet.clear();
3911 // Out of the scratch directory before removing it, and out of the key maps
3912 // too: the keys this test generated are process-local, but leaving them in
3913 // the keystore would let a later test think a script was its own.
3914 CRITICAL_BLOCK(cs_mapKeys)
3915 {
3916 mapKeys.clear();
3917 mapPubKeys.clear();
3918 }
3919#ifdef _WIN32
3920 SetCurrentDirectoryA(cwd.c_str());
3921#else
3922 if (chdir(cwd.c_str()) != 0) { /* nothing useful to do about it */ }
3923#endif
3631 PayoutTestRemoveDir(dir); 3924 PayoutTestRemoveDir(dir);
3632 strSetDataDir = savedDataDir; 3925 strSetDataDir = savedDataDir;
3633 nBestHeight = savedBestHeight; 3926 nBestHeight = savedBestHeight;