Skip to content

Commit

Permalink
Merge bitcoin#13339: wallet: Replace %w by wallet name in -walletnoti…
Browse files Browse the repository at this point in the history
…fy script

4e9efac test: Check wallet name in -walletnotify script (João Barbosa)
9a5b5ee wallet: Replace %w by wallet name in -walletnotify script (João Barbosa)

Pull request description:

  Fixes bitcoin#13237.

ACKs for top commit:
  laanwj:
    ACK 4e9efac

Tree-SHA512: 189dd1c785485f2e974d7c12531851b2a977778b3b954aa95efd527322ba3345924cfd587fb9c90b0fa979202af0ab2d90e53d125fe266a36c94f757e4176203
  • Loading branch information
laanwj authored and sidhujag committed Feb 18, 2020
1 parent dfa49c0 commit 0f86b36
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 4 deletions.
10 changes: 10 additions & 0 deletions src/util/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#include <malloc.h>
#endif

#include <boost/algorithm/string/replace.hpp>
#include <thread>
// SYSCOIN only features
#include <boost/algorithm/string.hpp>
Expand Down Expand Up @@ -1727,6 +1728,15 @@ fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
}
#endif

#ifndef WIN32
std::string ShellEscape(const std::string& arg)
{
std::string escaped = arg;
boost::replace_all(escaped, "'", "'\"'\"'");
return "'" + escaped + "'";
}
#endif

#if HAVE_SYSTEM
void runCommand(const std::string& strCommand)
{
Expand Down
3 changes: 3 additions & 0 deletions src/util/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ fs::path GetConfigFile(const std::string& confPath);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
#ifndef WIN32
std::string ShellEscape(const std::string& arg);
#endif
#if HAVE_SYSTEM
void runCommand(const std::string& strCommand);
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void WalletInit::AddWalletOptions() const
gArgs.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
gArgs.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
#if HAVE_SYSTEM
gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID and %w is replaced by wallet name. %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
#endif
gArgs.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
gArgs.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
Expand Down
8 changes: 8 additions & 0 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,14 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
if (!strCmd.empty())
{
boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
#ifndef WIN32
// Substituting the wallet name isn't currently supported on windows
// because windows shell escaping has not been implemented yet:
// https://github.com/bitcoin/bitcoin/pull/13339#issuecomment-537384875
// A few ways it could be implemented in the future are described in:
// https://github.com/bitcoin/bitcoin/pull/13339#issuecomment-461288094
boost::replace_all(strCmd, "%w", ShellEscape(GetName()));
#endif
std::thread t(runCommand, strCmd);
t.detach(); // thread runs free
}
Expand Down
18 changes: 15 additions & 3 deletions test/functional/feature_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,24 @@
connect_nodes,
)

# Linux allow all characters other than \x00
# Windows disallow control characters (0-31) and /\?%:|"<>
FILE_CHAR_START = 32 if os.name == 'nt' else 1
FILE_CHAR_END = 128
FILE_CHAR_BLACKLIST = '/\\?%*:|"<>' if os.name == 'nt' else '/'


def notify_outputname(walletname, txid):
return txid if os.name == 'nt' else '{}_{}'.format(walletname, txid)


class NotificationsTest(SyscoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True

def setup_network(self):
self.wallet = ''.join(chr(i) for i in range(FILE_CHAR_START, FILE_CHAR_END) if chr(i) not in FILE_CHAR_BLACKLIST)
self.alertnotify_dir = os.path.join(self.options.tmpdir, "alertnotify")
self.blocknotify_dir = os.path.join(self.options.tmpdir, "blocknotify")
self.walletnotify_dir = os.path.join(self.options.tmpdir, "walletnotify")
Expand All @@ -33,7 +44,8 @@ def setup_network(self):
"-blocknotify=echo > {}".format(os.path.join(self.blocknotify_dir, '%s'))],
["-blockversion=211",
"-rescan",
"-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, '%s'))]]
"-wallet={}".format(self.wallet),
"-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s')))]]
super().setup_network()

def run_test(self):
Expand All @@ -53,7 +65,7 @@ def run_test(self):
wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)

# directory content should equal the generated transaction hashes
txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
txids_rpc = list(map(lambda t: notify_outputname(self.wallet, t['txid']), self.nodes[1].listtransactions("*", block_count)))
assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))
self.stop_node(1)
for tx_file in os.listdir(self.walletnotify_dir):
Expand All @@ -67,7 +79,7 @@ def run_test(self):
wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)

# directory content should equal the generated transaction hashes
txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
txids_rpc = list(map(lambda t: notify_outputname(self.wallet, t['txid']), self.nodes[1].listtransactions("*", block_count)))
assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))

# TODO: add test for `-alertnotify` large fork notifications
Expand Down

0 comments on commit 0f86b36

Please sign in to comment.