From 08349ee1dac501679c9a20b46378cb22baeb1dce Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 28 Sep 2020 20:44:25 +0200 Subject: [PATCH 1/4] Merge #15367: feature: Added ability for users to add a startup command 090530cc24054d6b4658752bb88f75a3b73eab5d feature: Added ability for users to add a startup command (Ben Carman) Pull request description: Thoughts for adding the feature is for users to be able to add things like electrum-personal-server or lnd to run whenever Bitcoin Core is running. Open to feedback about the feature. ACKs for top commit: MarcoFalke: re-ACK 090530cc24 dongcarl: tACK 090530c Tree-SHA512: ba514d2fc8b4fb12b781c1a9c89845a25fce0b80ba7c907761cde4abb81edd03fa643682edc895986dc20b273ac3b95769508806db7fbd99ec28623f85c41e67 --- doc/release-notes-15367.md | 6 ++++++ src/init.cpp | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 doc/release-notes-15367.md diff --git a/doc/release-notes-15367.md b/doc/release-notes-15367.md new file mode 100644 index 0000000000000..fed8967bc0f77 --- /dev/null +++ b/doc/release-notes-15367.md @@ -0,0 +1,6 @@ +Configuration option changes +---------------------------- + +- The `startupnotify` option is used to specify a command to + execute when Dash Core has finished with its startup + sequence. (#5728) \ No newline at end of file diff --git a/src/init.cpp b/src/init.cpp index 041578528f73a..f38f8cfd24dde 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -539,6 +539,9 @@ void SetupServerArgs(NodeContext& node) "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-settings=", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-syncmempool", strprintf("Sync mempool from other nodes on start (default: %u)", DEFAULT_SYNC_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); +#if HAVE_SYSTEM + argsman.AddArg("-startupnotify=", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); +#endif #ifndef WIN32 argsman.AddArg("-sysperms", "Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); #else @@ -859,6 +862,17 @@ static void CleanupBlockRevFiles() } } +#if HAVE_SYSTEM +static void StartupNotify(const ArgsManager& args) +{ + std::string cmd = args.GetArg("-startupnotify", ""); + if (!cmd.empty()) { + std::thread t(runCommand, cmd); + t.detach(); // thread runs free + } +} +#endif + static void PeriodicStats(ArgsManager& args, const CTxMemPool& mempool) { assert(args.GetBoolArg("-statsenabled", DEFAULT_STATSD_ENABLE)); @@ -2537,5 +2551,9 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc banman->DumpBanlist(); }, DUMP_BANS_INTERVAL); +#if HAVE_SYSTEM + StartupNotify(args); +#endif + return true; } From e29a35a997072064fb58ca0b160da79e68b475d3 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 1 Oct 2020 17:41:22 +0200 Subject: [PATCH 2/4] Merge #18309: zmq: Add support to listen on multiple interfaces e66870c5a4c2adbd30dca67d409fd5cd98697587 zmq: Append address to notify log output (nthumann) 241803da211265444e65f254f24dd184f2457fa9 test: Add zmq test to support multiple interfaces (nthumann) a0b2e5cb6aa8db0563fac7d67a949b9baefe3a25 doc: Add release notes to support multiple interfaces (nthumann) b1c3f180ecb63f3960506d202feebaa4271058ae doc: Adjust ZMQ usage to support multiple interfaces (nthumann) 347c94f551c3f144c44e00373e4dd61ff6d908b7 zmq: Add support to listen on multiple interfaces (Nicolas Thumann) Pull request description: This PR adds support for ZeroMQ to listen on multiple interfaces, just like the RPC server. Currently, if you specify more than one e.g. `zmqpubhashblock` paramter, only the first one will be used. Therefore a user may be forced to listen on all interfaces (e.g. `zmqpubhashblock=0.0.0.0:28332`), which can result in an increased attack surface. With this PR a user can specify multiple interfaces to listen on, e.g. `-zmqpubhashblock=tcp://127.0.0.1:28332 -zmqpubhashblock=tcp://192.168.1.123:28332`. ACKs for top commit: laanwj: Code review ACK e66870c5a4c2adbd30dca67d409fd5cd98697587 instagibbs: reACK https://github.com/bitcoin/bitcoin/pull/18309/commits/e66870c5a4c2adbd30dca67d409fd5cd98697587 Tree-SHA512: f38ab4a6ff00dc821e5f4842508cefadb701e70bb3893992c1b32049be20247c8aa9476a1f886050c5f17fe7f2ce99ee30193ce2c81a7482a5a51f8fc22300c7 --- doc/release-notes-18309.md | 4 ++++ doc/zmq.md | 2 ++ src/zmq/zmqnotificationinterface.cpp | 6 ++---- src/zmq/zmqpublishnotifier.cpp | 16 ++++++++-------- test/functional/interface_zmq.py | 25 +++++++++++++++++++++++++ 5 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 doc/release-notes-18309.md diff --git a/doc/release-notes-18309.md b/doc/release-notes-18309.md new file mode 100644 index 0000000000000..b31f85eb6ed0e --- /dev/null +++ b/doc/release-notes-18309.md @@ -0,0 +1,4 @@ +Command-line options +----------------------------- + +The same ZeroMQ notification (e.g. `-zmqpubhashtx=address`) can now be specified multiple times to publish the same notification to different ZeroMQ sockets. \ No newline at end of file diff --git a/doc/zmq.md b/doc/zmq.md index ee8fd82430431..9447bf2928cc1 100644 --- a/doc/zmq.md +++ b/doc/zmq.md @@ -80,6 +80,7 @@ Currently, the following notifications are supported: The socket type is PUB and the address must be a valid ZeroMQ socket address. The same address can be used in more than one notification. +The same notification can be specified more than once. The option to set the PUB socket's outbound message high water mark (SNDHWM) may be set individually for each notification: @@ -108,6 +109,7 @@ The high water mark value must be an integer greater than or equal to 0. For instance: $ dashd -zmqpubhashtx=tcp://127.0.0.1:28332 \ + -zmqpubhashtx=tcp://192.168.1.2:28332 \ -zmqpubrawtx=ipc:///tmp/dashd.tx.raw \ -zmqpubhashtxhwm=10000 diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 904b380a37ca5..073ba4ae9d9da 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -55,10 +55,8 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create() for (const auto& entry : factories) { std::string arg("-zmq" + entry.first); - if (gArgs.IsArgSet(arg)) - { - const auto& factory = entry.second; - const std::string address = gArgs.GetArg(arg, ""); + const auto& factory = entry.second; + for (const std::string& address : gArgs.GetArgs(arg)) { std::unique_ptr notifier = factory(); notifier->SetType(entry.first); notifier->SetAddress(address); diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 0f4444c535085..fd10dce13c871 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -198,7 +198,7 @@ bool CZMQAbstractPublishNotifier::SendZmqMessage(const char *command, const void bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish hashblock %s\n", hash.GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish hashblock %s to %s\n", hash.GetHex(), this->address); char data[32]; for (unsigned int i = 0; i < 32; i++) data[31 - i] = hash.begin()[i]; @@ -218,7 +218,7 @@ bool CZMQPublishHashChainLockNotifier::NotifyChainLock(const CBlockIndex *pindex bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish hashtx %s\n", hash.GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish hashtx %s to %s\n", hash.GetHex(), this->address); char data[32]; for (unsigned int i = 0; i < 32; i++) data[31 - i] = hash.begin()[i]; @@ -279,7 +279,7 @@ bool CZMQPublishHashRecoveredSigNotifier::NotifyRecoveredSig(const std::shared_p bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { - LogPrint(BCLog::ZMQ, "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish rawblock %s to %s\n", pindex->GetBlockHash().GetHex(), this->address); const Consensus::Params& consensusParams = Params().GetConsensus(); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -344,7 +344,7 @@ bool CZMQPublishRawChainLockSigNotifier::NotifyChainLock(const CBlockIndex *pind bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish rawtx %s\n", hash.GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish rawtx %s to %s\n", hash.GetHex(), this->address); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << transaction; return SendZmqMessage(MSG_RAWTX, &(*ss.begin()), ss.size()); @@ -353,7 +353,7 @@ bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &tr bool CZMQPublishRawTransactionLockNotifier::NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) { uint256 hash = transaction->GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish rawtxlock %s\n", hash.GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish rawtxlock %s to %s\n", hash.GetHex(), this->address); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << *transaction; return SendZmqMessage(MSG_RAWTXLOCK, &(*ss.begin()), ss.size()); @@ -362,7 +362,7 @@ bool CZMQPublishRawTransactionLockNotifier::NotifyTransactionLock(const CTransac bool CZMQPublishRawTransactionLockSigNotifier::NotifyTransactionLock(const CTransactionRef& transaction, const std::shared_ptr& islock) { uint256 hash = transaction->GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish rawtxlocksig %s\n", hash.GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish rawtxlocksig %s to %s\n", hash.GetHex(), this->address); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << *transaction; ss << *islock; @@ -372,7 +372,7 @@ bool CZMQPublishRawTransactionLockSigNotifier::NotifyTransactionLock(const CTran bool CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote(const std::shared_ptr& vote) { uint256 nHash = vote->GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish rawgovernanceobject: hash = %s, vote = %d\n", nHash.ToString(), vote->ToString()); + LogPrint(BCLog::ZMQ, "zmq: Publish rawgovernanceobject: hash = %s to %s, vote = %d\n", nHash.ToString(), this->address, vote->ToString()); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << *vote; return SendZmqMessage(MSG_RAWGVOTE, &(*ss.begin()), ss.size()); @@ -381,7 +381,7 @@ bool CZMQPublishRawGovernanceVoteNotifier::NotifyGovernanceVote(const std::share bool CZMQPublishRawGovernanceObjectNotifier::NotifyGovernanceObject(const std::shared_ptr& govobj) { uint256 nHash = govobj->GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish rawgovernanceobject: hash = %s, type = %d\n", nHash.ToString(), ToUnderlying(govobj->GetObjectType())); + LogPrint(BCLog::ZMQ, "zmq: Publish rawgovernanceobject: hash = %s to %s, type = %d\n", nHash.ToString(), this->address, ToUnderlying(govobj->GetObjectType())); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << *govobj; return SendZmqMessage(MSG_RAWGOBJ, &(*ss.begin()), ss.size()); diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 322d516df373c..bf2bcba99187c 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -78,6 +78,7 @@ def setup_nodes(self): def run_test(self): try: self._zmq_test() + self.test_multiple_interfaces() finally: # Destroy the ZMQ context. self.log.debug("Destroying ZMQ context") @@ -131,5 +132,29 @@ def _zmq_test(self): assert_equal(self.nodes[1].getzmqnotifications(), []) + def test_multiple_interfaces(self): + import zmq + # Set up two subscribers with different addresses + subscribers = [] + for i in range(2): + address = 'tcp://127.0.0.1:%d' % (28334 + i) + socket = self.zmq_context.socket(zmq.SUB) + socket.set(zmq.RCVTIMEO, 60000) + hashblock = ZMQSubscriber(socket, b"hashblock") + socket.connect(address) + subscribers.append({'address': address, 'hashblock': hashblock}) + + self.restart_node(0, ['-zmqpub%s=%s' % (subscriber['hashblock'].topic.decode(), subscriber['address']) for subscriber in subscribers]) + + # Relax so that the subscriber is ready before publishing zmq messages + sleep(0.2) + + # Generate 1 block in nodes[0] and receive all notifications + self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE) + + # Should receive the same block hash on both subscribers + assert_equal(self.nodes[0].getbestblockhash(), subscribers[0]['hashblock'].receive().hex()) + assert_equal(self.nodes[0].getbestblockhash(), subscribers[1]['hashblock'].receive().hex()) + if __name__ == '__main__': ZMQTest().main() From a800821e9fcc382509c33e6faf6cb61c293c3535 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 30 May 2020 12:33:34 -0400 Subject: [PATCH 3/4] Merge #18965: tests: implement base58_decode 60ed33904cf974e8f3c1b95392a23db1fe2d4a98 tests: implement base58_decode (10xcryptodev) Pull request description: implements TODO: def base58_decode ACKs for top commit: ryanofsky: Code review ACK 60ed33904cf974e8f3c1b95392a23db1fe2d4a98. Just suggested changes since last review. Thank you for taking suggestions! Tree-SHA512: b3c06b4df041a6d88033cd077a093813a688e42d0b9aa777c715e5fd69cfba7b1bf984428bd98417d3c15232d3d48bc9c163317564f9e1d562db6611c21e2c10 --- test/functional/test_framework/address.py | 48 ++++++++++++++++++++++- test/functional/test_runner.py | 1 + 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index dafbdeb8d886c..96bb1d6d5c98c 100644 --- a/test/functional/test_framework/address.py +++ b/test/functional/test_framework/address.py @@ -8,9 +8,11 @@ # # This file encodes and decodes BASE58 P2PKH and P2SH addresses # +import unittest from .script import hash256, hash160, CScript from .util import hex_str_to_bytes +from test_framework.util import assert_equal # Note unlike in bitcoin, this address isn't bech32 since we don't (at this time) support bech32. ADDRESS_BCRT1_UNSPENDABLE = 'yVg3NBUHNEhgDceqwVUjsZHreC5PBHnUo9' @@ -35,7 +37,32 @@ def byte_to_base58(b, version): str = str[2:] return result -# TODO: def base58_decode + +def base58_to_byte(s, verify_checksum=True): + if not s: + return b'' + n = 0 + for c in s: + n *= 58 + assert c in chars + digit = chars.index(c) + n += digit + h = '%x' % n + if len(h) % 2: + h = '0' + h + res = n.to_bytes((n.bit_length() + 7) // 8, 'big') + pad = 0 + for c in s: + if c == chars[0]: + pad += 1 + else: + break + res = b'\x00' * pad + res + if verify_checksum: + assert_equal(hash256(res[:-4])[:4], res[-4:]) + + return res[1:-4], int(res[0]) + def keyhash_to_p2pkh(hash, main = False): assert len(hash) == 20 @@ -68,3 +95,22 @@ def check_script(script): if (type(script) is bytes or type(script) is CScript): return script assert False + + +class TestFrameworkScript(unittest.TestCase): + def test_base58encodedecode(self): + def check_base58(data, version): + self.assertEqual(base58_to_byte(byte_to_base58(data, version)), (data, version)) + + check_base58(b'\x1f\x8e\xa1p*{\xd4\x94\x1b\xca\tA\xb8R\xc4\xbb\xfe\xdb.\x05', 111) + check_base58(b':\x0b\x05\xf4\xd7\xf6l;\xa7\x00\x9fE50)l\x84\\\xc9\xcf', 111) + check_base58(b'A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) + check_base58(b'\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) + check_base58(b'\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) + check_base58(b'\0\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 111) + check_base58(b'\x1f\x8e\xa1p*{\xd4\x94\x1b\xca\tA\xb8R\xc4\xbb\xfe\xdb.\x05', 0) + check_base58(b':\x0b\x05\xf4\xd7\xf6l;\xa7\x00\x9fE50)l\x84\\\xc9\xcf', 0) + check_base58(b'A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) + check_base58(b'\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) + check_base58(b'\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) + check_base58(b'\0\0\0A\xc1\xea\xf1\x11\x80%Y\xba\xd6\x1b`\xd6+\x1f\x89|c\x92\x8a', 0) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 9046e54cfc284..0de954f59765d 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -68,6 +68,7 @@ TEST_EXIT_SKIPPED = 77 TEST_FRAMEWORK_MODULES = [ + "address", "blocktools", "muhash", "script", From 3f77d2312fb4f96089eedfe8be2584fdd711636e Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 16 Jul 2020 21:33:13 +0200 Subject: [PATCH 4/4] Merge #16525: Dump transaction version as an unsigned integer in RPC/TxToUniv e80259f1976545e4f1ab6a420644be0c32261773 Additionally treat Tx.nVersion as unsigned in joinpsbts (Matt Corallo) 970de70bdd3542e75b73c79b06f143168c361494 Dump transaction version as an unsigned integer in RPC/TxToUniv (Matt Corallo) Pull request description: Consensus-wise we already treat it as an unsigned integer (the only rules around it are in CSV/locktime handling), but changing the underlying data type means touching consensus code for a simple cleanup change, which isn't really worth it. See-also, https://github.com/rust-bitcoin/rust-bitcoin/pull/299 ACKs for top commit: sipa: ACK e80259f1976545e4f1ab6a420644be0c32261773 practicalswift: ACK e80259f1976545e4f1ab6a420644be0c32261773 ajtowns: ACK e80259f1976545e4f1ab6a420644be0c32261773 code review -- checked all other uses of tx.nVersion treat it as unsigned (except for policy.cpp:IsStandard anyway), so looks good. naumenkogs: ACK e80259f Tree-SHA512: 6760a2c77e24e9e1f79a336ca925f9bbca3a827ce02003c71d7f214b82ed3dea13fa7d9f87df9b9445cd58dff8b44a15571d821c876f22f8e5a372a014c9976b --- doc/release-notes-16525.md | 9 +++++++++ src/core_write.cpp | 4 +++- src/rpc/rawtransaction.cpp | 8 ++++---- test/functional/rpc_rawtransaction.py | 3 ++- 4 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 doc/release-notes-16525.md diff --git a/doc/release-notes-16525.md b/doc/release-notes-16525.md new file mode 100644 index 0000000000000..88e4175b3ae8c --- /dev/null +++ b/doc/release-notes-16525.md @@ -0,0 +1,9 @@ +RPC changes +----------- + +Exposed transaction version numbers are now treated as unsigned 16-bit integers +instead of signed 16-bit integers. This matches their treatment in consensus +logic. Versions greater than 3 continue to be non-standard (matching previous +behavior of smaller than 1 or greater than 3 being non-standard). Note that +this includes the joinpsbt command, which combines partially-signed +transactions by selecting the highest version number. diff --git a/src/core_write.cpp b/src/core_write.cpp index 5e69d2d890469..f78578246c24f 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -190,7 +190,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, { uint256 txid = tx.GetHash(); entry.pushKV("txid", txid.GetHex()); - entry.pushKV("version", tx.nVersion); + // Transaction version is actually unsigned in consensus checks, just signed in memory, + // so cast to unsigned before giving it to the user. + entry.pushKV("version", static_cast(static_cast(tx.nVersion))); entry.pushKV("type", tx.nType); entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION)); entry.pushKV("locktime", (int64_t)tx.nLockTime); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 9e942a022e782..ea81ace82fe44 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1604,7 +1604,7 @@ UniValue joinpsbts(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "At least two PSBTs are required to join PSBTs."); } - int32_t best_version = 1; + uint16_t best_version = 1; uint32_t best_locktime = 0xffffffff; for (unsigned int i = 0; i < txs.size(); ++i) { PartiallySignedTransaction psbtx; @@ -1614,8 +1614,8 @@ UniValue joinpsbts(const JSONRPCRequest& request) } psbtxs.push_back(psbtx); // Choose the highest version number - if (psbtx.tx->nVersion > best_version) { - best_version = psbtx.tx->nVersion; + if (static_cast(psbtx.tx->nVersion) > best_version) { + best_version = static_cast(psbtx.tx->nVersion); } // Choose the lowest lock time if (psbtx.tx->nLockTime < best_locktime) { @@ -1626,7 +1626,7 @@ UniValue joinpsbts(const JSONRPCRequest& request) // Create a blank psbt where everything will be added PartiallySignedTransaction merged_psbt; merged_psbt.tx = CMutableTransaction(); - merged_psbt.tx->nVersion = best_version; + merged_psbt.tx->nVersion = static_cast(best_version); merged_psbt.tx->nLockTime = best_locktime; // Merge diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 044d6d2a03522..0d054812f0cdd 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -359,11 +359,12 @@ def run_test(self): # Note, this is different to bitcoin. Bitcoin has a 32 bit integer # representing the version, we have 16 bits of version and 16 bits of # type. + # As transaction version is unsigned, this should convert to its unsigned equivalent. tx = CTransaction() tx.nVersion = -0x8000 rawtx = ToHex(tx) decrawtx = self.nodes[0].decoderawtransaction(rawtx) - assert_equal(decrawtx['version'], -0x8000) + assert_equal(decrawtx['version'], 0x8000) # Test the maximum transaction version number that fits in a signed 32-bit integer. tx = CTransaction()