diff options
Diffstat (limited to 'src/rpc.cpp')
| -rw-r--r-- | src/rpc.cpp | 441 |
1 files changed, 367 insertions, 74 deletions
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. | ||
| 1861 | enum 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 | |||
| 1866 | static 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. | ||
| 3033 | static 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. | ||
| 3052 | static 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. |
| 2947 | static void RefreshStats(int blocksFoundThisSession, uint64 roundShareTotal); | 3072 | static 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; |