Skip to content

Commit eb7d244

Browse files
Merge dashpay#5928: backport: Merge bitcoin#20406, 21370, 21395, 21007, 20040, 21418, 21447, 20197, 21613, 21602
daacafb Merge bitcoin#21426: rpc: remove scantxoutset EXPERIMENTAL warning (MarcoFalke) b8aec5c Merge bitcoin#20197: p2p: protect onions in AttemptToEvictConnection(), add eviction protection test coverage (Wladimir J. van der Laan) dd92322 Merge bitcoin#21447: Always add -daemonwait to known command line arguments (Wladimir J. van der Laan) 3325620 Merge bitcoin#21418: contrib: Make systemd invoke dependencies only when ready (Wladimir J. van der Laan) 99f09a0 Merge bitcoin#20040: wallet: Refactor OutputGroups to handle fees and spending eligibility on grouping (Samuel Dobson) 6ca0eb1 Merge bitcoin#21007: bitcoind: Add -daemonwait option to wait for initialization (Wladimir J. van der Laan) 666e6e2 Merge bitcoin#20406: util: Avoid invalid integer negation in FormatMoney and ValueFromAmount (Wladimir J. van der Laan) 1a07e04 Merge bitcoin#21370: Use C++11 member initializer in CNodeState (fanquake) 6423f6b Merge bitcoin#21395: Net processing: Remove unused CNode.address member (MarcoFalke) Pull request description: bitcoin backports Top commit has no ACKs. Tree-SHA512: dc9490c6c99cc08e8c8ffbd6b71f48e8df8b51dd2d7ca940de44ff47ab28ec3e2d45b7e381a7124d513f7e29ad13300c9df68acd7ddec3022a603eca162b12f3
2 parents 2dacfb0 + daacafb commit eb7d244

32 files changed

+1085
-488
lines changed

configure.ac

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,8 +1007,9 @@ AC_CHECK_DECLS([getifaddrs, freeifaddrs],[CHECK_SOCKET],,
10071007
)
10081008
AC_CHECK_DECLS([strnlen])
10091009

1010-
dnl Check for daemon(3), unrelated to --with-daemon (although used by it)
1011-
AC_CHECK_DECLS([daemon])
1010+
dnl These are used for daemonization in dashd
1011+
AC_CHECK_DECLS([fork])
1012+
AC_CHECK_DECLS([setsid])
10121013

10131014
AC_CHECK_DECLS([pipe2])
10141015

contrib/init/dashd.service

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ After=network-online.target
1818
Wants=network-online.target
1919

2020
[Service]
21-
ExecStart=/usr/bin/dashd -daemon \
21+
ExecStart=/usr/bin/dashd -daemonwait \
2222
-pid=/run/dashd/dashd.pid \
2323
-conf=/etc/dash/dash.conf \
2424
-datadir=/var/lib/dashd
@@ -33,6 +33,7 @@ ExecStartPre=/bin/chgrp dashcore /etc/dash
3333
Type=forking
3434
PIDFile=/run/dashd/dashd.pid
3535
Restart=on-failure
36+
TimeoutStartSec=infinity
3637
TimeoutStopSec=600
3738

3839
# Directory creation and permissions

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ BITCOIN_CORE_H = \
355355
util/time.h \
356356
util/thread.h \
357357
util/threadnames.h \
358+
util/tokenpipe.h \
358359
util/trace.h \
359360
util/translation.h \
360361
util/ui_change_type.h \
@@ -792,6 +793,7 @@ libbitcoin_util_a_SOURCES = \
792793
util/string.cpp \
793794
util/thread.cpp \
794795
util/threadnames.cpp \
796+
util/tokenpipe.cpp \
795797
$(BITCOIN_CORE_H)
796798

797799
if USE_LIBEVENT

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ BITCOIN_TESTS =\
132132
test/merkleblock_tests.cpp \
133133
test/miner_tests.cpp \
134134
test/multisig_tests.cpp \
135+
test/net_peer_eviction_tests.cpp \
135136
test/net_tests.cpp \
136137
test/netbase_tests.cpp \
137138
test/pmt_tests.cpp \

src/bench/coin_selection.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,18 @@ static void CoinSelection(benchmark::Bench& bench)
4242
}
4343
addCoin(3 * COIN, wallet, wtxs);
4444

45-
// Create groups
46-
std::vector<OutputGroup> groups;
45+
// Create coins
46+
std::vector<COutput> coins;
4747
for (const auto& wtx : wtxs) {
48-
COutput output(wtx.get(), 0 /* iIn */, 6 * 24 /* nDepthIn */, true /* spendable */, true /* solvable */, true /* safe */);
49-
groups.emplace_back(output.GetInputCoin(), 6, false, 0, 0);
48+
coins.emplace_back(wtx.get(), 0 /* iIn */, 6 * 24 /* nDepthIn */, true /* spendable */, true /* solvable */, true /* safe */);
5049
}
5150
const CoinEligibilityFilter filter_standard(1, 6, 0);
52-
const CoinSelectionParams coin_selection_params(true, 34, 148, CFeeRate(0), 0);
51+
const CoinSelectionParams coin_selection_params(true, 34, 148, CFeeRate(0), 0, false);
5352
bench.run([&] {
5453
std::set<CInputCoin> setCoinsRet;
5554
CAmount nValueRet;
5655
bool bnb_used;
57-
bool success = wallet.SelectCoinsMinConf(1003 * COIN, filter_standard, groups, setCoinsRet, nValueRet, coin_selection_params, bnb_used);
56+
bool success = wallet.SelectCoinsMinConf(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params, bnb_used);
5857
assert(success);
5958
assert(nValueRet == 1003 * COIN);
6059
assert(setCoinsRet.size() == 2);
@@ -74,7 +73,8 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>
7473
tx.vout.resize(nInput + 1);
7574
tx.vout[nInput].nValue = nValue;
7675
std::unique_ptr<CWalletTx> wtx = std::make_unique<CWalletTx>(&testWallet, MakeTransactionRef(std::move(tx)));
77-
set.emplace_back(COutput(wtx.get(), nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0);
76+
set.emplace_back();
77+
set.back().Insert(COutput(wtx.get(), nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0, false);
7878
wtxn.emplace_back(std::move(wtx));
7979
}
8080
// Copied from src/wallet/test/coinselector_tests.cpp

src/bitcoind.cpp

Lines changed: 111 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <util/system.h>
2222
#include <util/strencodings.h>
2323
#include <util/threadnames.h>
24+
#include <util/tokenpipe.h>
2425
#include <util/translation.h>
2526
#include <stacktraces.h>
2627
#include <util/url.h>
@@ -35,6 +36,79 @@ UrlDecodeFn* const URL_DECODE = urlDecode;
3536
//
3637
// Start
3738
//
39+
#if HAVE_DECL_FORK
40+
41+
/** Custom implementation of daemon(). This implements the same order of operations as glibc.
42+
* Opens a pipe to the child process to be able to wait for an event to occur.
43+
*
44+
* @returns 0 if successful, and in child process.
45+
* >0 if successful, and in parent process.
46+
* -1 in case of error (in parent process).
47+
*
48+
* In case of success, endpoint will be one end of a pipe from the child to parent process,
49+
* which can be used with TokenWrite (in the child) or TokenRead (in the parent).
50+
*/
51+
int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint)
52+
{
53+
// communication pipe with child process
54+
std::optional<TokenPipe> umbilical = TokenPipe::Make();
55+
if (!umbilical) {
56+
return -1; // pipe or pipe2 failed.
57+
}
58+
59+
int pid = fork();
60+
if (pid < 0) {
61+
return -1; // fork failed.
62+
}
63+
if (pid != 0) {
64+
// Parent process gets read end, closes write end.
65+
endpoint = umbilical->TakeReadEnd();
66+
umbilical->TakeWriteEnd().Close();
67+
68+
int status = endpoint.TokenRead();
69+
if (status != 0) { // Something went wrong while setting up child process.
70+
endpoint.Close();
71+
return -1;
72+
}
73+
74+
return pid;
75+
}
76+
// Child process gets write end, closes read end.
77+
endpoint = umbilical->TakeWriteEnd();
78+
umbilical->TakeReadEnd().Close();
79+
80+
#if HAVE_DECL_SETSID
81+
if (setsid() < 0) {
82+
exit(1); // setsid failed.
83+
}
84+
#endif
85+
86+
if (!nochdir) {
87+
if (chdir("/") != 0) {
88+
exit(1); // chdir failed.
89+
}
90+
}
91+
if (!noclose) {
92+
// Open /dev/null, and clone it into STDIN, STDOUT and STDERR to detach
93+
// from terminal.
94+
int fd = open("/dev/null", O_RDWR);
95+
if (fd >= 0) {
96+
bool err = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0;
97+
// Don't close if fd<=2 to try to handle the case where the program was invoked without any file descriptors open.
98+
if (fd > 2) close(fd);
99+
if (err) {
100+
exit(1); // dup2 failed.
101+
}
102+
} else {
103+
exit(1); // open /dev/null failed.
104+
}
105+
}
106+
endpoint.TokenWrite(0); // Success
107+
return 0;
108+
}
109+
110+
#endif
111+
38112
static bool AppInit(int argc, char* argv[])
39113
{
40114
NodeContext node;
@@ -72,6 +146,14 @@ static bool AppInit(int argc, char* argv[])
72146
}
73147

74148
CoreContext context{node};
149+
#if HAVE_DECL_FORK
150+
// Communication with parent after daemonizing. This is used for signalling in the following ways:
151+
// - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
152+
// that the parent process can quit, and whether it was successful/unsuccessful.
153+
// - an unexpected shutdown of the child process creates an unexpected end of stream at the parent
154+
// end, which is interpreted as failure to start.
155+
TokenPipeEnd daemon_ep;
156+
#endif
75157
try
76158
{
77159
if (!CheckDataDirOption()) {
@@ -117,24 +199,34 @@ static bool AppInit(int argc, char* argv[])
117199
// InitError will have been called with detailed error, which ends up on console
118200
return false;
119201
}
120-
if (args.GetBoolArg("-daemon", false)) {
121-
#if HAVE_DECL_DAEMON
122-
#if defined(MAC_OSX)
123-
#pragma GCC diagnostic push
124-
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
125-
#endif
202+
if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
203+
#if HAVE_DECL_FORK
126204
tfm::format(std::cout, PACKAGE_NAME " starting\n");
127205

128206
// Daemonize
129-
if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
130-
return InitError(Untranslated(strprintf("daemon() failed: %s\n", strerror(errno))));
207+
switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
208+
case 0: // Child: continue.
209+
// If -daemonwait is not enabled, immediately send a success token the parent.
210+
if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
211+
daemon_ep.TokenWrite(1);
212+
daemon_ep.Close();
213+
}
214+
break;
215+
case -1: // Error happened.
216+
return InitError(Untranslated(strprintf("fork_daemon() failed: %s\n", strerror(errno))));
217+
default: { // Parent: wait and exit.
218+
int token = daemon_ep.TokenRead();
219+
if (token) { // Success
220+
exit(EXIT_SUCCESS);
221+
} else { // fRet = false or token read error (premature exit).
222+
tfm::format(std::cerr, "Error during initializaton - check debug.log for details\n");
223+
exit(EXIT_FAILURE);
224+
}
225+
}
131226
}
132-
#if defined(MAC_OSX)
133-
#pragma GCC diagnostic pop
134-
#endif
135227
#else
136228
return InitError(Untranslated("-daemon is not supported on this operating system\n"));
137-
#endif // HAVE_DECL_DAEMON
229+
#endif // HAVE_DECL_FORK
138230
}
139231
// Lock data directory after daemonization
140232
if (!AppInitLockDataDirectory())
@@ -147,6 +239,13 @@ static bool AppInit(int argc, char* argv[])
147239
PrintExceptionContinue(std::current_exception(), "AppInit()");
148240
}
149241

242+
#if HAVE_DECL_FORK
243+
if (daemon_ep.IsOpen()) {
244+
// Signal initialization status to parent, then close pipe.
245+
daemon_ep.TokenWrite(fRet);
246+
daemon_ep.Close();
247+
}
248+
#endif
150249
if (fRet) {
151250
WaitForShutdown();
152251
}

src/core_io.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strN
4141
int ParseSighashString(const UniValue& sighash);
4242

4343
// core_write.cpp
44-
UniValue ValueFromAmount(const CAmount& amount);
44+
UniValue ValueFromAmount(const CAmount amount);
4545
std::string FormatScript(const CScript& script);
4646
std::string EncodeHexTx(const CTransaction& tx);
4747
std::string SighashToStr(unsigned char sighash_type);

src/core_write.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <univalue.h>
1616
#include <util/check.h>
1717
#include <util/strencodings.h>
18+
#include <util/system.h>
1819

1920
#include <addressindex.h>
2021
#include <spentindex.h>
@@ -26,14 +27,17 @@
2627
#include <evo/specialtx.h>
2728
#include <llmq/commitment.h>
2829

29-
UniValue ValueFromAmount(const CAmount& amount)
30+
UniValue ValueFromAmount(const CAmount amount)
3031
{
31-
bool sign = amount < 0;
32-
int64_t n_abs = (sign ? -amount : amount);
33-
int64_t quotient = n_abs / COIN;
34-
int64_t remainder = n_abs % COIN;
32+
static_assert(COIN > 1);
33+
int64_t quotient = amount / COIN;
34+
int64_t remainder = amount % COIN;
35+
if (amount < 0) {
36+
quotient = -quotient;
37+
remainder = -remainder;
38+
}
3539
return UniValue(UniValue::VNUM,
36-
strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
40+
strprintf("%s%d.%08d", amount < 0 ? "-" : "", quotient, remainder));
3741
}
3842

3943
std::string FormatScript(const CScript& script)

src/evo/cbtx.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class CChainLocksHandler;
2424
}// namespace llmq
2525

2626
// Forward declaration from core_io to get rid of circular dependency
27-
UniValue ValueFromAmount(const CAmount& amount);
27+
UniValue ValueFromAmount(const CAmount amount);
2828

2929
// coinbase transaction
3030
class CCbTx

src/init.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -779,10 +779,12 @@ void SetupServerArgs(NodeContext& node)
779779
argsman.AddArg("-statsport=<port>", strprintf("Specify statsd port (default: %u)", DEFAULT_STATSD_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
780780
argsman.AddArg("-statsns=<ns>", strprintf("Specify additional namespace prefix (default: %s)", DEFAULT_STATSD_NAMESPACE), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
781781
argsman.AddArg("-statsperiod=<seconds>", strprintf("Specify the number of seconds between periodic measurements (default: %d)", DEFAULT_STATSD_PERIOD), ArgsManager::ALLOW_ANY, OptionsCategory::STATSD);
782-
#if HAVE_DECL_DAEMON
783-
argsman.AddArg("-daemon", "Run in the background as a daemon and accept commands", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
782+
#if HAVE_DECL_FORK
783+
argsman.AddArg("-daemon", strprintf("Run in the background as a daemon and accept commands (default: %d)", DEFAULT_DAEMON), ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
784+
argsman.AddArg("-daemonwait", strprintf("Wait for initialization to be finished before exiting. This implies -daemon (default: %d)", DEFAULT_DAEMONWAIT), ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
784785
#else
785786
hidden_args.emplace_back("-daemon");
787+
hidden_args.emplace_back("-daemonwait");
786788
#endif
787789

788790
// Add the hidden options

0 commit comments

Comments
 (0)