diff options
-rw-r--r-- | doc/release-process.md | 6 | ||||
-rwxr-xr-x | qa/rpc-tests/keypool.py | 10 | ||||
-rwxr-xr-x | qa/rpc-tests/p2p-segwit.py | 78 | ||||
-rwxr-xr-x | qa/rpc-tests/wallet-hd.py | 2 | ||||
-rw-r--r-- | src/indirectmap.h | 4 | ||||
-rw-r--r-- | src/init.cpp | 2 | ||||
-rw-r--r-- | src/key.h | 31 | ||||
-rw-r--r-- | src/main.cpp | 10 | ||||
-rw-r--r-- | src/main.h | 2 | ||||
-rw-r--r-- | src/miner.cpp | 2 | ||||
-rw-r--r-- | src/policy/policy.cpp | 19 | ||||
-rw-r--r-- | src/policy/policy.h | 12 | ||||
-rw-r--r-- | src/primitives/transaction.h | 8 | ||||
-rw-r--r-- | src/pubkey.h | 11 | ||||
-rw-r--r-- | src/qt/optionsmodel.cpp | 21 | ||||
-rw-r--r-- | src/qt/optionsmodel.h | 4 | ||||
-rw-r--r-- | src/txmempool.cpp | 2 | ||||
-rw-r--r-- | src/wallet/rpcdump.cpp | 29 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 24 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 52 | ||||
-rw-r--r-- | src/wallet/wallet.h | 7 |
21 files changed, 261 insertions, 75 deletions
diff --git a/doc/release-process.md b/doc/release-process.md index 35ee1edae1..41c1ac8556 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -112,16 +112,16 @@ The gbuild invocations below <b>DO NOT DO THIS</b> by default. ### Build and sign Bitcoin Core for Linux, Windows, and OS X: pushd ./gitian-builder - ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gbuild --memory 3000 --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../ - ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml + ./bin/gbuild --memory 3000 --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win.yml mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../ - ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml + ./bin/gbuild --memory 3000 --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../ diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py index c75303ecbf..fa39476568 100755 --- a/qa/rpc-tests/keypool.py +++ b/qa/rpc-tests/keypool.py @@ -12,6 +12,11 @@ class KeyPoolTest(BitcoinTestFramework): def run_test(self): nodes = self.nodes + addr_before_encrypting = nodes[0].getnewaddress() + addr_before_encrypting_data = nodes[0].validateaddress(addr_before_encrypting) + wallet_info_old = nodes[0].getwalletinfo() + assert(addr_before_encrypting_data['hdmasterkeyid'] == wallet_info_old['hdmasterkeyid']) + # Encrypt wallet and wait to terminate nodes[0].encryptwallet('test') bitcoind_processes[0].wait() @@ -19,6 +24,11 @@ class KeyPoolTest(BitcoinTestFramework): nodes[0] = start_node(0, self.options.tmpdir) # Keep creating keys addr = nodes[0].getnewaddress() + addr_data = nodes[0].validateaddress(addr) + wallet_info = nodes[0].getwalletinfo() + assert(addr_before_encrypting_data['hdmasterkeyid'] != wallet_info['hdmasterkeyid']) + assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid']) + try: addr = nodes[0].getnewaddress() raise AssertionError('Keypool should be exhausted after one address') diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py index fa2c5d1f05..cd02692b1e 100755 --- a/qa/rpc-tests/p2p-segwit.py +++ b/qa/rpc-tests/p2p-segwit.py @@ -1086,6 +1086,82 @@ class SegWitTest(BitcoinTestFramework): self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0]) assert(block4.sha256 not in self.old_node.getdataset) + # V0 segwit outputs should be standard after activation, but not before. + def test_standardness_v0(self, segwit_activated): + print("\tTesting standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before")) + assert(len(self.utxo)) + + witness_program = CScript([OP_TRUE]) + witness_hash = sha256(witness_program) + scriptPubKey = CScript([OP_0, witness_hash]) + + p2sh_pubkey = hash160(witness_program) + p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL]) + + # First prepare a p2sh output (so that spending it will pass standardness) + p2sh_tx = CTransaction() + p2sh_tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")] + p2sh_tx.vout = [CTxOut(self.utxo[0].nValue-1000, p2sh_scriptPubKey)] + p2sh_tx.rehash() + + # Mine it on test_node to create the confirmed output. + self.test_node.test_transaction_acceptance(p2sh_tx, with_witness=True, accepted=True) + self.nodes[0].generate(1) + sync_blocks(self.nodes) + + # Now test standardness of v0 P2WSH outputs. + # Start by creating a transaction with two outputs. + tx = CTransaction() + tx.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))] + tx.vout = [CTxOut(p2sh_tx.vout[0].nValue-10000, scriptPubKey)] + tx.vout.append(CTxOut(8000, scriptPubKey)) # Might burn this later + tx.rehash() + + self.std_node.test_transaction_acceptance(tx, with_witness=True, accepted=segwit_activated) + + # Now create something that looks like a P2PKH output. This won't be spendable. + scriptPubKey = CScript([OP_0, hash160(witness_hash)]) + tx2 = CTransaction() + if segwit_activated: + # if tx was accepted, then we spend the second output. + tx2.vin = [CTxIn(COutPoint(tx.sha256, 1), b"")] + tx2.vout = [CTxOut(7000, scriptPubKey)] + tx2.wit.vtxinwit.append(CTxInWitness()) + tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program] + else: + # if tx wasn't accepted, we just re-spend the p2sh output we started with. + tx2.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))] + tx2.vout = [CTxOut(p2sh_tx.vout[0].nValue-1000, scriptPubKey)] + tx2.rehash() + + self.std_node.test_transaction_acceptance(tx2, with_witness=True, accepted=segwit_activated) + + # Now update self.utxo for later tests. + tx3 = CTransaction() + if segwit_activated: + # tx and tx2 were both accepted. Don't bother trying to reclaim the + # P2PKH output; just send tx's first output back to an anyone-can-spend. + sync_mempools(self.nodes) + tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")] + tx3.vout = [CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE]))] + tx3.wit.vtxinwit.append(CTxInWitness()) + tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program] + tx3.rehash() + self.test_node.test_transaction_acceptance(tx3, with_witness=True, accepted=True) + else: + # tx and tx2 didn't go anywhere; just clean up the p2sh_tx output. + tx3.vin = [CTxIn(COutPoint(p2sh_tx.sha256, 0), CScript([witness_program]))] + tx3.vout = [CTxOut(p2sh_tx.vout[0].nValue-1000, witness_program)] + tx3.rehash() + self.test_node.test_transaction_acceptance(tx3, with_witness=True, accepted=True) + + self.nodes[0].generate(1) + sync_blocks(self.nodes) + self.utxo.pop(0) + self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue)) + assert_equal(len(self.nodes[1].getrawmempool()), 0) + + # Verify that future segwit upgraded transactions are non-standard, # but valid in blocks. Can run this before and after segwit activation. def test_segwit_versions(self): @@ -1658,6 +1734,7 @@ class SegWitTest(BitcoinTestFramework): self.test_witness_tx_relay_before_segwit_activation() self.test_block_relay(segwit_activated=False) self.test_p2sh_witness(segwit_activated=False) + self.test_standardness_v0(segwit_activated=False) sync_blocks(self.nodes) @@ -1679,6 +1756,7 @@ class SegWitTest(BitcoinTestFramework): self.test_witness_input_length() self.test_block_relay(segwit_activated=True) self.test_tx_relay_after_segwit_activation() + self.test_standardness_v0(segwit_activated=True) self.test_segwit_versions() self.test_premature_coinbase_witness_spend() self.test_signature_version_1() diff --git a/qa/rpc-tests/wallet-hd.py b/qa/rpc-tests/wallet-hd.py index c738ee2207..c11da1e9a9 100755 --- a/qa/rpc-tests/wallet-hd.py +++ b/qa/rpc-tests/wallet-hd.py @@ -31,7 +31,7 @@ class WalletHDTest(BitcoinTestFramework): tmpdir = self.options.tmpdir # Make sure we use hd, keep masterkeyid - masterkeyid = self.nodes[1].getwalletinfo()['masterkeyid'] + masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid'] assert_equal(len(masterkeyid), 40) # Import a non-HD private key in the HD wallet diff --git a/src/indirectmap.h b/src/indirectmap.h index 28e1e8dedd..76da4a6bd5 100644 --- a/src/indirectmap.h +++ b/src/indirectmap.h @@ -1,3 +1,7 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef BITCOIN_INDIRECTMAP_H #define BITCOIN_INDIRECTMAP_H diff --git a/src/init.cpp b/src/init.cpp index 312dfe1699..8d4a2cafbf 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -446,7 +446,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Node relay options:")); if (showDebug) strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard())); - strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); + strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(_("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT)); @@ -15,7 +15,7 @@ #include <vector> -/** +/** * secp256k1: * const unsigned int PRIVATE_KEY_SIZE = 279; * const unsigned int PUBLIC_KEY_SIZE = 65; @@ -45,6 +45,8 @@ private: //! The actual byte data unsigned char vch[32]; + static_assert(sizeof(vch) == 32, "vch must be 32 bytes in length to not break serialization"); + //! Check whether the 32-byte array pointed to be vch is valid keydata. bool static Check(const unsigned char* vch); @@ -70,20 +72,19 @@ public: friend bool operator==(const CKey& a, const CKey& b) { - return a.fCompressed == b.fCompressed && a.size() == b.size() && - memcmp(&a.vch[0], &b.vch[0], a.size()) == 0; + return a.fCompressed == b.fCompressed && + a.size() == b.size() && + memcmp(&a.vch[0], &b.vch[0], a.size()) == 0; } //! Initialize using begin and end iterators to byte data. template <typename T> void Set(const T pbegin, const T pend, bool fCompressedIn) { - if (pend - pbegin != 32) { + if (pend - pbegin != sizeof(vch)) { fValid = false; - return; - } - if (Check(&pbegin[0])) { - memcpy(vch, (unsigned char*)&pbegin[0], 32); + } else if (Check(&pbegin[0])) { + memcpy(vch, (unsigned char*)&pbegin[0], sizeof(vch)); fValid = true; fCompressed = fCompressedIn; } else { @@ -92,7 +93,7 @@ public: } //! Simple read-only vector-like interface. - unsigned int size() const { return (fValid ? 32 : 0); } + unsigned int size() const { return (fValid ? sizeof(vch) : 0); } const unsigned char* begin() const { return vch; } const unsigned char* end() const { return vch + size(); } @@ -110,7 +111,7 @@ public: /** * Convert the private key to a CPrivKey (serialized OpenSSL private key data). - * This is expensive. + * This is expensive. */ CPrivKey GetPrivKey() const; @@ -146,9 +147,6 @@ public: //! Load private key and check that public key matches. bool Load(CPrivKey& privkey, CPubKey& vchPubKey, bool fSkipCheck); - - //! Check whether an element of a signature (r or s) is valid. - static bool CheckSignatureElement(const unsigned char* vch, int len, bool half); }; struct CExtKey { @@ -160,8 +158,11 @@ struct CExtKey { friend bool operator==(const CExtKey& a, const CExtKey& b) { - return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild && - a.chaincode == b.chaincode && a.key == b.key; + return a.nDepth == b.nDepth && + memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && + a.nChild == b.nChild && + a.chaincode == b.chaincode && + a.key == b.key; } void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; diff --git a/src/main.cpp b/src/main.cpp index 124bc57e7d..8dd703b687 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,7 +74,6 @@ bool fHavePruned = false; bool fPruneMode = false; bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG; bool fRequireStandard = true; -unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; bool fCheckBlockIndex = false; bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; size_t nCoinCacheUsage = 5000 * 300; @@ -1144,13 +1143,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } // Reject transactions with witness before segregated witness activates (override with -prematurewitness) - if (!GetBoolArg("-prematurewitness",false) && !tx.wit.IsNull() && !IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus())) { + bool witnessEnabled = IsWitnessEnabled(chainActive.Tip(), Params().GetConsensus()); + if (!GetBoolArg("-prematurewitness",false) && !tx.wit.IsNull() && !witnessEnabled) { return state.DoS(0, false, REJECT_NONSTANDARD, "no-witness-yet", true); } // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; - if (fRequireStandard && !IsStandardTx(tx, reason)) + if (fRequireStandard && !IsStandardTx(tx, reason, witnessEnabled)) return state.DoS(0, false, REJECT_NONSTANDARD, reason); // Only accept nLockTime-using transactions that can be mined in the next @@ -1296,7 +1296,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than // merely non-standard transaction. - if ((nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST) || (nBytesPerSigOp && nSigOpsCost > nSize * WITNESS_SCALE_FACTOR / nBytesPerSigOp)) + if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST) return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, strprintf("%d", nSigOpsCost)); @@ -3567,7 +3567,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const CB // {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are // multiple, the last one is used. bool fHaveWitness = false; - if (IsWitnessEnabled(pindexPrev, consensusParams)) { + if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE) { int commitpos = GetWitnessCommitmentIndex(block); if (commitpos != -1) { bool malleated = false; diff --git a/src/main.h b/src/main.h index feaaaad750..26ea6adc6b 100644 --- a/src/main.h +++ b/src/main.h @@ -124,7 +124,6 @@ static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; /** Default for -permitbaremultisig */ static const bool DEFAULT_PERMIT_BAREMULTISIG = true; -static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; static const bool DEFAULT_CHECKPOINTS_ENABLED = true; static const bool DEFAULT_TXINDEX = false; static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100; @@ -165,7 +164,6 @@ extern int nScriptCheckThreads; extern bool fTxIndex; extern bool fIsBareMultisigStd; extern bool fRequireStandard; -extern unsigned int nBytesPerSigOp; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; extern size_t nCoinCacheUsage; diff --git a/src/miner.cpp b/src/miner.cpp index 25a5becf93..9575858840 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -187,7 +187,7 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; - pblocktemplate->vTxSigOpsCost[0] = GetLegacySigOpCount(pblock->vtx[0]); + pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 8617db00c8..48080abc77 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -31,7 +31,7 @@ * DUP CHECKSIG DROP ... repeated 100 times... OP_1 */ -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled) { std::vector<std::vector<unsigned char> > vSolutions; if (!Solver(scriptPubKey, whichType, vSolutions)) @@ -50,10 +50,13 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType) (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) return false; + else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH)) + return false; + return whichType != TX_NONSTANDARD; } -bool IsStandardTx(const CTransaction& tx, std::string& reason) +bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled) { if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) { reason = "version"; @@ -92,7 +95,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason) unsigned int nDataOut = 0; txnouttype whichType; BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (!::IsStandard(txout.scriptPubKey, whichType)) { + if (!::IsStandard(txout.scriptPubKey, whichType, witnessEnabled)) { reason = "scriptpubkey"; return false; } @@ -151,12 +154,14 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) return true; } -int64_t GetVirtualTransactionSize(int64_t nWeight) +unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; + +int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost) { - return (nWeight + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; + return (std::max(nWeight, nSigOpCost * nBytesPerSigOp) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR; } -int64_t GetVirtualTransactionSize(const CTransaction& tx) +int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost) { - return GetVirtualTransactionSize(GetTransactionWeight(tx)); + return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost); } diff --git a/src/policy/policy.h b/src/policy/policy.h index f5f8652fb5..6bf5ca0ee5 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -28,6 +28,8 @@ static const unsigned int MAX_P2SH_SIGOPS = 15; static const unsigned int MAX_STANDARD_TX_SIGOPS_COST = MAX_BLOCK_SIGOPS_COST/5; /** Default for -maxmempool, maximum megabytes of mempool memory usage */ static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300; +/** Default for -bytespersigop */ +static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; /** * Standard script verification flags that standard transactions will comply * with. However scripts violating these flags may still be present in valid @@ -53,12 +55,12 @@ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_ static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST; -bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); +bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled = false); /** * Check for standard transaction types * @return True if all outputs (scriptPubKeys) use only standard transaction forms */ -bool IsStandardTx(const CTransaction& tx, std::string& reason); +bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled = false); /** * Check for standard transaction types * @param[in] mapInputs Map of previous transactions that have outputs we're spending @@ -66,8 +68,10 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason); */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); +extern unsigned int nBytesPerSigOp; + /** Compute the virtual transaction size (weight reinterpreted as bytes). */ -int64_t GetVirtualTransactionSize(int64_t nWeight); -int64_t GetVirtualTransactionSize(const CTransaction& tx); +int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost); +int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0); #endif // BITCOIN_POLICY_POLICY_H diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index d37890667f..5689d15bf7 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -290,6 +290,8 @@ struct CMutableTransaction; */ template<typename Stream, typename Operation, typename TxType> inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, int nType, int nVersion) { + const bool fAllowWitness = !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS); + READWRITE(*const_cast<int32_t*>(&tx.nVersion)); unsigned char flags = 0; if (ser_action.ForRead()) { @@ -298,7 +300,7 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in const_cast<CTxWitness*>(&tx.wit)->SetNull(); /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */ READWRITE(*const_cast<std::vector<CTxIn>*>(&tx.vin)); - if (tx.vin.size() == 0 && !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) { + if (tx.vin.size() == 0 && fAllowWitness) { /* We read a dummy or an empty vin. */ READWRITE(flags); if (flags != 0) { @@ -309,7 +311,7 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in /* We read a non-empty vin. Assume a normal vout follows. */ READWRITE(*const_cast<std::vector<CTxOut>*>(&tx.vout)); } - if ((flags & 1) && !(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) { + if ((flags & 1) && fAllowWitness) { /* The witness flag is present, and we support witnesses. */ flags ^= 1; const_cast<CTxWitness*>(&tx.wit)->vtxinwit.resize(tx.vin.size()); @@ -322,7 +324,7 @@ inline void SerializeTransaction(TxType& tx, Stream& s, Operation ser_action, in } else { // Consistency check assert(tx.wit.vtxinwit.size() <= tx.vin.size()); - if (!(nVersion & SERIALIZE_TRANSACTION_NO_WITNESS)) { + if (fAllowWitness) { /* Check whether witnesses need to be serialized. */ if (!tx.wit.IsNull()) { flags |= 1; diff --git a/src/pubkey.h b/src/pubkey.h index db5444ea9d..aebfdbc826 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -13,7 +13,7 @@ #include <stdexcept> #include <vector> -/** +/** * secp256k1: * const unsigned int PRIVATE_KEY_SIZE = 279; * const unsigned int PUBLIC_KEY_SIZE = 65; @@ -156,7 +156,7 @@ public: /* * Check syntactic correctness. - * + * * Note that this is consensus critical as CheckSig() calls it! */ bool IsValid() const @@ -203,8 +203,11 @@ struct CExtPubKey { friend bool operator==(const CExtPubKey &a, const CExtPubKey &b) { - return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], 4) == 0 && a.nChild == b.nChild && - a.chaincode == b.chaincode && a.pubkey == b.pubkey; + return a.nDepth == b.nDepth && + memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && + a.nChild == b.nChild && + a.chaincode == b.chaincode && + a.pubkey == b.pubkey; } void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index cc2cbc0e66..684db71a8c 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -43,6 +43,8 @@ void OptionsModel::Init(bool resetSettings) if (resetSettings) Reset(); + checkAndMigrate(); + QSettings settings; // Ensure restart flag is unset on client startup @@ -429,3 +431,22 @@ bool OptionsModel::isRestartRequired() QSettings settings; return settings.value("fRestartRequired", false).toBool(); } + +void OptionsModel::checkAndMigrate() +{ + // Migration of default values + // Check if the QSettings container was already loaded with this client version + QSettings settings; + static const char strSettingsVersionKey[] = "nSettingsVersion"; + int settingsVersion = settings.contains(strSettingsVersionKey) ? settings.value(strSettingsVersionKey).toInt() : 0; + if (settingsVersion < CLIENT_VERSION) + { + // -dbcache was bumped from 100 to 300 in 0.13 + // see https://github.com/bitcoin/bitcoin/pull/8273 + // force people to upgrade to the new value if they are using 100MB + if (settingsVersion < 130000 && settings.contains("nDatabaseCache") && settings.value("nDatabaseCache").toLongLong() == 100) + settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache); + + settings.setValue(strSettingsVersionKey, CLIENT_VERSION); + } +}
\ No newline at end of file diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 3b491ceac2..b23b5f2607 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -84,9 +84,11 @@ private: /* settings that were overriden by command-line */ QString strOverriddenByCommandLine; - /// Add option to list of GUI options overridden through command line/config file + // Add option to list of GUI options overridden through command line/config file void addOverriddenOption(const std::string &option); + // Check settings version and upgrade default values if required + void checkAndMigrate(); Q_SIGNALS: void displayUnitChanged(int unit); void coinControlFeaturesChanged(bool); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 691baa6744..82827b8e4f 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -75,7 +75,7 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp) size_t CTxMemPoolEntry::GetTxSize() const { - return GetVirtualTransactionSize(nTxWeight); + return GetVirtualTransactionSize(nTxWeight, sigOpCost); } // Update the given tx for any in-mempool descendants. diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index d55cc68dc0..6647d3297f 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -602,19 +602,42 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString()); file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime())); file << "\n"; + + // add the base58check encoded extended master if the wallet uses HD + CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID; + if (!masterKeyID.IsNull()) + { + CKey key; + if (pwalletMain->GetKey(masterKeyID, key)) + { + CExtKey masterKey; + masterKey.SetMaster(key.begin(), key.size()); + + CBitcoinExtKey b58extkey; + b58extkey.SetKey(masterKey); + + file << "# extended private masterkey: " << b58extkey.ToString() << "\n\n"; + } + } for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { const CKeyID &keyid = it->second; std::string strTime = EncodeDumpTime(it->first); std::string strAddr = CBitcoinAddress(keyid).ToString(); CKey key; if (pwalletMain->GetKey(keyid, key)) { + file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime); if (pwalletMain->mapAddressBook.count(keyid)) { - file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr); + file << strprintf("label=%s", EncodeDumpString(pwalletMain->mapAddressBook[keyid].name)); + } else if (keyid == masterKeyID) { + file << "hdmaster=1"; } else if (setKeyPool.count(keyid)) { - file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); + file << "reserve=1"; + } else if (pwalletMain->mapKeyMetadata[keyid].hdKeypath == "m") { + file << "inactivehdmaster=1"; } else { - file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); + file << "change=1"; } + file << strprintf(" # addr=%s%s\n", strAddr, (pwalletMain->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? " hdkeypath="+pwalletMain->mapKeyMetadata[keyid].hdKeypath : "")); } } file << "\n"; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b4831ad795..a90807e514 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2081,7 +2081,7 @@ UniValue encryptwallet(const UniValue& params, bool fHelp) // slack space in .dat files; that is bad if the old data is // unencrypted private keys. So: StartShutdown(); - return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; + return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup."; } UniValue lockunspent(const UniValue& params, bool fHelp) @@ -2260,16 +2260,16 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) "Returns an object containing various wallet state info.\n" "\nResult:\n" "{\n" - " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n" - " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n" - " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n" - " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n" - " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" - " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" - " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" - " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n" - " \"masterkeyid\": \"<hash160>\", (string) the Hash160 of the HD master pubkey\n" + " \"walletversion\": xxxxx, (numeric) the wallet version\n" + " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n" + " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n" + " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n" + " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n" + " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" + " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" + " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" + " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n" + " \"hdmasterkeyid\": \"<hash160>\", (string) the Hash160 of the HD master pubkey\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") @@ -2291,7 +2291,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID; if (!masterKeyID.IsNull()) - obj.push_back(Pair("masterkeyid", masterKeyID.GetHex())); + obj.push_back(Pair("hdmasterkeyid", masterKeyID.GetHex())); return obj; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5908dfeace..e5ee5063a5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -626,6 +626,15 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) Lock(); Unlock(strWalletPassphrase); + + // if we are using HD, replace the HD master key (seed) with a new one + if (!hdChain.masterKeyID.IsNull()) { + CKey key; + CPubKey masterPubKey = GenerateNewHDMasterKey(); + if (!SetHDMasterKey(masterPubKey)) + return false; + } + NewKeyPool(); Lock(); @@ -1166,20 +1175,43 @@ CAmount CWallet::GetChange(const CTransaction& tx) const return nChange; } -bool CWallet::SetHDMasterKey(const CKey& key) +CPubKey CWallet::GenerateNewHDMasterKey() +{ + CKey key; + key.MakeNewKey(true); + + int64_t nCreationTime = GetTime(); + CKeyMetadata metadata(nCreationTime); + + // calculate the pubkey + CPubKey pubkey = key.GetPubKey(); + assert(key.VerifyPubKey(pubkey)); + + // set the hd keypath to "m" -> Master, refers the masterkeyid to itself + metadata.hdKeypath = "m"; + metadata.hdMasterKeyID = pubkey.GetID(); + + { + LOCK(cs_wallet); + + // mem store the metadata + mapKeyMetadata[pubkey.GetID()] = metadata; + + // write the key&metadata to the database + if (!AddKeyPubKey(key, pubkey)) + throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed"); + } + + return pubkey; +} + +bool CWallet::SetHDMasterKey(const CPubKey& pubkey) { LOCK(cs_wallet); // ensure this wallet.dat can only be opened by clients supporting HD SetMinVersion(FEATURE_HD); - // store the key as normal "key"/"ckey" object - // in the database - // key metadata is not required - CPubKey pubkey = key.GetPubKey(); - if (!AddKeyPubKey(key, pubkey)) - throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed"); - // store the keyid (hash160) together with // the child index counter in the database // as a hdchain object @@ -3299,8 +3331,8 @@ bool CWallet::InitLoadWallet() if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && walletInstance->hdChain.masterKeyID.IsNull()) { // generate a new master key CKey key; - key.MakeNewKey(true); - if (!walletInstance->SetHDMasterKey(key)) + CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey(); + if (!walletInstance->SetHDMasterKey(masterPubKey)) throw std::runtime_error("CWallet::GenerateNewKey(): Storing master key failed"); } CPubKey newDefaultKey; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 3a3cb6d851..0c95fdf4b0 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -899,10 +899,13 @@ public: /* Set the HD chain model (chain child index counters) */ bool SetHDChain(const CHDChain& chain, bool memonly); + const CHDChain& GetHDChain() { return hdChain; } + /* Generates a new HD master key (will not be activated) */ + CPubKey GenerateNewHDMasterKey(); + /* Set the current HD master key (will reset the chain child index counters) */ - bool SetHDMasterKey(const CKey& key); - const CHDChain& GetHDChain() { return hdChain; } + bool SetHDMasterKey(const CPubKey& key); }; /** A key allocated from the key pool. */ |