aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release-process.md6
-rwxr-xr-xqa/rpc-tests/keypool.py10
-rwxr-xr-xqa/rpc-tests/p2p-segwit.py78
-rwxr-xr-xqa/rpc-tests/wallet-hd.py2
-rw-r--r--src/indirectmap.h4
-rw-r--r--src/init.cpp2
-rw-r--r--src/key.h31
-rw-r--r--src/main.cpp10
-rw-r--r--src/main.h2
-rw-r--r--src/miner.cpp2
-rw-r--r--src/policy/policy.cpp19
-rw-r--r--src/policy/policy.h12
-rw-r--r--src/primitives/transaction.h8
-rw-r--r--src/pubkey.h11
-rw-r--r--src/qt/optionsmodel.cpp21
-rw-r--r--src/qt/optionsmodel.h4
-rw-r--r--src/txmempool.cpp2
-rw-r--r--src/wallet/rpcdump.cpp29
-rw-r--r--src/wallet/rpcwallet.cpp24
-rw-r--r--src/wallet/wallet.cpp52
-rw-r--r--src/wallet/wallet.h7
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));
diff --git a/src/key.h b/src/key.h
index b4f48d59f5..b589710bad 100644
--- a/src/key.h
+++ b/src/key.h
@@ -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. */