From 335b53bc56287a3c84436888cd63dd347cfbe162 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 24 Jul 2017 12:56:56 +0200 Subject: [PATCH 01/20] Merge #9622: [rpc] listsinceblock should include lost transactions when parameter is a reorg'd block Summary: 876e92b Testing: listsinceblock should display all transactions that were affected since the given block, including transactions that were removed due to a reorg. (Karl-Johan Alm) f999c46 listsinceblock: optionally find and list any transactions that were undone due to reorg when requesting a non-main chain block in a new 'removed' array. (Karl-Johan Alm) Pull request description: The following scenario will not notify the caller of the fact `tx0` has been dropped: 1. User 1 receives BTC in tx0 from utxo1 in block aa1. 2. User 2 receives BTC in tx1 from utxo1 (same) in block bb1 3. User 1 sees 2 confirmations at block aa3. 4. Reorg into bb chain. 5. User 1 asks `listsinceblock aa3` and does not see that tx0 is now invalidated. See `listsinceblock.py` commit for related test. The proposed fix is to iterate from the given block down to the fork point, and to check each transaction in the blocks against the wallet, in addition to including all transactions from the fork point to the active chain tip (the current behavior). Any transactions that were present will now also be listed in the `listsinceblock` output in a new `replaced` array. This operation may be a bit heavy but the circumstances (and perceived frequency of occurrence) warrant it, I believe. Example output: ```Python { 'transactions': [], 'replaced': [ { 'walletconflicts': [], 'vout': 1, 'account': '', 'timereceived': 1485234857, 'time': 1485234857, 'amount': '1.00000000', 'bip125-replaceable': 'unknown', 'trusted': False, 'category': 'receive', 'txid': 'ce673859a30dee1d2ebdb3c05f2eea7b1da54baf68f93bb8bfe37c5f09ed22ff', 'address': 'miqEt4kWp9zSizwGGuUWLAmxEcTW9bFUnQ', 'label': '', 'confirmations': -7 } ], 'lastblock': '7a388f27d09e3699102a4ebf81597d974fc4c72093eeaa02adffbbf7527f6715' } ``` I believe this addresses the comment by @luke-jr in https://github.com/bitcoin/bitcoin/pull/9516#issuecomment-274190081 but I could be wrong.. Tree-SHA512: 607b5dcaeccb9dc0d963d3de138c40490f3e923050b29821e6bd513d26beb587bddc748fbb194503fe618cfe34a6ed65d95e8d9c5764a882b6c5f976520cff35 Backport of Core PR 9622 https://github.com/bitcoin/bitcoin/pull/9622/files Completes T551 Test Plan: make check test_runner.py wallet_listsinceblock Reviewers: deadalnix, Fabien, #bitcoin_abc Reviewed By: Fabien, #bitcoin_abc Subscribers: teamcity, schancel Differential Revision: https://reviews.bitcoinabc.org/D2689 --- doc/release-notes.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index ff2f24c09..a508d9a14 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -26,5 +26,4 @@ Bitcoin-ABC 19.x backports: - Minor bug fixes and wallet UI cleanup - Removed `txconfirmtarget` option from bitcoind - Added parameter `include_removed` to `listsinceblock` for better tracking of transactions during a reorg. See `bitcoin-cli help listsinceblock` for more details. - - `listsinceblock` will now throw an error if an unknown `blockhash` argument value is passed, instead of returning a list of all wallet transactions since - the genesis block. + - `listsinceblock` will now throw an error if an unknown `blockhash` argument value is passed, instead of returning a list of all wallet transactions since the genesis block. From 52c055764598595e574bd0cca09173a493037ea9 Mon Sep 17 00:00:00 2001 From: Florian Date: Fri, 1 Mar 2019 00:38:43 +0000 Subject: [PATCH 02/20] Fix unlocked_until in getwalletinfo rpc Summary: Getwalletinfo returned an uninitialized value for unlocked_until before the first walletpassphrase call, even though the wallet was locked and it should return 0. Test Plan: make check ./wallet_encryption.py Reviewers: O1 Bitcoin ABC, #bitcoin_abc, deadalnix, Fabien Reviewed By: O1 Bitcoin ABC, #bitcoin_abc, deadalnix, Fabien Subscribers: teamcity, schancel Differential Revision: https://reviews.bitcoinabc.org/D2633 --- src/wallet/wallet.h | 1 + test/functional/wallet_encryption.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0246ba5a5..c3c23d276 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -764,6 +764,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface { fBroadcastTransactions = false; fAbortRescan = false; fScanningWallet = false; + nRelockTime = 0; } std::map mapWallet; diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index 692c525df..a44b94952 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -14,6 +14,7 @@ class WalletEncryptionTest(BitcoinTestFramework): + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 @@ -32,8 +33,12 @@ def run_test(self): self.nodes[0].node_encrypt_wallet(passphrase) self.start_node(0) + # Check the encrypted wallet is marked as locked on initialization + assert_equal(self.nodes[0].getwalletinfo()['unlocked_until'], 0) + # Test that the wallet is encrypted - assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", + assert_raises_rpc_error( + -13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) # Check that walletpassphrase works @@ -42,19 +47,25 @@ def run_test(self): # Check that the timeout is right time.sleep(2) - assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", + assert_raises_rpc_error( + -13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) # Test wrong passphrase assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase + "wrong", 10) - # Test walletlock + # Test walletlock and unlocked_until values + self.nodes[0].setmocktime(1) self.nodes[0].walletpassphrase(passphrase, 84600) assert_equal(privkey, self.nodes[0].dumpprivkey(address)) + assert_equal( + self.nodes[0].getwalletinfo()['unlocked_until'], 1 + 84600) self.nodes[0].walletlock() - assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", + assert_raises_rpc_error( + -13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) + assert_equal(self.nodes[0].getwalletinfo()['unlocked_until'], 0) # Test passphrase changes self.nodes[0].walletpassphrasechange(passphrase, passphrase2) From 213c01d985214be2e846a13cf7ab44393726c909 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 27 Mar 2019 23:02:06 +0000 Subject: [PATCH 03/20] Remove nonnull warning when calling secp256k1_schnorr_sign with NULL noncefp Summary: This warning was hidden under normal conditions because SECP256K1_ARG_NONNULL is bypassed when SECP256K1_BUILD is set. A NULL noncefp means the default nonce function is used. Test Plan: make check Reviewers: O1 Bitcoin ABC, #bitcoin_abc, deadalnix Reviewed By: O1 Bitcoin ABC, #bitcoin_abc, deadalnix Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2747 --- src/secp256k1/include/secp256k1_schnorr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/secp256k1/include/secp256k1_schnorr.h b/src/secp256k1/include/secp256k1_schnorr.h index afbae8604..60137fc32 100644 --- a/src/secp256k1/include/secp256k1_schnorr.h +++ b/src/secp256k1/include/secp256k1_schnorr.h @@ -48,7 +48,7 @@ SECP256K1_API int secp256k1_schnorr_sign( const unsigned char *seckey, secp256k1_nonce_function noncefp, const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); # ifdef __cplusplus } From 72ca22262d9e3a519b6b425ad4fd156dde8ed2fe Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 27 Mar 2019 16:05:57 -0700 Subject: [PATCH 04/20] [Part 2 of 5] Add a CChainState class to clarify internal interfaces Summary: Move block writing out of AcceptBlock Backport of Core PR 10279 commit e104f0f https://github.com/bitcoin/bitcoin/pull/10279/commits/e104f0fb7e464f8cadb4cbc99e8329d22c35c36a Depends on D1968 Progress towards T572 Test Plan: make check test_runner.py Reviewers: #bitcoin_abc, schancel, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: jasonbcox, teamcity Differential Revision: https://reviews.bitcoinabc.org/D1969 --- src/validation.cpp | 74 ++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 78b07b9a6..8c1f1613f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3278,9 +3278,9 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState &state, return true; } -static bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, - unsigned int nAddSize, unsigned int nHeight, - uint64_t nTime, bool fKnown = false) { +static bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, + unsigned int nHeight, uint64_t nTime, + bool fKnown = false) { LOCK(cs_LastBlockFile); unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile; @@ -3339,7 +3339,7 @@ static bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, fclose(file); } } else { - return state.Error("out of disk space"); + return error("out of disk space"); } } } @@ -3789,6 +3789,33 @@ bool ProcessNewBlockHeaders(const Config &config, return true; } +/** + * Store block on disk. If dbp is non-nullptr, the file is known to already + * reside on disk. + */ +static CDiskBlockPos SaveBlockToDisk(const CBlock &block, int nHeight, + const CChainParams &chainparams, + const CDiskBlockPos *dbp) { + unsigned int nBlockSize = + ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + if (dbp != nullptr) { + blockPos = *dbp; + } + if (!FindBlockPos(blockPos, nBlockSize + 8, nHeight, block.GetBlockTime(), + dbp != nullptr)) { + error("%s: FindBlockPos failed", __func__); + return CDiskBlockPos(); + } + if (dbp == nullptr) { + if (!WriteBlockToDisk(block, blockPos, chainparams.DiskMagic())) { + AbortNode("Failed to write block"); + return CDiskBlockPos(); + } + } + return blockPos; +} + /** * Store a block on disk. * @@ -3927,29 +3954,18 @@ static bool AcceptBlock(const Config &config, GetMainSignals().NewPoWValidBlock(pindex, pblock); } - int nHeight = pindex->nHeight; const CChainParams &chainparams = config.GetChainParams(); // Write block to history file try { - unsigned int nBlockSize = - ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); - CDiskBlockPos blockPos; - if (dbp != nullptr) { - blockPos = *dbp; - } - - if (!FindBlockPos(state, blockPos, nBlockSize + 8, nHeight, - block.GetBlockTime(), dbp != nullptr)) { - return error("AcceptBlock(): FindBlockPos failed"); - } - - if (dbp == nullptr) { - if (!WriteBlockToDisk(block, blockPos, chainparams.DiskMagic())) { - AbortNode(state, "Failed to write block"); - } + CDiskBlockPos blockPos = + SaveBlockToDisk(block, pindex->nHeight, chainparams, dbp); + if (blockPos.IsNull()) { + state.Error(strprintf( + "%s: Failed to find position to write new block to disk", + __func__)); + return false; } - if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) { return error("AcceptBlock(): ReceivedBlockTransactions failed"); } @@ -4870,19 +4886,13 @@ bool LoadGenesisBlock(const CChainParams &chainparams) { // one already on disk) try { CBlock &block = const_cast(chainparams.GenesisBlock()); - // Start new block file - unsigned int nBlockSize = - ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); - CDiskBlockPos blockPos; - CValidationState state; - if (!FindBlockPos(state, blockPos, nBlockSize + 8, 0, - block.GetBlockTime())) { - return error("%s: FindBlockPos failed", __func__); - } - if (!WriteBlockToDisk(block, blockPos, chainparams.DiskMagic())) { + CDiskBlockPos blockPos = + SaveBlockToDisk(block, 0, chainparams, nullptr); + if (blockPos.IsNull()) { return error("%s: writing genesis block to disk failed", __func__); } CBlockIndex *pindex = AddToBlockIndex(block); + CValidationState state; if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) { return error("%s: genesis block not accepted", __func__); } From b43bcd219de07fc413bf3741eafa49f09310a827 Mon Sep 17 00:00:00 2001 From: sken Date: Thu, 28 Mar 2019 13:33:21 -0500 Subject: [PATCH 05/20] [secp256k1] add schnorr verify jni binding Summary: schnorr jni binding that will allow jvm support Test Plan: use the test vector data from https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr/test-vectors.csv Reviewers: O1 Bitcoin ABC, #bitcoin_abc, deadalnix, jasonbcox Reviewed By: O1 Bitcoin ABC, #bitcoin_abc, jasonbcox Subscribers: jasonbcox, schancel Differential Revision: https://reviews.bitcoinabc.org/D2745 --- .../src/java/org/bitcoin/NativeSecp256k1.java | 32 ++++ .../java/org/bitcoin/NativeSecp256k1Test.java | 153 ++++++++++++++++++ .../src/java/org_bitcoin_NativeSecp256k1.c | 23 ++- .../src/java/org_bitcoin_NativeSecp256k1.h | 8 + 4 files changed, 215 insertions(+), 1 deletion(-) diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java index c678480e8..c159da36e 100644 --- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java @@ -414,6 +414,36 @@ public static synchronized boolean randomize(byte[] seed) throws AssertFailExcep } } + /** + * Verifies the given Schnorr signature in native code. + * Calling when enabled == false is undefined (probably library not loaded) + * + * @param data The data which was signed, must be exactly 32 bytes + * @param signature The signature is exactly 64 bytes + * @param pub The public key which did the signing which is the same ECDSA + */ + public static boolean schnorrVerify(byte[] data, byte[] signature, byte[] pub) { + checkArgument(data.length == 32 && signature.length == 64 && (pub.length == 33 || pub.length == 65)); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + 64 + pub.length) { + byteBuff = ByteBuffer.allocateDirect(32 + 64 + pub.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(signature); + byteBuff.put(pub); + + r.lock(); + try { + return secp256k1_schnorr_verify(byteBuff, Secp256k1Context.getContext(), pub.length) == 1; + } finally { + r.unlock(); + } + } + private static native long secp256k1_ctx_clone(long context); private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); @@ -438,6 +468,8 @@ public static synchronized boolean randomize(byte[] seed) throws AssertFailExcep private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + private static native int secp256k1_schnorr_verify(ByteBuffer byteBuff, long context, int pubLen); + private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen); } diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java index 9fc0360dd..e928afa68 100644 --- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java +++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -164,6 +164,156 @@ public static void testRandomize() throws AssertFailException { assertEquals( result, true, "testRandomize"); } + private static class SchnorrTestVector { + String data; + String sig; + String pubKey; + boolean expected; + String comment; + + SchnorrTestVector(String d, String s, String p, boolean e, String c) { + data = d; + sig = s; + pubKey = p; + expected = e; + comment = c; + } + } + + /** + * This tests schnorrVerify() for a valid signature + * It tests the following test vectors + * https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr/test-vectors.csv + */ + public static void testSchnorrVerify() throws AssertFailException{ + SchnorrTestVector[] tests = new SchnorrTestVector[]{ + new SchnorrTestVector( + "0000000000000000000000000000000000000000000000000000000000000000", + "787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF67031A98831859DC34DFFEEDDA86831842CCD0079E1F92AF177F7F22CC1DCED05", + "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + true, + "success" + ), + new SchnorrTestVector( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + true, + "success" + ), + new SchnorrTestVector( + "5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", + "00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE00880371D01766935B92D2AB4CD5C8A2A5837EC57FED7660773A05F0DE142380", + "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", + true, + "success" + ), + new SchnorrTestVector( + "4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703", + "00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6302A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D", + "03DEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34", + true, + "success" + ), + new SchnorrTestVector( + "0000000000000000000000000000000000000000000000000000000000000000", + "52818579ACA59767E3291D91B76B637BEF062083284992F2D95F564CA6CB4E3530B1DA849C8E8304ADC0CFE870660334B3CFC18E825EF1DB34CFAE3DFC5D8187", + "031B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F", + true, + "success" + ), + new SchnorrTestVector( + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "570DD4CA83D4E6317B8EE6BAE83467A1BF419D0767122DE409394414B05080DCE9EE5F237CBD108EABAE1E37759AE47F8E4203DA3532EB28DB860F33D62D49BD", + "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", + true, + "success" + ), + new SchnorrTestVector( + "4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703", + "00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6302A8DC32E64E86A333F20EF56EAC9BA30B7246D6D25E22ADB8C6BE1AEB08D49D", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + false, + "public key not on the curve" + ), + new SchnorrTestVector( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1DFA16AEE06609280A19B67A24E1977E4697712B5FD2943914ECD5F730901B4AB7", + "03EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34", + false, + "incorrect R residuosity" + ), + new SchnorrTestVector( + "5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", + "00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BED092F9D860F1776A1F7412AD8A1EB50DACCC222BC8C0E26B2056DF2F273EFDEC", + "03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B", + false, + "negated message hash" + ), + new SchnorrTestVector( + "0000000000000000000000000000000000000000000000000000000000000000", + "787A848E71043D280C50470E8E1532B2DD5D20EE912A45DBDD2BD1DFBF187EF68FCE5677CE7A623CB20011225797CE7A8DE1DC6CCD4F754A47DA6C600E59543C", + "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + false, + "negated s value" + ), + new SchnorrTestVector( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + "03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + false, + "negated public key" + ), + new SchnorrTestVector( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "00000000000000000000000000000000000000000000000000000000000000009E9D01AF988B5CEDCE47221BFA9B222721F3FA408915444A4B489021DB55775F", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + false, + "sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 0" + ), + new SchnorrTestVector( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "0000000000000000000000000000000000000000000000000000000000000001D37DDF0254351836D84B1BD6A795FD5D523048F298C4214D187FE4892947F728", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + false, + "sG - eP is infinite. Test fails in single verification if jacobi(y(inf)) is defined as 1 and x(inf) as 1" + ), + new SchnorrTestVector( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + false, + "sig[0:32] is not an X coordinate on the curve" + ), + new SchnorrTestVector( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2F1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + false, + "sig[0:32] is equal to field size" + ), + new SchnorrTestVector( + "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", + "2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + "02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", + false, + "sig[32:64] is equal to curve order" + ) + }; + int i = 0; + for(SchnorrTestVector test : tests) { + boolean expected = test.expected; + byte[] data = DatatypeConverter.parseHexBinary(test.data); + byte[] sig = DatatypeConverter.parseHexBinary(test.sig); + byte[] pub = DatatypeConverter.parseHexBinary(test.pubKey); + boolean result = NativeSecp256k1.schnorrVerify(data, sig, pub); + + String testMsg = String.join(" ", "testSchnorrVerify", String.valueOf(i++), String.valueOf(expected), test.comment); + + assertEquals(result, expected, testMsg); + } + } + public static void testCreateECDHSecret() throws AssertFailException{ byte[] sec = DatatypeConverter.parseHexBinary("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530"); @@ -212,6 +362,9 @@ public static void main(String[] args) throws AssertFailException{ //Test randomize() testRandomize(); + //Test verifySchnorr() success/fail + testSchnorrVerify(); + //Test ECDH testCreateECDHSecret(); diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c index bcef7b32c..a87a6ee73 100644 --- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -5,7 +5,7 @@ #include "include/secp256k1.h" #include "include/secp256k1_ecdh.h" #include "include/secp256k1_recovery.h" - +#include "include/secp256k1_schnorr.h" SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone (JNIEnv* env, jclass classObject, jlong ctx_l) @@ -332,6 +332,27 @@ SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1p return 0; } +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* sigdata = { (unsigned char*) (data + 32) }; + const unsigned char* pubdata = { (unsigned char*) (data + 32 + 64) }; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if( ret ) { + ret = secp256k1_schnorr_verify(ctx, sigdata, data, &pubkey); + } + + (void)classObject; + + return ret; +} + SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) { diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h index fe613c9e9..7ca6e0288 100644 --- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h @@ -104,6 +104,14 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse (JNIEnv *, jclass, jobject, jlong, jint); +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_schnorr_verify + * Signature: (Ljava/nio/ByteBuffer;JI)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1verify + (JNIEnv *, jclass, jobject, jlong, jint); + /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdh From 786177c3ec791ea25d57299ae0f112b4284d1160 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 28 Sep 2017 13:46:00 +0200 Subject: [PATCH 06/20] Merge #10858: [RPC] Add "warnings" field to getblockchaininfo and unify "warnings" field in get*info RPCs Summary: 395cef7 Change getmininginfo errors field to warnings (Andrew Chow) 8502b20 Unify help text for GetWarnings output in get*info RPCs (Andrew Chow) f77f0e4 Add warnings field to getblockchaininfo (Andrew Chow) Pull request description: The `getblockchaininfo` output does not contain the `warnings` field which the `getinfo`, `getmininginfo`, and `getnetworkinfo` RPCs have. It should have it as the errors pertain to the blockchain. This PR adds that field. This PR also unifies the help text for the `warnings` field and its output position so that all of the `get*info` commands are consistent. `getnetworkinfo`'s `errors` field is named `warnings`. I did not change this even though it is inconsistent since this naming has been in use for a long time. Tree-SHA512: 385ab6acfee67fc8816f4d51ab2bd7a623264c7973906dfbab0a171f199e9db16fde19093a5bc3dfbdd4ff5f19d2186b646eb6b3bae0a4d7c9add43650a4a9d9 Backport of PR10858 https://github.com/bitcoin/bitcoin/commit/9a8e9167f2636fdc2fc047dfed1747920b0f047f?diff=unified#diff-a0c8f511d90e83aa9b5857e819ced344R1165 Completes T567 Test Plan: make check test_runner.py getblockchaininfo should also produce a "warnings" field getmininginfo should have a "warnings" field in place of its "errors" field during regular use getmininginfo should behave as previously (i.e. have an "errors" field) when running bitcoind -deprecatedrpc=getmininginfo Reviewers: deadalnix, jasonbcox, Fabien, O1 Bitcoin ABC, #bitcoin_abc Reviewed By: jasonbcox, Fabien, O1 Bitcoin ABC, #bitcoin_abc Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2730 --- doc/release-notes.md | 6 +++++- src/rpc/blockchain.cpp | 2 ++ src/rpc/mining.cpp | 12 ++++++++++-- src/rpc/net.cpp | 4 ++-- test/functional/rpc_blockchain.py | 1 + 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index a508d9a14..b58eb4c61 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -26,4 +26,8 @@ Bitcoin-ABC 19.x backports: - Minor bug fixes and wallet UI cleanup - Removed `txconfirmtarget` option from bitcoind - Added parameter `include_removed` to `listsinceblock` for better tracking of transactions during a reorg. See `bitcoin-cli help listsinceblock` for more details. - - `listsinceblock` will now throw an error if an unknown `blockhash` argument value is passed, instead of returning a list of all wallet transactions since the genesis block. + - `listsinceblock` will now throw an error if an unknown `blockhash` argument value is passed, instead of returning a list of all wallet transactions since + the genesis block. + - Various minor fixes to RPC parameter validation + - Minor wallet performance improvements + - `errors` in getmininginfo rpc commmand has been deprecated. Use `warnings` now instead. diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index a2356be6e..1a8d5d957 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -24,6 +24,7 @@ #include "util.h" #include "utilstrencodings.h" #include "validation.h" +#include "warnings.h" #include // boost::thread::interrupt @@ -1280,6 +1281,7 @@ UniValue getblockchaininfo(const Config &config, obj.pushKV("pruneheight", block->nHeight); } + obj.pushKV("warnings", GetWarnings("statusbar")); return obj; } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 56153322a..85788bddf 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -234,12 +234,16 @@ static UniValue getmininginfo(const Config &config, " \"currentblocktx\": nnn, (numeric) The last block " "transaction\n" " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" - " \"errors\": \"...\" (string) Current errors\n" " \"networkhashps\": nnn, (numeric) The network hashes per " "second\n" " \"pooledtx\": n (numeric) The size of the mempool\n" " \"chain\": \"xxxx\", (string) current network name as " "defined in BIP70 (main, test, regtest)\n" + " \"warnings\": \"...\" (string) any network and " + "blockchain warnings\n" + " \"errors\": \"...\" (string) DEPRECATED. Same as " + "warnings. Only shown when bitcoind is started with " + "-deprecatedrpc=getmininginfo\n" "}\n" "\nExamples:\n" + HelpExampleCli("getmininginfo", "") + @@ -256,10 +260,14 @@ static UniValue getmininginfo(const Config &config, obj.pushKV("blockprioritypercentage", uint8_t(gArgs.GetArg("-blockprioritypercentage", DEFAULT_BLOCK_PRIORITY_PERCENTAGE))); - obj.pushKV("errors", GetWarnings("statusbar")); obj.pushKV("networkhashps", getnetworkhashps(config, request)); obj.pushKV("pooledtx", uint64_t(g_mempool.size())); obj.pushKV("chain", config.GetChainParams().NetworkIDString()); + if (IsDeprecatedRPCEnabled(gArgs, "getmininginfo")) { + obj.pushKV("errors", GetWarnings("statusbar")); + } else { + obj.pushKV("warnings", GetWarnings("statusbar")); + } return obj; } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index d8b09ed37..f4d6cb81b 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -563,8 +563,8 @@ static UniValue getnetworkinfo(const Config &config, " }\n" " ,...\n" " ]\n" - " \"warnings\": \"...\" " - "(string) any network warnings\n" + " \"warnings\": \"...\" (string) any network " + "and blockchain warnings\n" "}\n" "\nExamples:\n" + HelpExampleCli("getnetworkinfo", "") + diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 4e00ec1bf..4b3756f40 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -63,6 +63,7 @@ def _test_getblockchaininfo(self): 'pruned', 'softforks', 'verificationprogress', + 'warnings', ] res = self.nodes[0].getblockchaininfo() # result should have pruneheight and default keys if pruning is enabled From c3099395e0ba61c0d3bb74b010446c6f2ecf02ef Mon Sep 17 00:00:00 2001 From: Pierre Rochard Date: Sun, 17 Dec 2017 11:01:23 -0500 Subject: [PATCH 07/20] remove unused fnoncriticalerrors variable from cwalletdb::findwallettx Summary: remove unused fnoncriticalerrors variable from cwalletdb::findwallettx Backport of Core PR11923 https://github.com/bitcoin/bitcoin/pull/11923/files Completes T570 Test Plan: make check test_runner.py bitcoin-qt Reviewers: Fabien, jasonbcox, deadalnix, O1 Bitcoin ABC, #bitcoin_abc Reviewed By: deadalnix, O1 Bitcoin ABC, #bitcoin_abc Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2742 --- src/wallet/walletdb.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index a66788510..5437b25bf 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -666,7 +666,6 @@ DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { DBErrors CWalletDB::FindWalletTx(std::vector &txIds, std::vector &vWtx) { - bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; try { @@ -718,10 +717,6 @@ DBErrors CWalletDB::FindWalletTx(std::vector &txIds, result = DB_CORRUPT; } - if (fNoncriticalErrors && result == DB_LOAD_OK) { - result = DB_NONCRITICAL_ERROR; - } - return result; } From 3ae078c57683e6333fa5c4df51ee53828c461b2b Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 30 Mar 2019 10:12:54 -0700 Subject: [PATCH 08/20] [Part 3 of 5] Add a CChainState class to clarify internal interfaces Summary: Make DisconnectBlock unaware of where undo data resides on disk Backport of core PR 10279 Commit 93a34cf. Depends on D1969 Test Plan: make VERBOSE=1 check && ./test/functional/test_runner.py Reviewers: #bitcoin_abc, O1 Bitcoin ABC, jasonbcox Reviewed By: #bitcoin_abc, O1 Bitcoin ABC, jasonbcox Subscribers: teamcity Differential Revision: https://reviews.bitcoinabc.org/D1970 --- src/validation.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 8c1f1613f..f98212b3d 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1301,8 +1301,12 @@ bool UndoWriteToDisk(const CBlockUndo &blockundo, CDiskBlockPos &pos, return true; } -bool UndoReadFromDisk(CBlockUndo &blockundo, const CDiskBlockPos &pos, - const uint256 &hashBlock) { +static bool UndoReadFromDisk(CBlockUndo &blockundo, const CBlockIndex *pindex) { + CDiskBlockPos pos = pindex->GetUndoPos(); + if (pos.IsNull()) { + return error("%s: no undo data available", __func__); + } + // Open history file to read CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); if (filein.IsNull()) { @@ -1314,7 +1318,7 @@ bool UndoReadFromDisk(CBlockUndo &blockundo, const CDiskBlockPos &pos, // We need a CHashVerifier as reserializing may lose data CHashVerifier verifier(&filein); try { - verifier << hashBlock; + verifier << pindex->pprev->GetBlockHash(); verifier >> blockundo; filein >> hashChecksum; } catch (const std::exception &e) { @@ -1396,13 +1400,7 @@ static DisconnectResult DisconnectBlock(const CBlock &block, const CBlockIndex *pindex, CCoinsViewCache &view) { CBlockUndo blockUndo; - CDiskBlockPos pos = pindex->GetUndoPos(); - if (pos.IsNull()) { - error("DisconnectBlock(): no undo data available"); - return DISCONNECT_FAILED; - } - - if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) { + if (!UndoReadFromDisk(blockUndo, pindex)) { error("DisconnectBlock(): failure reading undo data"); return DISCONNECT_FAILED; } @@ -4551,10 +4549,8 @@ bool CVerifyDB::VerifyDB(const Config &config, CCoinsView *coinsview, // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { CBlockUndo undo; - CDiskBlockPos pos = pindex->GetUndoPos(); - if (!pos.IsNull()) { - if (!UndoReadFromDisk(undo, pos, - pindex->pprev->GetBlockHash())) { + if (!pindex->GetUndoPos().IsNull()) { + if (!UndoReadFromDisk(undo, pindex)) { return error( "VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); From 842f968ceedf770d27248314337b552084e0c948 Mon Sep 17 00:00:00 2001 From: Florian Date: Tue, 26 Mar 2019 20:27:39 +0000 Subject: [PATCH 09/20] Fix comment about s in schnorr sigs Summary: s/order/n/ for consistency. Test Plan: None Reviewers: markblundeberg, O1 Bitcoin ABC, #bitcoin_abc, deadalnix, Fabien, jasonbcox Reviewed By: O1 Bitcoin ABC, #bitcoin_abc, deadalnix, Fabien, jasonbcox Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2741 --- src/secp256k1/src/modules/schnorr/schnorr_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/secp256k1/src/modules/schnorr/schnorr_impl.h b/src/secp256k1/src/modules/schnorr/schnorr_impl.h index 5577f9fdd..5e609e517 100644 --- a/src/secp256k1/src/modules/schnorr/schnorr_impl.h +++ b/src/secp256k1/src/modules/schnorr/schnorr_impl.h @@ -37,7 +37,7 @@ * public key point P, * signature: (32-byte r, scalar s) * - * Signature is invalid if s >= order or r >= p. + * Signature is invalid if s >= n or r >= p. * Compute scalar e = Hash(r || compressed(P) || m) mod n. * Option 1 (faster for single verification): * Compute point R = s * G - e * P. From 601ef7d9a1557b54d3bd4b6b4920690dacc3e223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20S=C3=A9chet?= Date: Sat, 30 Mar 2019 18:55:48 +0100 Subject: [PATCH 10/20] Lint everything Summary: As per title Test Plan: make check ./test/functional/test_runner.py Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2758 --- test/functional/rpc_blockchain.py | 3 ++- test/functional/wallet_encryption.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 4b3756f40..a33a5034b 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -107,7 +107,7 @@ def _test_getchaintxstats(self): assert_raises_rpc_error( -8, "Invalid block count: should be between 0 and the block's height - 1", - self.nodes[0].getchaintxstats, 201) + self.nodes[0].getchaintxstats, 201) def _test_gettxoutsetinfo(self): node = self.nodes[0] @@ -240,5 +240,6 @@ def _test_getblock(self): assert_equal( getblockinfo['nextblockhash'], getblockheaderinfo['nextblockhash']) + if __name__ == '__main__': BlockchainTest().main() diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index a44b94952..94332e5b2 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -39,7 +39,7 @@ def run_test(self): # Test that the wallet is encrypted assert_raises_rpc_error( -13, "Please enter the wallet passphrase with walletpassphrase first", - self.nodes[0].dumpprivkey, address) + self.nodes[0].dumpprivkey, address) # Check that walletpassphrase works self.nodes[0].walletpassphrase(passphrase, 2) @@ -49,7 +49,7 @@ def run_test(self): time.sleep(2) assert_raises_rpc_error( -13, "Please enter the wallet passphrase with walletpassphrase first", - self.nodes[0].dumpprivkey, address) + self.nodes[0].dumpprivkey, address) # Test wrong passphrase assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", @@ -64,7 +64,7 @@ def run_test(self): self.nodes[0].walletlock() assert_raises_rpc_error( -13, "Please enter the wallet passphrase with walletpassphrase first", - self.nodes[0].dumpprivkey, address) + self.nodes[0].dumpprivkey, address) assert_equal(self.nodes[0].getwalletinfo()['unlocked_until'], 0) # Test passphrase changes From cbc0d5b5ec1d887745ea17a2c127ee3b8b767c73 Mon Sep 17 00:00:00 2001 From: "Jason B. Cox" Date: Tue, 2 Apr 2019 11:41:12 -0700 Subject: [PATCH 11/20] Backport remaining changes from Core PR 10742 Summary: Partial backport of Core PR 10742 https://github.com/bitcoin/bitcoin/pull/10742/files Completes T549 Test Plan: make check test_runner.py Reviewers: #bitcoin_abc, deadalnix, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: teamcity, schancel Differential Revision: https://reviews.bitcoinabc.org/D2719 --- src/test/data/tx_invalid.json | 4 +-- src/wallet/rpcdump.cpp | 2 +- src/wallet/test/accounting_tests.cpp | 2 +- src/wallet/test/walletdb_tests.cpp | 2 +- src/wallet/wallet.cpp | 40 +++++++++++++------------- src/wallet/walletdb.cpp | 42 ++++++++++++++-------------- src/wallet/walletdb.h | 14 +++++----- 7 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index 310171d93..edbc8df81 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -258,7 +258,7 @@ ["where the pubkey is obtained through key recovery with sig and the wrong sighash."], ["This is to show that FindAndDelete is applied only to non-segwit scripts"], ["To show that the tests are 'correctly wrong', they should pass by modifying OP_CHECKSIG under interpreter.cpp"], -["by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE)"], +["by replacing (sigversion == SigVersion::BASE) with (sigversion != SigVersion::BASE)"], ["Non-segwit: wrong sighash (without FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"], [[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]], "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012103b12a1ec8428fc74166926318c15e17408fea82dbb157575e16a8c365f546248f4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH"], @@ -269,7 +269,7 @@ ["Script is 2 CHECKMULTISIGVERIFY DROP"], ["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"], ["Signature is 0 2 "], -["Should pass by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE) under OP_CHECKMULTISIG"], +["Should pass by replacing (sigversion == SigVersion::BASE) with (sigversion != SigVersion::BASE) under OP_CHECKMULTISIG"], ["Non-segwit: wrong sighash (without FindAndDelete) = 4bc6a53e8e16ef508c19e38bba08831daba85228b0211f323d4cb0999cf2a5e8"], [[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]], "01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596015221023fd5dd42b44769c5653cbc5947ff30ab8871f240ad0c0e7432aefe84b5b4ff3421039d52178dbde360b83f19cf348deb04fa8360e1bf5634577be8e50fafc2b0e4ef4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH"], diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index d3d9c4186..1925a3051 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -432,7 +432,7 @@ UniValue removeprunedfunds(const Config &config, txIds.push_back(txid); std::vector txIdsOut; - if (pwallet->ZapSelectTx(txIds, txIdsOut) != DB_LOAD_OK) { + if (pwallet->ZapSelectTx(txIds, txIdsOut) != DBErrors::LOAD_OK) { throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction."); } diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp index dd394ee5d..3164b89cf 100644 --- a/src/wallet/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -18,7 +18,7 @@ static void GetResults(std::map &results) { std::list aes; results.clear(); - BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK); + BOOST_CHECK(pwalletMain->ReorderTransactions() == DBErrors::LOAD_OK); pwalletMain->ListAccountCreditDebit("", aes); for (CAccountingEntry &ae : aes) { results[ae.nOrderPos * SATOSHI] = ae; diff --git a/src/wallet/test/walletdb_tests.cpp b/src/wallet/test/walletdb_tests.cpp index c80af9eac..ccb8fcd2c 100644 --- a/src/wallet/test/walletdb_tests.cpp +++ b/src/wallet/test/walletdb_tests.cpp @@ -37,7 +37,7 @@ static std::unique_ptr TmpDB(const fs::path &pathTemp, static std::unique_ptr LoadWallet(CWalletDB *db) { std::unique_ptr wallet(new CWallet(Params())); DBErrors res = db->LoadWallet(wallet.get()); - BOOST_CHECK(res == DB_LOAD_OK); + BOOST_CHECK(res == DBErrors::LOAD_OK); return wallet; } } // namespace diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index e41e0a141..7854d615a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -830,11 +830,11 @@ DBErrors CWallet::ReorderTransactions() { if (pwtx) { if (!walletdb.WriteTx(*pwtx)) { - return DB_LOAD_FAIL; + return DBErrors::LOAD_FAIL; } } else if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) { - return DB_LOAD_FAIL; + return DBErrors::LOAD_FAIL; } } else { int64_t nOrderPosOff = 0; @@ -854,18 +854,18 @@ DBErrors CWallet::ReorderTransactions() { // Since we're changing the order, write it back. if (pwtx) { if (!walletdb.WriteTx(*pwtx)) { - return DB_LOAD_FAIL; + return DBErrors::LOAD_FAIL; } } else if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) { - return DB_LOAD_FAIL; + return DBErrors::LOAD_FAIL; } } } walletdb.WriteOrderPosNext(nOrderPosNext); - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { @@ -3347,7 +3347,7 @@ DBErrors CWallet::LoadWallet(bool &fFirstRunRet) { fFirstRunRet = false; DBErrors nLoadWalletRet = CWalletDB(*dbw, "cr+").LoadWallet(this); - if (nLoadWalletRet == DB_NEED_REWRITE) { + if (nLoadWalletRet == DBErrors::NEED_REWRITE) { if (dbw->Rewrite("\x04pool")) { setInternalKeyPool.clear(); setExternalKeyPool.clear(); @@ -3363,13 +3363,13 @@ DBErrors CWallet::LoadWallet(bool &fFirstRunRet) { mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty() && mapHdPubKeys.empty() && mapKeyMetadata.empty(); - if (nLoadWalletRet != DB_LOAD_OK) { + if (nLoadWalletRet != DBErrors::LOAD_OK) { return nLoadWalletRet; } uiInterface.LoadWallet(this); - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } DBErrors CWallet::ZapSelectTx(std::vector &txIdsIn, @@ -3381,7 +3381,7 @@ DBErrors CWallet::ZapSelectTx(std::vector &txIdsIn, mapWallet.erase(txid); } - if (nZapSelectTxRet == DB_NEED_REWRITE) { + if (nZapSelectTxRet == DBErrors::NEED_REWRITE) { if (dbw->Rewrite("\x04pool")) { setInternalKeyPool.clear(); setExternalKeyPool.clear(); @@ -3392,18 +3392,18 @@ DBErrors CWallet::ZapSelectTx(std::vector &txIdsIn, } } - if (nZapSelectTxRet != DB_LOAD_OK) { + if (nZapSelectTxRet != DBErrors::LOAD_OK) { return nZapSelectTxRet; } MarkDirty(); - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } DBErrors CWallet::ZapWalletTx(std::vector &vWtx) { DBErrors nZapWalletTxRet = CWalletDB(*dbw, "cr+").ZapWalletTx(vWtx); - if (nZapWalletTxRet == DB_NEED_REWRITE) { + if (nZapWalletTxRet == DBErrors::NEED_REWRITE) { if (dbw->Rewrite("\x04pool")) { LOCK(cs_wallet); setInternalKeyPool.clear(); @@ -3415,11 +3415,11 @@ DBErrors CWallet::ZapWalletTx(std::vector &vWtx) { } } - if (nZapWalletTxRet != DB_LOAD_OK) { + if (nZapWalletTxRet != DBErrors::LOAD_OK) { return nZapWalletTxRet; } - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } bool CWallet::SetAddressBook(const CTxDestination &address, @@ -4224,7 +4224,7 @@ CWallet *CWallet::CreateWalletFromFile(const CChainParams &chainParams, std::unique_ptr tempWallet = MakeUnique(chainParams, std::move(dbw)); DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); - if (nZapWalletRet != DB_LOAD_OK) { + if (nZapWalletRet != DBErrors::LOAD_OK) { InitError( strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); return nullptr; @@ -4239,25 +4239,25 @@ CWallet *CWallet::CreateWalletFromFile(const CChainParams &chainParams, new CWalletDBWrapper(&bitdb, walletFile)); CWallet *walletInstance = new CWallet(chainParams, std::move(dbw)); DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); - if (nLoadWalletRet != DB_LOAD_OK) { - if (nLoadWalletRet == DB_CORRUPT) { + if (nLoadWalletRet != DBErrors::LOAD_OK) { + if (nLoadWalletRet == DBErrors::CORRUPT) { InitError( strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); return nullptr; } - if (nLoadWalletRet == DB_NONCRITICAL_ERROR) { + if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR) { InitWarning(strprintf( _("Error reading %s! All keys read correctly, but transaction " "data" " or address book entries might be missing or incorrect."), walletFile)); - } else if (nLoadWalletRet == DB_TOO_NEW) { + } else if (nLoadWalletRet == DBErrors::TOO_NEW) { InitError(strprintf( _("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME))); return nullptr; - } else if (nLoadWalletRet == DB_NEED_REWRITE) { + } else if (nLoadWalletRet == DBErrors::NEED_REWRITE) { InitError(strprintf( _("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME))); diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 5437b25bf..0a6cfcb74 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -548,14 +548,14 @@ bool CWalletDB::IsKeyType(const std::string &strType) { DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { CWalletScanState wss; bool fNoncriticalErrors = false; - DBErrors result = DB_LOAD_OK; + DBErrors result = DBErrors::LOAD_OK; LOCK(pwallet->cs_wallet); try { int nMinVersion = 0; if (batch.Read((std::string) "minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) { - return DB_TOO_NEW; + return DBErrors::TOO_NEW; } pwallet->LoadMinVersion(nMinVersion); } @@ -564,7 +564,7 @@ DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { Dbc *pcursor = batch.GetCursor(); if (!pcursor) { LogPrintf("Error getting wallet database cursor\n"); - return DB_CORRUPT; + return DBErrors::CORRUPT; } while (true) { @@ -578,7 +578,7 @@ DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { if (ret != 0) { LogPrintf("Error reading next record from wallet database\n"); - return DB_CORRUPT; + return DBErrors::CORRUPT; } // Try to be tolerant of single corrupt records: @@ -587,7 +587,7 @@ DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { // losing keys is considered a catastrophic error, anything else // we assume the user can live with: if (IsKeyType(strType) || strType == "defaultkey") { - result = DB_CORRUPT; + result = DBErrors::CORRUPT; } else { // Leave other errors alone, if we try to fix them we might // make things worse. But do warn the user there is @@ -612,16 +612,16 @@ DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { } catch (const boost::thread_interrupted &) { throw; } catch (...) { - result = DB_CORRUPT; + result = DBErrors::CORRUPT; } - if (fNoncriticalErrors && result == DB_LOAD_OK) { - result = DB_NONCRITICAL_ERROR; + if (fNoncriticalErrors && result == DBErrors::LOAD_OK) { + result = DBErrors::NONCRITICAL_ERROR; } // Any wallet corruption at all: skip any rewriting or upgrading, we don't // want to make it worse. - if (result != DB_LOAD_OK) { + if (result != DBErrors::LOAD_OK) { return result; } @@ -642,7 +642,7 @@ DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000)) { - return DB_NEED_REWRITE; + return DBErrors::NEED_REWRITE; } if (wss.nFileVersion < CLIENT_VERSION) { @@ -666,13 +666,13 @@ DBErrors CWalletDB::LoadWallet(CWallet *pwallet) { DBErrors CWalletDB::FindWalletTx(std::vector &txIds, std::vector &vWtx) { - DBErrors result = DB_LOAD_OK; + DBErrors result = DBErrors::LOAD_OK; try { int nMinVersion = 0; if (batch.Read((std::string) "minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) { - return DB_TOO_NEW; + return DBErrors::TOO_NEW; } } @@ -680,7 +680,7 @@ DBErrors CWalletDB::FindWalletTx(std::vector &txIds, Dbc *pcursor = batch.GetCursor(); if (!pcursor) { LogPrintf("Error getting wallet database cursor\n"); - return DB_CORRUPT; + return DBErrors::CORRUPT; } while (true) { @@ -694,7 +694,7 @@ DBErrors CWalletDB::FindWalletTx(std::vector &txIds, if (ret != 0) { LogPrintf("Error reading next record from wallet database\n"); - return DB_CORRUPT; + return DBErrors::CORRUPT; } std::string strType; @@ -714,7 +714,7 @@ DBErrors CWalletDB::FindWalletTx(std::vector &txIds, } catch (const boost::thread_interrupted &) { throw; } catch (...) { - result = DB_CORRUPT; + result = DBErrors::CORRUPT; } return result; @@ -726,7 +726,7 @@ DBErrors CWalletDB::ZapSelectTx(std::vector &txIdsIn, std::vector txIds; std::vector vWtx; DBErrors err = FindWalletTx(txIds, vWtx); - if (err != DB_LOAD_OK) { + if (err != DBErrors::LOAD_OK) { return err; } @@ -757,27 +757,27 @@ DBErrors CWalletDB::ZapSelectTx(std::vector &txIdsIn, } if (delerror) { - return DB_CORRUPT; + return DBErrors::CORRUPT; } - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } DBErrors CWalletDB::ZapWalletTx(std::vector &vWtx) { // Build list of wallet TXs. std::vector txIds; DBErrors err = FindWalletTx(txIds, vWtx); - if (err != DB_LOAD_OK) { + if (err != DBErrors::LOAD_OK) { return err; } // Erase each wallet TX. for (const TxId &txid : txIds) { if (!EraseTx(txid)) { - return DB_CORRUPT; + return DBErrors::CORRUPT; } } - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } void MaybeCompactWalletDB() { diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 3b53afc7d..8848c3e82 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -51,13 +51,13 @@ class uint160; class uint256; /** Error statuses for the wallet database */ -enum DBErrors { - DB_LOAD_OK, - DB_CORRUPT, - DB_NONCRITICAL_ERROR, - DB_TOO_NEW, - DB_LOAD_FAIL, - DB_NEED_REWRITE +enum class DBErrors { + LOAD_OK, + CORRUPT, + NONCRITICAL_ERROR, + TOO_NEW, + LOAD_FAIL, + NEED_REWRITE }; /** From 6bfa21c23343634fec2985698fef3da957167db8 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 2 Apr 2019 10:56:14 -0700 Subject: [PATCH 12/20] Merge #10275: [rpc] Allow fetching tx directly from specified block in getrawtransaction Summary: 434526a [test] Add tests for getrawtransaction with block hash. (Karl-Johan Alm) b167951 [rpc] Allow getrawtransaction to take optional blockhash to fetch transaction from a block directly. (Karl-Johan Alm) a5f5a2c [rpc] Fix fVerbose parsing (remove excess if cases). (Karl-Johan Alm) Pull request description: [Reviewer hint: use [?w=1](https://github.com/bitcoin/bitcoin/pull/10275/files?w=1) to avoid seeing a bunch of indentation changes.] Presuming a user knows the block hash of the block containing a given transaction, this PR allows them to fetch the raw transaction, even without `-txindex`. It also enables support for getting transactions that are in orphaned blocks. Note that supplying a block hash will override mempool and txindex support in `GetTransaction`. The rationale behind this is that a transaction may be in multiple places (orphaned blocks) and if the user supplies an explicit block hash it should be adhered to. ```Bash $ # a41.. is a tx inside an orphan block ..3c6f.. -- first try getting it normally $ ./bitcoin-cli getrawtransaction a41e66ee1341aa9fb9475b98cfdc1fe1261faa56c0a49254f33065ec90f7cd79 1 error code: -5 error message: No such mempool transaction. Use -txindex to enable blockchain transaction queries. Use gettransaction for wallet transactions. $ # now try with block hash $ ./bitcoin-cli getrawtransaction a41e66ee1341aa9fb9475b98cfdc1fe1261faa56c0a49254f33065ec90f7cd79 1 0000000000000000003c6fe479122bfa4a9187493937af1734e1e5cd9f198ec7 { "hex": "01000000014e7e81144e42f6d65550e59b715d470c9301fd7ac189[...]90488ac00000000", "inMainChain": false, "txid": "a41e66ee1341aa9fb9475b98cfdc1fe1261faa56c0a49254f33065ec90f7cd79", "hash": "a41e66ee1341aa9fb9475b98cfdc1fe1261faa56c0a49254f33065ec90f7cd79", "size": 225, [...] } $ # another tx 6c66... in block 462000 $ ./bitcoin-cli getrawtransaction 6c66b98191e9d6cc671f6817142152ebf6c5cab2ef008397b5a71ac13255a735 1 00000000000000000217f2c12922e321f6d4aa933ce88005a9a493c503054a40 { "hex": "0200000004d157[...]88acaf0c0700", "inMainChain": true, "txid": "6c66b98191e9d6cc671f6817142152ebf6c5cab2ef008397b5a71ac13255a735", "hash": "6c66b98191e9d6cc671f6817142152ebf6c5cab2ef008397b5a71ac13255a735", "size": 666, [...] } $ ``` Tree-SHA512: 279be3818141edd3cc194a9ee65929331920afb30297ab2d6da07293a2d7311afee5c8b00c6457477d9f1f86e86786a9b56878ea3ee19fa2629b829d042d0cda Backport of Core PR 10275 https://github.com/bitcoin/bitcoin/pull/10275/files Completes T562 Test Plan: make check test_runner.py Reviewers: deadalnix, Fabien, #bitcoin_abc Reviewed By: Fabien, #bitcoin_abc Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2746 --- doc/release-notes.md | 3 + src/rpc/rawtransaction.cpp | 86 ++++++++++++++++++--------- src/validation.cpp | 83 +++++++++++++------------- src/validation.h | 3 +- test/functional/rpc_rawtransaction.py | 35 ++++++++++- 5 files changed, 138 insertions(+), 72 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index b58eb4c61..a6e4950d6 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -31,3 +31,6 @@ Bitcoin-ABC 19.x backports: - Various minor fixes to RPC parameter validation - Minor wallet performance improvements - `errors` in getmininginfo rpc commmand has been deprecated. Use `warnings` now instead. + - Added optional `blockhash` parameter to `getrawtransaction` to narrowly + search for a transaction within a given block. New returned field + `in_active_chain` will indicate if that block is part of the active chain. diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 43f6075ac..36a3af1ac 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -65,13 +65,20 @@ void TxToJSON(const CTransaction &tx, const uint256 hashBlock, static UniValue getrawtransaction(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() < 1 || - request.params.size() > 2) { + request.params.size() > 3) { throw std::runtime_error( - "getrawtransaction \"txid\" ( verbose )\n" + "getrawtransaction \"txid\" ( verbose \"blockhash\" )\n" "\nNOTE: By default this function only works for mempool " "transactions. If the -txindex option is\n" - "enabled, it also works for blockchain transactions.\n" + "enabled, it also works for blockchain transactions. If the block " + "which contains the transaction\n" + "is known, its hash can be provided even for nodes without " + "-txindex. Note that if a blockhash is\n" + "provided, only that block will be searched and if the transaction " + "is in the mempool or other\n" + "blocks, or if this node does not have the given block available, " + "the transaction will not be found.\n" "DEPRECATED: for now, it also works for transactions with unspent " "outputs.\n" @@ -83,8 +90,10 @@ static UniValue getrawtransaction(const Config &config, "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" - "2. verbose (bool, optional, default=false) If false, return " - "a string, otherwise return a json object\n" + "2. verbose (bool, optional, default=false) If false, return a " + "string, otherwise return a json object\n" + "3. \"blockhash\" (string, optional) The block in which to look " + "for the transaction\n" "\nResult (if verbose is not set or set to false):\n" "\"data\" (string) The serialized, hex-encoded data for " @@ -92,6 +101,9 @@ static UniValue getrawtransaction(const Config &config, "\nResult (if verbose is set to true):\n" "{\n" + " \"in_active_chain\": b, (bool) Whether specified block is in " + "the active chain or not (only present with explicit \"blockhash\" " + "argument)\n" " \"hex\" : \"data\", (string) The serialized, hex-encoded " "data for 'txid'\n" " \"txid\" : \"id\", (string) The transaction id (same as " @@ -145,40 +157,57 @@ static UniValue getrawtransaction(const Config &config, "\nExamples:\n" + HelpExampleCli("getrawtransaction", "\"mytxid\"") + HelpExampleCli("getrawtransaction", "\"mytxid\" true") + - HelpExampleRpc("getrawtransaction", "\"mytxid\", true")); + HelpExampleRpc("getrawtransaction", "\"mytxid\", true") + + HelpExampleCli("getrawtransaction", + "\"mytxid\" false \"myblockhash\"") + + HelpExampleCli("getrawtransaction", + "\"mytxid\" true \"myblockhash\"")); } LOCK(cs_main); + bool in_active_chain = true; TxId txid = TxId(ParseHashV(request.params[0], "parameter 1")); + CBlockIndex *blockindex = nullptr; // Accept either a bool (true) or a num (>=1) to indicate verbose output. bool fVerbose = false; if (!request.params[1].isNull()) { - if (request.params[1].isNum()) { - if (request.params[1].get_int() != 0) { - fVerbose = true; - } - } else if (request.params[1].isBool()) { - if (request.params[1].isTrue()) { - fVerbose = true; + fVerbose = request.params[1].isNum() + ? (request.params[1].get_int() != 0) + : request.params[1].get_bool(); + } + + if (!request.params[2].isNull()) { + uint256 blockhash = ParseHashV(request.params[2], "parameter 3"); + if (!blockhash.IsNull()) { + BlockMap::iterator it = mapBlockIndex.find(blockhash); + if (it == mapBlockIndex.end()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, + "Block hash not found"); } - } else { - throw JSONRPCError( - RPC_TYPE_ERROR, - "Invalid type provided. Verbose parameter must be a boolean."); + blockindex = it->second; + in_active_chain = chainActive.Contains(blockindex); } } CTransactionRef tx; - uint256 hashBlock; - if (!GetTransaction(config, txid, tx, hashBlock, true)) { - throw JSONRPCError( - RPC_INVALID_ADDRESS_OR_KEY, - std::string(fTxIndex ? "No such mempool or blockchain transaction" - : "No such mempool transaction. Use -txindex " - "to enable blockchain transaction queries") + - ". Use gettransaction for wallet transactions."); + uint256 hash_block; + if (!GetTransaction(config, txid, tx, hash_block, true, blockindex)) { + std::string errmsg; + if (blockindex) { + if (!blockindex->nStatus.hasData()) { + throw JSONRPCError(RPC_MISC_ERROR, "Block not available"); + } + errmsg = "No such transaction found in the provided block"; + } else { + errmsg = fTxIndex ? "No such mempool or blockchain transaction" + : "No such mempool transaction. Use -txindex to " + "enable blockchain transaction queries"; + } + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, + errmsg + + ". Use gettransaction for wallet transactions."); } if (!fVerbose) { @@ -186,7 +215,10 @@ static UniValue getrawtransaction(const Config &config, } UniValue result(UniValue::VOBJ); - TxToJSON(*tx, hashBlock, result); + if (blockindex) { + result.pushKV("in_active_chain", in_active_chain); + } + TxToJSON(*tx, hash_block, result); return result; } @@ -1288,7 +1320,7 @@ static UniValue sendrawtransaction(const Config &config, static const ContextFreeRPCCommand commands[] = { // category name actor (function) argNames // ------------------- ------------------------ ---------------------- ---------- - { "rawtransactions", "getrawtransaction", getrawtransaction, {"txid","verbose"} }, + { "rawtransactions", "getrawtransaction", getrawtransaction, {"txid","verbose","blockhash"} }, { "rawtransactions", "createrawtransaction", createrawtransaction, {"inputs","outputs","locktime"} }, { "rawtransactions", "decoderawtransaction", decoderawtransaction, {"hexstring"} }, { "rawtransactions", "decodescript", decodescript, {"hexstring"} }, diff --git a/src/validation.cpp b/src/validation.cpp index f98212b3d..51b043568 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -782,57 +782,58 @@ bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool, /** * Return transaction in txOut, and if it was found inside a block, its hash is - * placed in hashBlock. + * placed in hashBlock. If blockIndex is provided, the transaction is fetched + * from the corresponding block. */ bool GetTransaction(const Config &config, const TxId &txid, - CTransactionRef &txOut, uint256 &hashBlock, - bool fAllowSlow) { - CBlockIndex *pindexSlow = nullptr; + CTransactionRef &txOut, uint256 &hashBlock, bool fAllowSlow, + CBlockIndex *blockIndex) { + CBlockIndex *pindexSlow = blockIndex; LOCK(cs_main); - CTransactionRef ptx = g_mempool.get(txid); - if (ptx) { - txOut = ptx; - return true; - } - - if (fTxIndex) { - CDiskTxPos postx; - if (pblocktree->ReadTxIndex(txid, postx)) { - CAutoFile file(OpenBlockFile(postx, true), SER_DISK, - CLIENT_VERSION); - if (file.IsNull()) { - return error("%s: OpenBlockFile failed", __func__); - } - - CBlockHeader header; - try { - file >> header; - fseek(file.Get(), postx.nTxOffset, SEEK_CUR); - file >> txOut; - } catch (const std::exception &e) { - return error("%s: Deserialize or I/O error - %s", __func__, - e.what()); - } + if (!blockIndex) { + CTransactionRef ptx = g_mempool.get(txid); + if (ptx) { + txOut = ptx; + return true; + } - hashBlock = header.GetHash(); - if (txOut->GetId() != txid) { - return error("%s: txid mismatch", __func__); + if (fTxIndex) { + CDiskTxPos postx; + if (pblocktree->ReadTxIndex(txid, postx)) { + CAutoFile file(OpenBlockFile(postx, true), SER_DISK, + CLIENT_VERSION); + if (file.IsNull()) { + return error("%s: OpenBlockFile failed", __func__); + } + CBlockHeader header; + try { + file >> header; + fseek(file.Get(), postx.nTxOffset, SEEK_CUR); + file >> txOut; + } catch (const std::exception &e) { + return error("%s: Deserialize or I/O error - %s", __func__, + e.what()); + } + hashBlock = header.GetHash(); + if (txOut->GetId() != txid) { + return error("%s: txid mismatch", __func__); + } + return true; } - return true; + // transaction not found in index, nothing more can be done + return false; } - // transaction not found in index, nothing more can be done - return false; - } - - // use coin database to locate block that contains transaction, and scan it - if (fAllowSlow) { - const Coin &coin = AccessByTxid(*pcoinsTip, txid); - if (!coin.IsSpent()) { - pindexSlow = chainActive[coin.GetHeight()]; + // use coin database to locate block that contains transaction, and scan + // it + if (fAllowSlow) { + const Coin &coin = AccessByTxid(*pcoinsTip, txid); + if (!coin.IsSpent()) { + pindexSlow = chainActive[coin.GetHeight()]; + } } } diff --git a/src/validation.h b/src/validation.h index 01afec5c0..6f184a74f 100644 --- a/src/validation.h +++ b/src/validation.h @@ -405,7 +405,8 @@ bool IsInitialBlockDownload(); * Retrieve a transaction (from memory pool, or from disk, if possible). */ bool GetTransaction(const Config &config, const TxId &txid, CTransactionRef &tx, - uint256 &hashBlock, bool fAllowSlow = false); + uint256 &hashBlock, bool fAllowSlow = false, + CBlockIndex *blockIndex = nullptr); /** * Find the best known block, and make it the active tip of the block chain. diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index d2b6169a2..1070a7580 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -62,6 +62,35 @@ def run_test(self): assert_raises_rpc_error( -25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex']) + ##################################### + # getrawtransaction with block hash # + ##################################### + + # make a tx by sending then generate 2 blocks; block1 has the tx in it + tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1) + block1, block2 = self.nodes[2].generate(2) + self.sync_all() + # We should be able to get the raw transaction by providing the correct block + gottx = self.nodes[0].getrawtransaction(tx, True, block1) + assert_equal(gottx['txid'], tx) + assert_equal(gottx['in_active_chain'], True) + # We should not have the 'in_active_chain' flag when we don't provide a block + gottx = self.nodes[0].getrawtransaction(tx, True) + assert_equal(gottx['txid'], tx) + assert 'in_active_chain' not in gottx + # We should not get the tx if we provide an unrelated block + assert_raises_rpc_error(-5, "No such transaction found", + self.nodes[0].getrawtransaction, tx, True, block2) + # An invalid block hash should raise the correct errors + assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", + self.nodes[0].getrawtransaction, tx, True, True) + assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", + self.nodes[0].getrawtransaction, tx, True, "foobar") + assert_raises_rpc_error(-8, "parameter 3 must be of length 64", + self.nodes[0].getrawtransaction, tx, True, "abcd1234") + assert_raises_rpc_error(-5, "Block hash not found", self.nodes[0].getrawtransaction, + tx, True, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + # # RAW TX MULTISIG TESTS # # @@ -232,15 +261,15 @@ def run_test(self): # 6. invalid parameters - supply txid and string "Flase" assert_raises_rpc_error( - -3, "Invalid type", self.nodes[0].getrawtransaction, txHash, "False") + -1, "not a boolean", self.nodes[0].getrawtransaction, txHash, "False") # 7. invalid parameters - supply txid and empty array assert_raises_rpc_error( - -3, "Invalid type", self.nodes[0].getrawtransaction, txHash, []) + -1, "not a boolean", self.nodes[0].getrawtransaction, txHash, []) # 8. invalid parameters - supply txid and empty dict assert_raises_rpc_error( - -3, "Invalid type", self.nodes[0].getrawtransaction, txHash, {}) + -1, "not a boolean", self.nodes[0].getrawtransaction, txHash, {}) # Sanity checks on verbose getrawtransaction output rawTxOutput = self.nodes[0].getrawtransaction(txHash, True) From e6f978735f5e9312f46a348d620f43bf51c244a5 Mon Sep 17 00:00:00 2001 From: Nico Guiton Date: Tue, 2 Apr 2019 16:34:15 +0000 Subject: [PATCH 13/20] Use static_cast instead of C-style casts for non-fundamental types Summary: A C-style cast is equivalent to try casting in the following order: 1. const_cast(...) 2. static_cast(...) 3. const_cast(static_cast(...)) 4. reinterpret_cast(...) 5. const_cast(reinterpret_cast(...)) By using static_cast(...) explicitly we avoid the possibility of an unintentional and dangerous reinterpret_cast. Furthermore static_cast(...) allows for easier grepping of casts. Please enter the commit message for your changes. Lines starting Backport of Core PR10498 https://github.com/bitcoin/bitcoin/pull/10498 Completes T555 Test Plan: make check test_runner.py Reviewers: jasonbcox, deadalnix, Fabien, O1 Bitcoin ABC, #bitcoin_abc Reviewed By: jasonbcox, O1 Bitcoin ABC, #bitcoin_abc Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2765 --- src/addrman.h | 2 +- src/core_read.cpp | 6 +++--- src/httpserver.cpp | 2 +- src/net.cpp | 3 ++- src/netaddress.cpp | 3 ++- src/primitives/block.h | 4 ++-- src/protocol.h | 4 ++-- src/qt/bitcoin.cpp | 2 +- src/qt/bitcoingui.cpp | 9 +++++---- src/qt/coincontroldialog.cpp | 12 +++++++----- src/qt/coincontroltreewidget.cpp | 2 +- src/qt/sendcoinsdialog.cpp | 2 +- src/qt/splashscreen.cpp | 2 +- src/qt/transactionview.cpp | 4 ++-- src/qt/winshutdownmonitor.cpp | 5 +++-- src/script/script.h | 2 +- src/torcontrol.cpp | 6 +++--- src/txdb.h | 2 +- src/wallet/wallet.h | 2 +- 19 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/addrman.h b/src/addrman.h index 0e767fc2b..007a15b96 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -55,7 +55,7 @@ class CAddrInfo : public CAddress { template inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(*(CAddress *)this); + READWRITE(*static_cast(this)); READWRITE(source); READWRITE(nLastSuccess); READWRITE(nAttempts); diff --git a/src/core_read.cpp b/src/core_read.cpp index 63cbc8cad..e14a5ea7f 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -28,16 +28,16 @@ CScript ParseScript(const std::string &s) { continue; } - const char *name = GetOpName((opcodetype)op); + const char *name = GetOpName(static_cast(op)); if (strcmp(name, "OP_UNKNOWN") == 0) { continue; } std::string strName(name); - mapOpNames[strName] = (opcodetype)op; + mapOpNames[strName] = static_cast(op); // Convenience: OP_ADD and just ADD are both recognized: strName.replace(strName.find("OP_"),3,""); - mapOpNames[strName] = (opcodetype)op; + mapOpNames[strName] = static_cast(op); } } diff --git a/src/httpserver.cpp b/src/httpserver.cpp index baac2e277..71d20ef99 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -513,7 +513,7 @@ struct event_base *EventBase() { static void httpevent_callback_fn(evutil_socket_t, short, void *data) { // Static handler: simply call inner handler - HTTPEvent *self = ((HTTPEvent *)data); + HTTPEvent *self = static_cast(data); self->handler(); if (self->deleteWhenTriggered) delete self; } diff --git a/src/net.cpp b/src/net.cpp index a5a53533d..dbba1baf4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2109,7 +2109,8 @@ void CConnman::OpenNetworkConnection(const CAddress &addrConnect, return; } if (!pszDest) { - if (IsLocal(addrConnect) || FindNode((CNetAddr)addrConnect) || + if (IsLocal(addrConnect) || + FindNode(static_cast(addrConnect)) || IsBanned(addrConnect) || FindNode(addrConnect.ToStringIPPort())) { return; } diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 2e126d82a..82058ab1d 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -513,7 +513,8 @@ unsigned short CService::GetPort() const { } bool operator==(const CService &a, const CService &b) { - return (CNetAddr)a == (CNetAddr)b && a.port == b.port; + return static_cast(a) == static_cast(b) && + a.port == b.port; } bool operator<(const CService &a, const CService &b) { diff --git a/src/primitives/block.h b/src/primitives/block.h index 64e4d73fb..41ac6ff1a 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -70,14 +70,14 @@ class CBlock : public CBlockHeader { CBlock(const CBlockHeader &header) { SetNull(); - *((CBlockHeader *)this) = header; + *(static_cast(this)) = header; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(*(CBlockHeader *)this); + READWRITE(*static_cast(this)); READWRITE(vtx); } diff --git a/src/protocol.h b/src/protocol.h index 3e5c6f40a..3986b57c5 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -395,8 +395,8 @@ class CAddress : public CService { READWRITE(nTime); uint64_t nServicesInt = nServices; READWRITE(nServicesInt); - nServices = (ServiceFlags)nServicesInt; - READWRITE(*(CService *)this); + nServices = static_cast(nServicesInt); + READWRITE(*static_cast(this)); } // TODO: make private (improves encapsulation) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index c1f0d4ca3..80633f4fa 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -782,7 +782,7 @@ int main(int argc, char *argv[]) { WinShutdownMonitor::registerShutdownBlockReason( QObject::tr("%1 didn't yet exit safely...") .arg(QObject::tr(PACKAGE_NAME)), - (HWND)app.getMainWinId()); + static_cast(app.getMainWinId())); #endif app.exec(); app.requestShutdown(config); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a41aaf87a..a4bbb36f2 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -660,7 +660,7 @@ void BitcoinGUI::createTrayIconMenu() { #else // Note: On Mac, the dock icon is used to provide the tray's functionality. MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); - dockIconHandler->setMainWindow((QMainWindow *)this); + dockIconHandler->setMainWindow(static_cast(this)); trayIconMenu = dockIconHandler->dockMenu(); #endif @@ -996,14 +996,15 @@ void BitcoinGUI::message(const QString &title, const QString &message, buttons = QMessageBox::Ok; showNormalIfMinimized(); - QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, - buttons, this); + QMessageBox mBox(static_cast(nMBoxIcon), strTitle, + message, buttons, this); int r = mBox.exec(); if (ret != nullptr) { *ret = r == QMessageBox::Ok; } } else - notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message); + notificator->notify(static_cast(nNotifyIcon), + strTitle, message); } void BitcoinGUI::changeEvent(QEvent *e) { diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 4c9956e0d..e4517b7b3 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -169,9 +169,9 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, ui->radioTreeMode->click(); if (settings.contains("nCoinControlSortColumn") && settings.contains("nCoinControlSortOrder")) - sortView( - settings.value("nCoinControlSortColumn").toInt(), - ((Qt::SortOrder)settings.value("nCoinControlSortOrder").toInt())); + sortView(settings.value("nCoinControlSortColumn").toInt(), + (static_cast( + settings.value("nCoinControlSortOrder").toInt()))); } CoinControlDialog::~CoinControlDialog() { @@ -473,7 +473,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog *dialog) { nPayAmount += amount; if (amount > Amount::zero()) { - CTxOut txout(Amount(amount), (CScript)std::vector(24, 0)); + CTxOut txout(amount, + static_cast(std::vector(24, 0))); txDummy.vout.push_back(txout); if (txout.IsDust(dustRelayFee)) { fDust = true; @@ -566,7 +567,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog *dialog) { // Never create dust outputs; if we would, just add the dust to the // fee. if (nChange > Amount::zero() && nChange < MIN_CHANGE) { - CTxOut txout(nChange, (CScript)std::vector(24, 0)); + CTxOut txout(nChange, + static_cast(std::vector(24, 0))); if (txout.IsDust(dustRelayFee)) { // dust-change will be raised until no dust if (CoinControlDialog::fSubtractFeeFromAmount) { diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp index 03638bf60..e479b2286 100644 --- a/src/qt/coincontroltreewidget.cpp +++ b/src/qt/coincontroltreewidget.cpp @@ -23,7 +23,7 @@ void CoinControlTreeWidget::keyPressEvent(QKeyEvent *event) { { event->ignore(); CoinControlDialog *coinControlDialog = - (CoinControlDialog *)this->parentWidget(); + static_cast(this->parentWidget()); coinControlDialog->done(QDialog::Accepted); } else { this->QTreeWidget::keyPressEvent(event); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 424890bd4..0bfbf3ec7 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -376,7 +376,7 @@ void SendCoinsDialog::on_sendButton_clicked() { SEND_CONFIRM_DELAY, this); confirmationDialog.exec(); QMessageBox::StandardButton retval = - (QMessageBox::StandardButton)confirmationDialog.result(); + static_cast(confirmationDialog.result()); if (retval != QMessageBox::Yes) { fNewRecipientAllowed = true; diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 2d18fe891..3a49d1e72 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -32,7 +32,7 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) float fontFactor = 1.0; float devicePixelRatio = 1.0; #if QT_VERSION > 0x050100 - devicePixelRatio = ((QGuiApplication*)QCoreApplication::instance())->devicePixelRatio(); + devicePixelRatio = static_cast(QCoreApplication::instance())->devicePixelRatio(); #endif // define text to place diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 8c311b6c5..05d7c9481 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -338,8 +338,8 @@ void TransactionView::chooseWatchonly(int idx) { } transactionProxyModel->setWatchOnlyFilter( - (TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx) - .toInt()); + static_cast( + watchOnlyWidget->itemData(idx).toInt())); } void TransactionView::changedPrefix(const QString &prefix) { diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp index 7962e6351..0c51cf991 100644 --- a/src/qt/winshutdownmonitor.cpp +++ b/src/qt/winshutdownmonitor.cpp @@ -56,8 +56,9 @@ bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void WinShutdownMonitor::registerShutdownBlockReason(const QString &strReason, const HWND &mainWinId) { typedef BOOL(WINAPI * PSHUTDOWNBRCREATE)(HWND, LPCWSTR); - PSHUTDOWNBRCREATE shutdownBRCreate = (PSHUTDOWNBRCREATE)GetProcAddress( - GetModuleHandleA("User32.dll"), "ShutdownBlockReasonCreate"); + PSHUTDOWNBRCREATE shutdownBRCreate = + static_cast(GetProcAddress( + GetModuleHandleA("User32.dll"), "ShutdownBlockReasonCreate")); if (shutdownBRCreate == nullptr) { qWarning() << "registerShutdownBlockReason: GetProcAddress for " "ShutdownBlockReasonCreate failed"; diff --git a/src/script/script.h b/src/script/script.h index 6c50251d6..7bfe1024e 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -558,7 +558,7 @@ class CScript : public CScriptBase { pc += nSize; } - opcodeRet = (opcodetype)opcode; + opcodeRet = static_cast(opcode); return true; } diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 7b317b671..2ce81b23f 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -136,7 +136,7 @@ TorControlConnection::~TorControlConnection() { } void TorControlConnection::readcb(struct bufferevent *bev, void *ctx) { - TorControlConnection *self = (TorControlConnection *)ctx; + TorControlConnection *self = static_cast(ctx); struct evbuffer *input = bufferevent_get_input(bev); size_t n_read_out = 0; char *line; @@ -187,7 +187,7 @@ void TorControlConnection::readcb(struct bufferevent *bev, void *ctx) { void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ctx) { - TorControlConnection *self = (TorControlConnection *)ctx; + TorControlConnection *self = static_cast(ctx); if (what & BEV_EVENT_CONNECTED) { LogPrint(BCLog::TOR, "tor: Successfully connected!\n"); self->connected(*self); @@ -763,7 +763,7 @@ fs::path TorController::GetPrivateKeyFile() { } void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) { - TorController *self = (TorController *)arg; + TorController *self = static_cast(arg); self->Reconnect(); } diff --git a/src/txdb.h b/src/txdb.h index 6022a5143..94a12b368 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -49,7 +49,7 @@ struct CDiskTxPos : public CDiskBlockPos { template inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(*(CDiskBlockPos *)this); + READWRITE(*static_cast(this)); READWRITE(VARINT(nTxOffset)); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index c3c23d276..85511e3c8 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -346,7 +346,7 @@ class CWalletTx : public CMerkleTx { } } - READWRITE(*(CMerkleTx *)this); + READWRITE(*static_cast(this)); //!< Used to be vtxPrev std::vector vUnused; READWRITE(vUnused); From 15351602e11322f14fc164e9ada8a7e512aa2415 Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 27 Mar 2019 23:33:09 +0000 Subject: [PATCH 14/20] Add schnorr sign benchmark Summary: As per title. Depends on D2747. Test Plan: ./bench_sign Reviewers: O1 Bitcoin ABC, #bitcoin_abc, deadalnix, Fabien, jasonbcox Reviewed By: O1 Bitcoin ABC, #bitcoin_abc, Fabien, jasonbcox Subscribers: jasonbcox, Fabien, schancel Differential Revision: https://reviews.bitcoinabc.org/D2748 --- src/secp256k1/src/bench_sign.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c index 544b43963..e69ec1955 100644 --- a/src/secp256k1/src/bench_sign.c +++ b/src/secp256k1/src/bench_sign.c @@ -8,6 +8,11 @@ #include "util.h" #include "bench.h" +#ifdef ENABLE_MODULE_SCHNORR +#include "include/secp256k1_schnorr.h" +#endif + + typedef struct { secp256k1_context* ctx; unsigned char msg[32]; @@ -44,12 +49,31 @@ static void bench_sign_run(void* arg) { } } +#ifdef ENABLE_MODULE_SCHNORR +static void bench_schnorr_sign_run(void* arg) { + int i,j; + bench_sign *data = (bench_sign*)arg; + + unsigned char sig[64]; + for (i = 0; i < 20000; i++) { + CHECK(secp256k1_schnorr_sign(data->ctx, sig, data->msg, data->key, NULL, NULL)); + for (j = 0; j < 32; j++) { + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; + } + } +} +#endif + int main(void) { bench_sign data; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, 20000); +#ifdef ENABLE_MODULE_SCHNORR + run_benchmark("schnorr_sign", bench_schnorr_sign_run, bench_sign_setup, NULL, &data, 10, 20000); +#endif secp256k1_context_destroy(data.ctx); return 0; From b0b7f96ece64865daff620b3117ce65b2e2a468a Mon Sep 17 00:00:00 2001 From: Florian Date: Wed, 27 Mar 2019 23:46:29 +0000 Subject: [PATCH 15/20] Add schnorr verify benchmark Summary: As per title. Depends on D2747. Test Plan: ./bench_verify Reviewers: O1 Bitcoin ABC, #bitcoin_abc, deadalnix, Fabien, jasonbcox Reviewed By: O1 Bitcoin ABC, #bitcoin_abc, Fabien, jasonbcox Subscribers: jasonbcox, Fabien, schancel Differential Revision: https://reviews.bitcoinabc.org/D2749 --- src/secp256k1/src/bench_verify.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c index 418defa0a..667614bb7 100644 --- a/src/secp256k1/src/bench_verify.c +++ b/src/secp256k1/src/bench_verify.c @@ -11,6 +11,10 @@ #include "util.h" #include "bench.h" +#ifdef ENABLE_MODULE_SCHNORR +#include "include/secp256k1_schnorr.h" +#endif + #ifdef ENABLE_OPENSSL_TESTS #include #include @@ -79,6 +83,25 @@ static void benchmark_verify_openssl(void* arg) { } #endif +#ifdef ENABLE_MODULE_SCHNORR +static void benchmark_schnorr_verify(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_pubkey pubkey; + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_schnorr_verify(data->ctx, data->sig, data->msg, &pubkey) == (i == 0)); + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} +#endif + int main(void) { int i; secp256k1_pubkey pubkey; @@ -106,6 +129,11 @@ int main(void) { run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000); EC_GROUP_free(data.ec_group); #endif +#ifdef ENABLE_MODULE_SCHNORR + CHECK(secp256k1_schnorr_sign(data.ctx, data.sig, data.msg, data.key, NULL, NULL)); + data.siglen = 64; + run_benchmark("schnorr_verify", benchmark_schnorr_verify, NULL, NULL, &data, 10, 20000); +#endif secp256k1_context_destroy(data.ctx); return 0; From 2b6875c536a0370a721b7e8e99002e3f9d78dd95 Mon Sep 17 00:00:00 2001 From: Fabien Date: Tue, 2 Apr 2019 08:40:01 +0000 Subject: [PATCH 16/20] Update wallet_listsinceblock.py to use signrawtransactionwithwallet rpc Summary: This has been added before D2009 gets landed, it needs to be updated as `signrawtransaction` is going to get deprecated in favor of `signrawtransactionwithwallet` and `signrawtransactionwithkey`. Test Plan: ./test/functional/test_runner.py wallet_listsinceblock Reviewers: #bitcoin_abc, deadalnix, jasonbcox Reviewed By: #bitcoin_abc, jasonbcox Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2763 --- test/functional/wallet_listsinceblock.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py index 8b8517713..315474d72 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -160,7 +160,7 @@ def test_double_spend(self): 'vout': utxo['vout'], }] txid1 = self.nodes[1].sendrawtransaction( - self.nodes[1].signrawtransaction( + self.nodes[1].signrawtransactionwithwallet( self.nodes[1].createrawtransaction(utxoDicts, recipientDict))['hex']) # send from nodes[2] using utxo to nodes[3] @@ -169,7 +169,7 @@ def test_double_spend(self): self.nodes[2].getnewaddress(): change, } self.nodes[2].sendrawtransaction( - self.nodes[2].signrawtransaction( + self.nodes[2].signrawtransactionwithwallet( self.nodes[2].createrawtransaction(utxoDicts, recipientDict2))['hex']) # generate on both sides @@ -236,7 +236,7 @@ def test_double_send(self): 'txid': utxo['txid'], 'vout': utxo['vout'], }] - signedtxres = self.nodes[2].signrawtransaction( + signedtxres = self.nodes[2].signrawtransactionwithwallet( self.nodes[2].createrawtransaction(utxoDicts, recipientDict)) assert signedtxres['complete'] From 62ba08288e592e92a7e76cf41be8bcc904f4d9a0 Mon Sep 17 00:00:00 2001 From: Fabien Date: Mon, 11 Feb 2019 13:48:45 +0100 Subject: [PATCH 17/20] [Target v0.19] Deprecate and add test for signrawtransaction Summary: Deprecate signrawtransaction (target is v0.19). Backport 3/3 of core PR10579 (part of commit d602348 + deprecation from 1e79c05) Depends on D2763 Completes task T438 Test Plan: make check ./test/functional/test_runner.py --extended Reviewers: #bitcoin_abc, jasonbcox, deadalnix Reviewed By: #bitcoin_abc, jasonbcox, deadalnix Subscribers: deadalnix, teamcity Differential Revision: https://reviews.bitcoinabc.org/D2009 --- doc/release-notes.md | 3 +++ src/rpc/rawtransaction.cpp | 14 +++++++++++++- test/functional/rpc_signrawtransaction.py | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index a6e4950d6..978958699 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -34,3 +34,6 @@ Bitcoin-ABC 19.x backports: - Added optional `blockhash` parameter to `getrawtransaction` to narrowly search for a transaction within a given block. New returned field `in_active_chain` will indicate if that block is part of the active chain. + - `signrawtransaction` RPC is now deprecated. The new RPCs + `signrawtransactionwithkey` and `signrawtransactionwithwallet` should + be used instead. diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 36a3af1ac..643a11fb5 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1111,7 +1111,8 @@ static UniValue signrawtransaction(const Config &config, "[{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\"," "\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype " ")\n" - "\nSign inputs for raw transaction (serialized, hex-encoded).\n" + "\nDEPRECATED.Sign inputs for raw transaction (serialized, " + "hex-encoded).\n" "The second optional argument (may be null) is an array of " "previous transaction outputs that\n" "this transaction depends on but may not yet be in the block " @@ -1190,6 +1191,17 @@ static UniValue signrawtransaction(const Config &config, HelpExampleRpc("signrawtransaction", "\"myhex\"")); } + if (!IsDeprecatedRPCEnabled(gArgs, "signrawtransaction")) { + throw JSONRPCError( + RPC_METHOD_DEPRECATED, + "signrawtransaction is deprecated and will be fully removed in " + "v0.20. " + "To use signrawtransaction in v0.19, restart bitcoind with " + "-deprecatedrpc=signrawtransaction.\n" + "Projects should transition to using signrawtransactionwithkey and " + "signrawtransactionwithwallet before upgrading to v0.20"); + } + RPCTypeCheck( request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index bb5e1b5ed..df9634f0f 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -12,6 +12,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 + self.extra_args = [["-deprecatedrpc=signrawtransaction"]] def successful_signing_test(self): """Creates and signs a valid raw transaction with one input. From af4f8fee91c6f5ca5b8aaa8e9e5980f9efecc633 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 4 Apr 2019 12:08:28 -0700 Subject: [PATCH 18/20] Document method for reviewers to verify chainTxData Summary: This commit adds the final block hash of the window to getchaintxstats and documents how reviewers can verify changes to chainTxData. Backport of PR12317: https://github.com/bitcoin/bitcoin/pull/12317/ Completes T566. Test Plan: make check test_runner.py rpc_blockchain Reviewers: jasonbcox, deadalnix, Fabien, O1 Bitcoin ABC, #bitcoin_abc Reviewed By: jasonbcox, Fabien, O1 Bitcoin ABC, #bitcoin_abc Subscribers: teamcity, schancel Differential Revision: https://reviews.bitcoinabc.org/D2711 --- src/rpc/blockchain.cpp | 29 ++++++++++++++++------------- test/functional/rpc_blockchain.py | 12 +++++++++--- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 1a8d5d957..928e3a3a3 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1707,20 +1707,22 @@ UniValue getchaintxstats(const Config &config, const JSONRPCRequest &request) { "ends the window.\n" "\nResult:\n" "{\n" - " \"time\": xxxxx, (numeric) The timestamp for the " - "final block in the window in UNIX format.\n" - " \"txcount\": xxxxx, (numeric) The total number of " - "transactions in the chain up to that point.\n" - " \"window_block_count\": xxxxx, (numeric) Size of the window in " - "number of blocks.\n" - " \"window_tx_count\": xxxxx, (numeric) The number of " - "transactions in the window. Only returned if " + " \"time\": xxxxx, (numeric) The " + "timestamp for the final block in the window in UNIX format.\n" + " \"txcount\": xxxxx, (numeric) The total " + "number of transactions in the chain up to that point.\n" + " \"window_final_block_hash\": \"...\", (string) The hash of " + "the final block in the window.\n" + " \"window_block_count\": xxxxx, (numeric) Size of " + "the window in number of blocks.\n" + " \"window_tx_count\": xxxxx, (numeric) The number " + "of transactions in the window. Only returned if " "\"window_block_count\" is > 0.\n" - " \"window_interval\": xxxxx, (numeric) The elapsed time in " - "the window in seconds. Only returned if \"window_block_count\" is " - "> 0.\n" - " \"txrate\": x.xx, (numeric) The average rate of " - "transactions per second in the window. Only returned if " + " \"window_interval\": xxxxx, (numeric) The elapsed " + "time in the window in seconds. Only returned if " + "\"window_block_count\" is > 0.\n" + " \"txrate\": x.xx, (numeric) The average " + "rate of transactions per second in the window. Only returned if " "\"window_interval\" is > 0.\n" "}\n" "\nExamples:\n" + @@ -1782,6 +1784,7 @@ UniValue getchaintxstats(const Config &config, const JSONRPCRequest &request) { UniValue ret(UniValue::VOBJ); ret.pushKV("time", int64_t(pindex->nTime)); ret.pushKV("txcount", int64_t(pindex->nChainTx)); + ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex()); ret.pushKV("window_block_count", blockcount); if (blockcount > 0) { ret.pushKV("window_tx_count", nTxDiff); diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index a33a5034b..12fed6b54 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -77,6 +77,8 @@ def _test_getblockchaininfo(self): assert_equal(sorted(res.keys()), keys) def _test_getchaintxstats(self): + self.log.info("Test getchaintxstats") + chaintxstats = self.nodes[0].getchaintxstats(1) # 200 txs plus genesis tx assert_equal(chaintxstats['txcount'], 201) @@ -84,22 +86,26 @@ def _test_getchaintxstats(self): # we have to round because of binary math assert_equal(round(chaintxstats['txrate'] * 600, 10), Decimal(1)) - b1 = self.nodes[0].getblock(self.nodes[0].getblockhash(1)) - b200 = self.nodes[0].getblock(self.nodes[0].getblockhash(200)) + b1_hash = self.nodes[0].getblockhash(1) + b1 = self.nodes[0].getblock(b1_hash) + b200_hash = self.nodes[0].getblockhash(200) + b200 = self.nodes[0].getblock(b200_hash) time_diff = b200['mediantime'] - b1['mediantime'] chaintxstats = self.nodes[0].getchaintxstats() assert_equal(chaintxstats['time'], b200['time']) assert_equal(chaintxstats['txcount'], 201) + assert_equal(chaintxstats['window_final_block_hash'], b200_hash) assert_equal(chaintxstats['window_block_count'], 199) assert_equal(chaintxstats['window_tx_count'], 199) assert_equal(chaintxstats['window_interval'], time_diff) assert_equal( round(chaintxstats['txrate'] * time_diff, 10), Decimal(199)) - chaintxstats = self.nodes[0].getchaintxstats(blockhash=b1['hash']) + chaintxstats = self.nodes[0].getchaintxstats(blockhash=b1_hash) assert_equal(chaintxstats['time'], b1['time']) assert_equal(chaintxstats['txcount'], 2) + assert_equal(chaintxstats['window_final_block_hash'], b1_hash) assert_equal(chaintxstats['window_block_count'], 0) assert('window_tx_count' not in chaintxstats) assert('window_interval' not in chaintxstats) From 86b2afb8195e090cc4326b736ec56a4f40ccb67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Thu, 4 Apr 2019 12:16:12 -0700 Subject: [PATCH 19/20] qa: Improve getchaintxstats functional test Summary: Completes T561. Depends on D2711. Backport of PR12083 https://github.com/bitcoin/bitcoin/pull/12083/files Test Plan: make check test_runner.py Reviewers: Fabien, deadalnix, O1 Bitcoin ABC, #bitcoin_abc, nakihito Reviewed By: Fabien, O1 Bitcoin ABC, #bitcoin_abc Subscribers: teamcity, schancel Differential Revision: https://reviews.bitcoinabc.org/D2702 --- src/rpc/blockchain.cpp | 33 ++++++++++++------------------- test/functional/rpc_blockchain.py | 27 +++++++++++++++++++++---- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 928e3a3a3..20a1cf32c 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1736,27 +1736,20 @@ UniValue getchaintxstats(const Config &config, const JSONRPCRequest &request) { int blockcount = 30 * 24 * 60 * 60 / config.GetChainParams().GetConsensus().nPowTargetSpacing; - bool havehash = !request.params[1].isNull(); - uint256 hash; - if (havehash) { - hash = uint256S(request.params[1].get_str()); - } - - { + if (request.params[1].isNull()) { LOCK(cs_main); - if (havehash) { - auto it = mapBlockIndex.find(hash); - if (it == mapBlockIndex.end()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Block not found"); - } - pindex = it->second; - if (!chainActive.Contains(pindex)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, - "Block is not in main chain"); - } - } else { - pindex = chainActive.Tip(); + pindex = chainActive.Tip(); + } else { + uint256 hash = uint256S(request.params[1].get_str()); + LOCK(cs_main); + auto it = mapBlockIndex.find(hash); + if (it == mapBlockIndex.end()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + pindex = it->second; + if (!chainActive.Contains(pindex)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, + "Block is not in main chain"); } } diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 12fed6b54..550c6ce57 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -79,6 +79,29 @@ def _test_getblockchaininfo(self): def _test_getchaintxstats(self): self.log.info("Test getchaintxstats") + # Test `getchaintxstats` invalid extra parameters + assert_raises_rpc_error( + -1, 'getchaintxstats', self.nodes[0].getchaintxstats, 0, '', 0) + + # Test `getchaintxstats` invalid `nblocks` + assert_raises_rpc_error( + -1, "JSON value is not an integer as expected", self.nodes[0].getchaintxstats, '') + assert_raises_rpc_error( + -8, "Invalid block count: should be between 0 and the block's height - 1", self.nodes[0].getchaintxstats, -1) + assert_raises_rpc_error(-8, "Invalid block count: should be between 0 and the block's height - 1", self.nodes[ + 0].getchaintxstats, self.nodes[0].getblockcount()) + + # Test `getchaintxstats` invalid `blockhash` + assert_raises_rpc_error( + -1, "JSON value is not a string as expected", self.nodes[0].getchaintxstats, blockhash=0) + assert_raises_rpc_error( + -5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0') + blockhash = self.nodes[0].getblockhash(200) + self.nodes[0].invalidateblock(blockhash) + assert_raises_rpc_error( + -8, "Block is not in main chain", self.nodes[0].getchaintxstats, blockhash=blockhash) + self.nodes[0].reconsiderblock(blockhash) + chaintxstats = self.nodes[0].getchaintxstats(1) # 200 txs plus genesis tx assert_equal(chaintxstats['txcount'], 201) @@ -111,10 +134,6 @@ def _test_getchaintxstats(self): assert('window_interval' not in chaintxstats) assert('txrate' not in chaintxstats) - assert_raises_rpc_error( - -8, "Invalid block count: should be between 0 and the block's height - 1", - self.nodes[0].getchaintxstats, 201) - def _test_gettxoutsetinfo(self): node = self.nodes[0] res = node.gettxoutsetinfo() From 5046a6317d721aef1e244e3d4170d1b057c17d96 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Mon, 12 Feb 2018 15:48:37 +0100 Subject: [PATCH 20/20] Fix Windows build errors introduced in D2765 Summary: See core issue #12386: https://github.com/bitcoin/bitcoin/issues/12386 Backport of core PR12416 Test Plan: make check Build the windows binaries Reviewers: #bitcoin_abc, deadalnix, jasonbcox Reviewed By: #bitcoin_abc, jasonbcox Subscribers: schancel Differential Revision: https://reviews.bitcoinabc.org/D2779 --- src/qt/bitcoin.cpp | 2 +- src/qt/winshutdownmonitor.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 80633f4fa..c1f0d4ca3 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -782,7 +782,7 @@ int main(int argc, char *argv[]) { WinShutdownMonitor::registerShutdownBlockReason( QObject::tr("%1 didn't yet exit safely...") .arg(QObject::tr(PACKAGE_NAME)), - static_cast(app.getMainWinId())); + (HWND)app.getMainWinId()); #endif app.exec(); app.requestShutdown(config); diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp index 0c51cf991..7962e6351 100644 --- a/src/qt/winshutdownmonitor.cpp +++ b/src/qt/winshutdownmonitor.cpp @@ -56,9 +56,8 @@ bool WinShutdownMonitor::nativeEventFilter(const QByteArray &eventType, void WinShutdownMonitor::registerShutdownBlockReason(const QString &strReason, const HWND &mainWinId) { typedef BOOL(WINAPI * PSHUTDOWNBRCREATE)(HWND, LPCWSTR); - PSHUTDOWNBRCREATE shutdownBRCreate = - static_cast(GetProcAddress( - GetModuleHandleA("User32.dll"), "ShutdownBlockReasonCreate")); + PSHUTDOWNBRCREATE shutdownBRCreate = (PSHUTDOWNBRCREATE)GetProcAddress( + GetModuleHandleA("User32.dll"), "ShutdownBlockReasonCreate"); if (shutdownBRCreate == nullptr) { qWarning() << "registerShutdownBlockReason: GetProcAddress for " "ShutdownBlockReasonCreate failed";