diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 8c699c2f8c..f5ddea46ed 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -1,78 +1,77 @@ # Copyright (c) 2015-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. bin_PROGRAMS += bench/bench_bitcoin BENCH_SRCDIR = bench BENCH_BINARY = bench/bench_bitcoin$(EXEEXT) RAW_TEST_FILES = \ bench/data/block413567.raw GENERATED_TEST_FILES = $(RAW_TEST_FILES:.raw=.raw.h) bench_bench_bitcoin_SOURCES = \ bench/bench_bitcoin.cpp \ bench/bench.cpp \ bench/bench.h \ bench/checkblock.cpp \ bench/checkqueue.cpp \ bench/Examples.cpp \ bench/rollingbloom.cpp \ bench/crypto_hash.cpp \ bench/ccoins_caching.cpp \ bench/mempool_eviction.cpp \ - bench/verify_script.cpp \ bench/base58.cpp \ bench/lockedpool.cpp \ bench/perf.cpp \ bench/perf.h nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_TEST_FILES) bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bench_bench_bitcoin_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ $(LIBMEMENV) \ $(LIBSECP256K1) \ $(LIBUNIVALUE) if ENABLE_ZMQ bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif if ENABLE_WALLET bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CRYPTO) endif bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_TEST_FILES) CLEANFILES += $(CLEAN_BITCOIN_BENCH) bench/checkblock.cpp: bench/data/block413567.raw.h bitcoin_bench: $(BENCH_BINARY) bench: $(BENCH_BINARY) FORCE $(BENCH_BINARY) bitcoin_bench_clean : FORCE rm -f $(CLEAN_BITCOIN_BENCH) $(bench_bench_bitcoin_OBJECTS) $(BENCH_BINARY) %.raw.h: %.raw @$(MKDIR_P) $(@D) @{ \ echo "static unsigned const char $(*F)[] = {" && \ $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ echo "};"; \ } > "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp deleted file mode 100644 index 6d208be781..0000000000 --- a/src/bench/verify_script.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// 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. - -#include "bench.h" -#include "key.h" -#if defined(HAVE_CONSENSUS_LIB) -#include "script/bitcoinconsensus.h" -#endif -#include "script/script.h" -#include "script/sign.h" -#include "streams.h" - -// FIXME: Dedup with BuildCreditingTransaction in test/script_tests.cpp. -static CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey) -{ - CMutableTransaction txCredit; - txCredit.nVersion = 1; - txCredit.nLockTime = 0; - txCredit.vin.resize(1); - txCredit.vout.resize(1); - txCredit.vin[0].prevout.SetNull(); - txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0); - txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; - txCredit.vout[0].scriptPubKey = scriptPubKey; - txCredit.vout[0].nValue = 1; - - return txCredit; -} - -// FIXME: Dedup with BuildSpendingTransaction in test/script_tests.cpp. -static CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit) -{ - CMutableTransaction txSpend; - txSpend.nVersion = 1; - txSpend.nLockTime = 0; - txSpend.vin.resize(1); - txSpend.vout.resize(1); - txSpend.vin[0].prevout.hash = txCredit.GetId(); - txSpend.vin[0].prevout.n = 0; - txSpend.vin[0].scriptSig = scriptSig; - txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; - txSpend.vout[0].scriptPubKey = CScript(); - txSpend.vout[0].nValue = txCredit.vout[0].nValue; - - return txSpend; -} - -// Microbenchmark for verification of a basic P2WPKH script. Can be easily -// modified to measure performance of other types of scripts. -static void VerifyScriptBench(benchmark::State& state) -{ - const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH; - const int witnessversion = 0; - - // Keypair. - CKey key; - const unsigned char vchKey[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; - key.Set(vchKey, vchKey + 32, false); - CPubKey pubkey = key.GetPubKey(); - uint160 pubkeyHash; - CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin()); - - // Script. - CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash); - CScript scriptSig; - CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG; - CTransaction txCredit = BuildCreditingTransaction(scriptPubKey); - CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit); - CScriptWitness& witness = txSpend.vin[0].scriptWitness; - witness.stack.emplace_back(); - key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SIGVERSION_WITNESS_V0), witness.stack.back(), 0); - witness.stack.back().push_back(static_cast(SIGHASH_ALL)); - witness.stack.push_back(ToByteVector(pubkey)); - - // Benchmark. - while (state.KeepRunning()) { - ScriptError err; - bool success = VerifyScript( - txSpend.vin[0].scriptSig, - txCredit.vout[0].scriptPubKey, - flags, - MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue), - &err); - assert(err == SCRIPT_ERR_OK); - assert(success); - -#if defined(HAVE_CONSENSUS_LIB) - CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - stream << txSpend; - int csuccess = bitcoinconsensus_verify_script_with_amount( - txCredit.vout[0].scriptPubKey.data(), - txCredit.vout[0].scriptPubKey.size(), - txCredit.vout[0].nValue, - (const unsigned char*)stream.data(), stream.size(), 0, flags, nullptr); - assert(csuccess == 1); -#endif - } -} - -BENCHMARK(VerifyScriptBench); diff --git a/src/core_memusage.h b/src/core_memusage.h index 5e10182075..52a35d65d1 100644 --- a/src/core_memusage.h +++ b/src/core_memusage.h @@ -1,66 +1,62 @@ // Copyright (c) 2015-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_CORE_MEMUSAGE_H #define BITCOIN_CORE_MEMUSAGE_H #include "primitives/transaction.h" #include "primitives/block.h" #include "memusage.h" static inline size_t RecursiveDynamicUsage(const CScript& script) { return memusage::DynamicUsage(*static_cast(&script)); } static inline size_t RecursiveDynamicUsage(const COutPoint& out) { return 0; } static inline size_t RecursiveDynamicUsage(const CTxIn& in) { - size_t mem = RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout) + memusage::DynamicUsage(in.scriptWitness.stack); - for (std::vector >::const_iterator it = in.scriptWitness.stack.begin(); it != in.scriptWitness.stack.end(); it++) { - mem += memusage::DynamicUsage(*it); - } - return mem; + return RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout); } static inline size_t RecursiveDynamicUsage(const CTxOut& out) { return RecursiveDynamicUsage(out.scriptPubKey); } static inline size_t RecursiveDynamicUsage(const CTransaction& tx) { size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout); for (std::vector::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) { mem += RecursiveDynamicUsage(*it); } for (std::vector::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) { mem += RecursiveDynamicUsage(*it); } return mem; } static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) { size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout); for (std::vector::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) { mem += RecursiveDynamicUsage(*it); } for (std::vector::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) { mem += RecursiveDynamicUsage(*it); } return mem; } static inline size_t RecursiveDynamicUsage(const CBlock& block) { size_t mem = memusage::DynamicUsage(block.vtx); for (const auto& tx : block.vtx) { mem += memusage::DynamicUsage(tx) + RecursiveDynamicUsage(*tx); } return mem; } static inline size_t RecursiveDynamicUsage(const CBlockLocator& locator) { return memusage::DynamicUsage(locator.vHave); } #endif // BITCOIN_CORE_MEMUSAGE_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 1e3be5f3d1..aa69e02d4a 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,203 +1,196 @@ // Copyright (c) 2009-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. #include "core_io.h" #include "base58.h" #include "primitives/transaction.h" #include "script/script.h" #include "script/standard.h" #include "serialize.h" #include "streams.h" #include #include "util.h" #include "utilmoneystr.h" #include "utilstrencodings.h" #include #include std::string FormatScript(const CScript& script) { std::string ret; CScript::const_iterator it = script.begin(); opcodetype op; while (it != script.end()) { CScript::const_iterator it2 = it; std::vector vch; if (script.GetOp2(it, op, &vch)) { if (op == OP_0) { ret += "0 "; continue; } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) { ret += strprintf("%i ", op - OP_1NEGATE - 1); continue; } else if (op >= OP_NOP && op <= OP_NOP10) { std::string str(GetOpName(op)); if (str.substr(0, 3) == std::string("OP_")) { ret += str.substr(3, std::string::npos) + " "; continue; } } if (vch.size() > 0) { ret += strprintf("0x%x 0x%x ", HexStr(it2, it - vch.size()), HexStr(it - vch.size(), it)); } else { ret += strprintf("0x%x ", HexStr(it2, it)); } continue; } ret += strprintf("0x%x ", HexStr(it2, script.end())); break; } return ret.substr(0, ret.size() - 1); } const std::map mapSigHashTypes = boost::assign::map_list_of (static_cast(SIGHASH_ALL), std::string("ALL")) (static_cast(SIGHASH_ALL|SIGHASH_ANYONECANPAY), std::string("ALL|ANYONECANPAY")) (static_cast(SIGHASH_NONE), std::string("NONE")) (static_cast(SIGHASH_NONE|SIGHASH_ANYONECANPAY), std::string("NONE|ANYONECANPAY")) (static_cast(SIGHASH_SINGLE), std::string("SINGLE")) (static_cast(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), std::string("SINGLE|ANYONECANPAY")) ; /** * Create the assembly string representation of a CScript object. * @param[in] script CScript object to convert into the asm string representation. * @param[in] fAttemptSighashDecode Whether to attempt to decode sighash types on data within the script that matches the format * of a signature. Only pass true for scripts you believe could contain signatures. For example, * pass false, or omit the this argument (defaults to false), for scriptPubKeys. */ std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) { std::string str; opcodetype opcode; std::vector vch; CScript::const_iterator pc = script.begin(); while (pc < script.end()) { if (!str.empty()) { str += " "; } if (!script.GetOp(pc, opcode, vch)) { str += "[error]"; return str; } if (0 <= opcode && opcode <= OP_PUSHDATA4) { if (vch.size() <= static_cast::size_type>(4)) { str += strprintf("%d", CScriptNum(vch, false).getint()); } else { // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature if (fAttemptSighashDecode && !script.IsUnspendable()) { std::string strSigHashDecode; // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig. // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the // checks in CheckSignatureEncoding. if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, NULL)) { const unsigned char chSigHashType = vch.back(); if (mapSigHashTypes.count(chSigHashType)) { strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]"; vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode. } } str += HexStr(vch) + strSigHashDecode; } else { str += HexStr(vch); } } } else { str += GetOpName(opcode); } } return str; } std::string EncodeHexTx(const CTransaction& tx, const int serialFlags) { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serialFlags); ssTx << tx; return HexStr(ssTx.begin(), ssTx.end()); } void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { txnouttype type; std::vector addresses; int nRequired; out.pushKV("asm", ScriptToAsmStr(scriptPubKey)); if (fIncludeHex) out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())); if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) { out.pushKV("type", GetTxnOutputType(type)); return; } out.pushKV("reqSigs", nRequired); out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR); BOOST_FOREACH(const CTxDestination& addr, addresses) a.push_back(CBitcoinAddress(addr).ToString()); out.pushKV("addresses", a); } void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) { entry.pushKV("txid", tx.GetId().GetHex()); entry.pushKV("hash", tx.GetHash().GetHex()); entry.pushKV("version", tx.nVersion); entry.pushKV("locktime", (int64_t)tx.nLockTime); UniValue vin(UniValue::VARR); for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxIn& txin = tx.vin[i]; UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); else { in.pushKV("txid", txin.prevout.hash.GetHex()); in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); in.pushKV("scriptSig", o); - if (!tx.vin[i].scriptWitness.IsNull()) { - UniValue txinwitness(UniValue::VARR); - for (const auto& item : tx.vin[i].scriptWitness.stack) { - txinwitness.push_back(HexStr(item.begin(), item.end())); - } - in.pushKV("txinwitness", txinwitness); - } } in.pushKV("sequence", (int64_t)txin.nSequence); vin.push_back(in); } entry.pushKV("vin", vin); UniValue vout(UniValue::VARR); for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut& txout = tx.vout[i]; UniValue out(UniValue::VOBJ); UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue)); out.pushKV("value", outValue); out.pushKV("n", (int64_t)i); UniValue o(UniValue::VOBJ); ScriptPubKeyToUniv(txout.scriptPubKey, o, true); out.pushKV("scriptPubKey", o); vout.push_back(out); } entry.pushKV("vout", vout); if (!hashBlock.IsNull()) entry.pushKV("blockhash", hashBlock.GetHex()); entry.pushKV("hex", EncodeHexTx(tx)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction". } diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 746d8fd50d..c17c48c691 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -1,144 +1,142 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-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. #include "primitives/transaction.h" #include "hash.h" #include "tinyformat.h" #include "utilstrencodings.h" std::string COutPoint::ToString() const { return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n); } CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn) { prevout = prevoutIn; scriptSig = scriptSigIn; nSequence = nSequenceIn; } CTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn) { prevout = COutPoint(hashPrevTx, nOut); scriptSig = scriptSigIn; nSequence = nSequenceIn; } std::string CTxIn::ToString() const { std::string str; str += "CTxIn("; str += prevout.ToString(); if (prevout.IsNull()) str += strprintf(", coinbase %s", HexStr(scriptSig)); else str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24)); if (nSequence != SEQUENCE_FINAL) str += strprintf(", nSequence=%u", nSequence); str += ")"; return str; } CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn) { nValue = nValueIn; scriptPubKey = scriptPubKeyIn; } std::string CTxOut::ToString() const { return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30)); } CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {} CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {} uint256 CMutableTransaction::GetId() const { return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS); } uint256 CTransaction::ComputeHash() const { return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS); } uint256 CTransaction::GetHash() const { return GetId(); } /* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */ CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), hash() {} CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), hash(ComputeHash()) {} CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), hash(ComputeHash()) {} CAmount CTransaction::GetValueOut() const { CAmount nValueOut = 0; for (std::vector::const_iterator it(vout.begin()); it != vout.end(); ++it) { nValueOut += it->nValue; if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } return nValueOut; } double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const { nTxSize = CalculateModifiedSize(nTxSize); if (nTxSize == 0) return 0.0; return dPriorityInputs / nTxSize; } unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const { // In order to avoid disincentivizing cleaning up the UTXO set we don't count // the constant overhead for each txin and up to 110 bytes of scriptSig (which // is enough to cover a compressed pubkey p2sh redemption) for priority. // Providing any more cleanup incentive than making additional inputs free would // risk encouraging people to create junk outputs to redeem later. if (nTxSize == 0) nTxSize = GetTransactionSize(*this); for (std::vector::const_iterator it(vin.begin()); it != vin.end(); ++it) { unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size()); if (nTxSize > offset) nTxSize -= offset; } return nTxSize; } unsigned int CTransaction::GetTotalSize() const { return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); } std::string CTransaction::ToString() const { std::string str; str += strprintf("CTransaction(txid=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n", GetId().ToString().substr(0,10), nVersion, vin.size(), vout.size(), nLockTime); for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; - for (unsigned int i = 0; i < vin.size(); i++) - str += " " + vin[i].scriptWitness.ToString() + "\n"; for (unsigned int i = 0; i < vout.size(); i++) str += " " + vout[i].ToString() + "\n"; return str; } int64_t GetTransactionSize(const CTransaction& tx) { return ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index fce0dd770f..d8aeae4c24 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -1,421 +1,375 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-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_PRIMITIVES_TRANSACTION_H #define BITCOIN_PRIMITIVES_TRANSACTION_H #include "amount.h" #include "script/script.h" #include "serialize.h" #include "uint256.h" static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000; /** An outpoint - a combination of a transaction hash and an index n into its vout */ class COutPoint { public: uint256 hash; uint32_t n; COutPoint() { SetNull(); } COutPoint(uint256 hashIn, uint32_t nIn) { hash = hashIn; n = nIn; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(hash); READWRITE(n); } void SetNull() { hash.SetNull(); n = (uint32_t) -1; } bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); } friend bool operator<(const COutPoint& a, const COutPoint& b) { int cmp = a.hash.Compare(b.hash); return cmp < 0 || (cmp == 0 && a.n < b.n); } friend bool operator==(const COutPoint& a, const COutPoint& b) { return (a.hash == b.hash && a.n == b.n); } friend bool operator!=(const COutPoint& a, const COutPoint& b) { return !(a == b); } std::string ToString() const; }; /** An input of a transaction. It contains the location of the previous * transaction's output that it claims and a signature that matches the * output's public key. */ class CTxIn { public: COutPoint prevout; CScript scriptSig; uint32_t nSequence; - CScriptWitness scriptWitness; //! Only serialized through CTransaction /* Setting nSequence to this value for every input in a transaction * disables nLockTime. */ static const uint32_t SEQUENCE_FINAL = 0xffffffff; /* Below flags apply in the context of BIP 68*/ /* If this flag set, CTxIn::nSequence is NOT interpreted as a * relative lock-time. */ static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31); /* If CTxIn::nSequence encodes a relative lock-time and this flag * is set, the relative lock-time has units of 512 seconds, * otherwise it specifies blocks with a granularity of 1. */ static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22); /* If CTxIn::nSequence encodes a relative lock-time, this mask is * applied to extract that lock-time from the sequence field. */ static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff; /* In order to use the same number of bits to encode roughly the * same wall-clock duration, and because blocks are naturally * limited to occur every 600s on average, the minimum granularity * for time-based relative lock-time is fixed at 512 seconds. * Converting from CTxIn::nSequence to seconds is performed by * multiplying by 512 = 2^9, or equivalently shifting up by * 9 bits. */ static const int SEQUENCE_LOCKTIME_GRANULARITY = 9; CTxIn() { nSequence = SEQUENCE_FINAL; } explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL); CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(prevout); READWRITE(*(CScriptBase*)(&scriptSig)); READWRITE(nSequence); } friend bool operator==(const CTxIn& a, const CTxIn& b) { return (a.prevout == b.prevout && a.scriptSig == b.scriptSig && a.nSequence == b.nSequence); } friend bool operator!=(const CTxIn& a, const CTxIn& b) { return !(a == b); } std::string ToString() const; }; /** An output of a transaction. It contains the public key that the next input * must be able to sign with to claim it. */ class CTxOut { public: CAmount nValue; CScript scriptPubKey; CTxOut() { SetNull(); } CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nValue); READWRITE(*(CScriptBase*)(&scriptPubKey)); } void SetNull() { nValue = -1; scriptPubKey.clear(); } bool IsNull() const { return (nValue == -1); } CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const { // "Dust" is defined in terms of CTransaction::minRelayTxFee, // which has units satoshis-per-kilobyte. // If you'd pay more than 1/3 in fees // to spend something, then we consider it dust. // A typical spendable non-segwit txout is 34 bytes big, and will // need a CTxIn of at least 148 bytes to spend: // so dust is a spendable txout less than // 546*minRelayTxFee/1000 (in satoshis). // A typical spendable segwit txout is 31 bytes big, and will // need a CTxIn of at least 67 bytes to spend: // so dust is a spendable txout less than // 294*minRelayTxFee/1000 (in satoshis). if (scriptPubKey.IsUnspendable()) return 0; size_t nSize = GetSerializeSize(*this, SER_DISK, 0); nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above return 3 * minRelayTxFee.GetFee(nSize); } bool IsDust(const CFeeRate &minRelayTxFee) const { return (nValue < GetDustThreshold(minRelayTxFee)); } friend bool operator==(const CTxOut& a, const CTxOut& b) { return (a.nValue == b.nValue && a.scriptPubKey == b.scriptPubKey); } friend bool operator!=(const CTxOut& a, const CTxOut& b) { return !(a == b); } std::string ToString() const; }; struct CMutableTransaction; /** * Basic transaction serialization format: * - int32_t nVersion * - std::vector vin * - std::vector vout * - uint32_t nLockTime - * - * Extended transaction serialization format: - * - int32_t nVersion - * - unsigned char dummy = 0x00 - * - unsigned char flags (!= 0) - * - std::vector vin - * - std::vector vout - * - if (flags & 1): - * - CTxWitness wit; - * - uint32_t nLockTime */ template inline void UnserializeTransaction(TxType& tx, Stream& s) { - const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS); - s >> tx.nVersion; - unsigned char flags = 0; tx.vin.clear(); tx.vout.clear(); /* Try to read the vin. In case the dummy is there, this will be read as an empty vector. */ s >> tx.vin; - if (tx.vin.size() == 0 && fAllowWitness) { - /* We read a dummy or an empty vin. */ - s >> flags; - if (flags != 0) { - s >> tx.vin; - s >> tx.vout; - } - } else { - /* We read a non-empty vin. Assume a normal vout follows. */ - s >> tx.vout; - } - if ((flags & 1) && fAllowWitness) { - /* The witness flag is present, and we support witnesses. */ - flags ^= 1; - for (size_t i = 0; i < tx.vin.size(); i++) { - s >> tx.vin[i].scriptWitness.stack; - } - } - if (flags) { - /* Unknown flag in the serialization */ - throw std::ios_base::failure("Unknown transaction optional data"); - } + /* We read a non-empty vin. Assume a normal vout follows. */ + s >> tx.vout; s >> tx.nLockTime; } template inline void SerializeTransaction(const TxType& tx, Stream& s) { s << tx.nVersion; - unsigned char flags = 0; - if (flags) { - /* Use extended format in case witnesses are to be serialized. */ - std::vector vinDummy; - s << vinDummy; - s << flags; - } s << tx.vin; s << tx.vout; - if (flags & 1) { - for (size_t i = 0; i < tx.vin.size(); i++) { - s << tx.vin[i].scriptWitness.stack; - } - } s << tx.nLockTime; } /** The basic transaction that is broadcasted on the network and contained in * blocks. A transaction can contain multiple inputs and outputs. */ class CTransaction { public: // Default transaction version. static const int32_t CURRENT_VERSION=2; // Changing the default transaction version requires a two step process: first // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and // MAX_STANDARD_VERSION will be equal. static const int32_t MAX_STANDARD_VERSION=2; // The local variables are made const to prevent unintended modification // without updating the cached hash value. However, CTransaction is not // actually immutable; deserialization and assignment are implemented, // and bypass the constness. This is safe, as they update the entire // structure, including the hash. const int32_t nVersion; const std::vector vin; const std::vector vout; const uint32_t nLockTime; private: /** Memory only. */ const uint256 hash; uint256 ComputeHash() const; public: /** Construct a CTransaction that qualifies as IsNull() */ CTransaction(); /** Convert a CMutableTransaction into a CTransaction. */ CTransaction(const CMutableTransaction &tx); CTransaction(CMutableTransaction &&tx); template inline void Serialize(Stream& s) const { SerializeTransaction(*this, s); } /** This deserializing constructor is provided instead of an Unserialize method. * Unserialize is not possible, since it would require overwriting const fields. */ template CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {} bool IsNull() const { return vin.empty() && vout.empty(); } const uint256& GetId() const { return hash; } // Compute a hash that includes both transaction and witness data uint256 GetHash() const; // Return sum of txouts. CAmount GetValueOut() const; // GetValueIn() is a method on CCoinsViewCache, because // inputs must be known to compute value in. // Compute priority, given priority of inputs and (optionally) tx size double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const; // Compute modified tx size for priority calculation (optionally given tx size) unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; /** * Get the total transaction size in bytes, including witness data. * "Total Size" defined in BIP141 and BIP144. * @return Total transaction size in bytes */ unsigned int GetTotalSize() const; bool IsCoinBase() const { return (vin.size() == 1 && vin[0].prevout.IsNull()); } friend bool operator==(const CTransaction& a, const CTransaction& b) { return a.hash == b.hash; } friend bool operator!=(const CTransaction& a, const CTransaction& b) { return a.hash != b.hash; } std::string ToString() const; }; /** A mutable version of CTransaction. */ struct CMutableTransaction { int32_t nVersion; std::vector vin; std::vector vout; uint32_t nLockTime; CMutableTransaction(); CMutableTransaction(const CTransaction& tx); template inline void Serialize(Stream& s) const { SerializeTransaction(*this, s); } template inline void Unserialize(Stream& s) { UnserializeTransaction(*this, s); } template CMutableTransaction(deserialize_type, Stream& s) { Unserialize(s); } /** Compute the hash of this CMutableTransaction. This is computed on the * fly, as opposed to GetId() in CTransaction, which uses a cached result. */ uint256 GetId() const; friend bool operator==(const CMutableTransaction& a, const CMutableTransaction& b) { return a.GetId() == b.GetId(); } }; typedef std::shared_ptr CTransactionRef; static inline CTransactionRef MakeTransactionRef() { return std::make_shared(); } template static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared(std::forward(txIn)); } /** Compute the size of a transaction */ int64_t GetTransactionSize(const CTransaction &tx); #endif // BITCOIN_PRIMITIVES_TRANSACTION_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 9ea4181f97..c770b066df 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,426 +1,373 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-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. #include "script/sign.h" #include "key.h" #include "keystore.h" #include "policy/policy.h" #include "primitives/transaction.h" #include "script/standard.h" #include "uint256.h" #include using namespace std; typedef std::vector valtype; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const { CKey key; if (!keystore->GetKey(address, key)) return false; // Signing with uncompressed keys is disabled in witness scripts if (sigversion == SIGVERSION_WITNESS_V0 && !key.IsCompressed()) return false; uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); if (!key.Sign(hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); return true; } static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) { vector vchSig; if (!creator.CreateSig(vchSig, address, scriptCode, sigversion)) return false; ret.push_back(vchSig); return true; } static bool SignN(const vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) { int nSigned = 0; int nRequired = multisigdata.front()[0]; for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++) { const valtype& pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); if (Sign1(keyID, creator, scriptCode, ret, sigversion)) ++nSigned; } return nSigned==nRequired; } /** * Sign scriptPubKey using signature made with creator. * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey, std::vector& ret, txnouttype& whichTypeRet, SigVersion sigversion) { CScript scriptRet; uint160 h160; ret.clear(); vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: case TX_NULL_DATA: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, creator, scriptPubKey, ret, sigversion); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion)) return false; else { CPubKey vch; creator.KeyStore().GetPubKey(keyID, vch); ret.push_back(ToByteVector(vch)); } return true; case TX_SCRIPTHASH: if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) { ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); return true; } return false; case TX_MULTISIG: ret.push_back(valtype()); // workaround CHECKMULTISIG bug return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion)); case TX_WITNESS_V0_KEYHASH: ret.push_back(vSolutions[0]); return true; case TX_WITNESS_V0_SCRIPTHASH: CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin()); if (creator.KeyStore().GetCScript(h160, scriptRet)) { ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); return true; } return false; default: return false; } } static CScript PushAll(const vector& values) { CScript result; BOOST_FOREACH(const valtype& v, values) { if (v.size() == 0) { result << OP_0; } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { result << CScript::EncodeOP_N(v[0]); } else { result << v; } } return result; } bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata) { CScript script = fromPubKey; bool solved = true; std::vector result; txnouttype whichType; solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE); - bool P2SH = false; CScript subscript; - sigdata.scriptWitness.stack.clear(); if (solved && whichType == TX_SCRIPTHASH) { // Solver returns the subscript that needs to be evaluated; // the final scriptSig is the signatures from that // and then the serialized subscript: script = subscript = CScript(result[0].begin(), result[0].end()); solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH; - P2SH = true; - } - - if (solved && whichType == TX_WITNESS_V0_KEYHASH) - { - CScript witnessscript; - witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG; - txnouttype subType; - solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0); - sigdata.scriptWitness.stack = result; - result.clear(); - } - else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH) - { - CScript witnessscript(result[0].begin(), result[0].end()); - txnouttype subType; - solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; - result.push_back(std::vector(witnessscript.begin(), witnessscript.end())); - sigdata.scriptWitness.stack = result; - result.clear(); - } - - if (P2SH) { result.push_back(std::vector(subscript.begin(), subscript.end())); } + sigdata.scriptSig = PushAll(result); // Test solution return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); } SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn) { SignatureData data; assert(tx.vin.size() > nIn); data.scriptSig = tx.vin[nIn].scriptSig; - data.scriptWitness = tx.vin[nIn].scriptWitness; return data; } void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data) { assert(tx.vin.size() > nIn); tx.vin[nIn].scriptSig = data.scriptSig; - tx.vin[nIn].scriptWitness = data.scriptWitness; } bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType) { assert(nIn < txTo.vin.size()); CTransaction txToConst(txTo); TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType); SignatureData sigdata; bool ret = ProduceSignature(creator, fromPubKey, sigdata); UpdateTransaction(txTo, nIn, sigdata); return ret; } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; assert(txin.prevout.n < txFrom.vout.size()); const CTxOut& txout = txFrom.vout[txin.prevout.n]; return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType); } static vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const vector& vSolutions, const vector& sigs1, const vector& sigs2, SigVersion sigversion) { // Combine all the signatures we've got: set allsigs; BOOST_FOREACH(const valtype& v, sigs1) { if (!v.empty()) allsigs.insert(v); } BOOST_FOREACH(const valtype& v, sigs2) { if (!v.empty()) allsigs.insert(v); } // Build a map of pubkey -> signature by matching sigs to pubkeys: assert(vSolutions.size() > 1); unsigned int nSigsRequired = vSolutions.front()[0]; unsigned int nPubKeys = vSolutions.size()-2; map sigs; BOOST_FOREACH(const valtype& sig, allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) { const valtype& pubkey = vSolutions[i+1]; if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion)) { sigs[pubkey] = sig; break; } } } // Now build a merged CScript: unsigned int nSigsHave = 0; std::vector result; result.push_back(valtype()); // pop-one-too-many workaround for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) { if (sigs.count(vSolutions[i+1])) { result.push_back(sigs[vSolutions[i+1]]); ++nSigsHave; } } // Fill any missing with OP_0: for (unsigned int i = nSigsHave; i < nSigsRequired; i++) result.push_back(valtype()); return result; } namespace { struct Stacks { std::vector script; - std::vector witness; Stacks() {} - explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_), witness() {} - explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) { + explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_) {} + explicit Stacks(const SignatureData& data) { EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); } SignatureData Output() const { SignatureData result; result.scriptSig = PushAll(script); - result.scriptWitness.stack = witness; return result; } }; } static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const txnouttype txType, const vector& vSolutions, Stacks sigs1, Stacks sigs2, SigVersion sigversion) { switch (txType) { case TX_NONSTANDARD: case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: if (sigs1.script.size() >= sigs2.script.size()) return sigs1; return sigs2; case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: if (sigs1.script.empty() || sigs1.script[0].empty()) return sigs2; return sigs1; case TX_WITNESS_V0_KEYHASH: - // Signatures are bigger than placeholders or empty scripts: - if (sigs1.witness.empty() || sigs1.witness[0].empty()) - return sigs2; - return sigs1; + return sigs2; case TX_SCRIPTHASH: if (sigs1.script.empty() || sigs1.script.back().empty()) return sigs2; else if (sigs2.script.empty() || sigs2.script.back().empty()) return sigs1; else { // Recur to combine: valtype spk = sigs1.script.back(); CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; vector > vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.script.pop_back(); sigs2.script.pop_back(); Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion); result.script.push_back(spk); return result; } case TX_MULTISIG: return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion)); case TX_WITNESS_V0_SCRIPTHASH: - if (sigs1.witness.empty() || sigs1.witness.back().empty()) - return sigs2; - else if (sigs2.witness.empty() || sigs2.witness.back().empty()) - return sigs1; - else - { - // Recur to combine: - CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end()); - txnouttype txType2; - vector vSolutions2; - Solver(pubKey2, txType2, vSolutions2); - sigs1.witness.pop_back(); - sigs1.script = sigs1.witness; - sigs1.witness.clear(); - sigs2.witness.pop_back(); - sigs2.script = sigs2.witness; - sigs2.witness.clear(); - Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SIGVERSION_WITNESS_V0); - result.witness = result.script; - result.script.clear(); - result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end())); - return result; - } + return sigs2; default: return Stacks(); } } SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2) { txnouttype txType; vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output(); } namespace { /** Dummy signature checker which accepts all signatures. */ class DummySignatureChecker : public BaseSignatureChecker { public: DummySignatureChecker() {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const { return true; } }; const DummySignatureChecker dummyChecker; } const BaseSignatureChecker& DummySignatureCreator::Checker() const { return dummyChecker; } bool DummySignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const { // Create a dummy signature that is a valid DER-encoding vchSig.assign(72, '\000'); vchSig[0] = 0x30; vchSig[1] = 69; vchSig[2] = 0x02; vchSig[3] = 33; vchSig[4] = 0x01; vchSig[4 + 33] = 0x02; vchSig[5 + 33] = 32; vchSig[6 + 33] = 0x01; vchSig[6 + 33 + 32] = SIGHASH_ALL; return true; } diff --git a/src/script/sign.h b/src/script/sign.h index 1cfc53c6c1..34531b743a 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -1,84 +1,83 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-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_SCRIPT_SIGN_H #define BITCOIN_SCRIPT_SIGN_H #include "script/interpreter.h" class CKeyID; class CKeyStore; class CScript; class CTransaction; struct CMutableTransaction; /** Virtual base class for signature creators. */ class BaseSignatureCreator { protected: const CKeyStore* keystore; public: BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {} const CKeyStore& KeyStore() const { return *keystore; }; virtual ~BaseSignatureCreator() {} virtual const BaseSignatureChecker& Checker() const =0; /** Create a singular (non-script) signature. */ virtual bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0; }; /** A signature creator for transactions. */ class TransactionSignatureCreator : public BaseSignatureCreator { const CTransaction* txTo; unsigned int nIn; int nHashType; CAmount amount; const TransactionSignatureChecker checker; public: TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); const BaseSignatureChecker& Checker() const { return checker; } bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const; }; class MutableTransactionSignatureCreator : public TransactionSignatureCreator { CTransaction tx; public: MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {} }; /** A signature creator that just produces 72-byte empty signatures. */ class DummySignatureCreator : public BaseSignatureCreator { public: DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {} const BaseSignatureChecker& Checker() const; bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const; }; struct SignatureData { CScript scriptSig; - CScriptWitness scriptWitness; SignatureData() {} explicit SignatureData(const CScript& script) : scriptSig(script) {} }; /** Produce a script signature using a generic signature creator. */ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata); /** Produce a script signature for a transaction. */ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); /** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2); /** Extract signature data from a transaction, and insert it. */ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data); #endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index d6aa0d15a0..f1205f7f45 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,1268 +1,1230 @@ // Copyright (c) 2011-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. #include "data/script_tests.json.h" #include "core_io.h" #include "key.h" #include "keystore.h" #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" #include "util.h" #include "utilstrencodings.h" #include "test/test_bitcoin.h" #include "rpc/server.h" #if defined(HAVE_CONSENSUS_LIB) #include "script/bitcoinconsensus.h" #endif #include #include #include #include #include #include #include // Uncomment if you want to output updated JSON tests. // #define UPDATE_JSON_TESTS static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; unsigned int ParseScriptFlags(std::string strFlags); std::string FormatScriptFlags(unsigned int flags); UniValue read_json(const std::string& jsondata) { UniValue v; if (!v.read(jsondata) || !v.isArray()) { BOOST_ERROR("Parse error."); return UniValue(UniValue::VARR); } return v.get_array(); } struct ScriptErrorDesc { ScriptError_t err; const char *name; }; static ScriptErrorDesc script_errors[]={ {SCRIPT_ERR_OK, "OK"}, {SCRIPT_ERR_UNKNOWN_ERROR, "UNKNOWN_ERROR"}, {SCRIPT_ERR_EVAL_FALSE, "EVAL_FALSE"}, {SCRIPT_ERR_OP_RETURN, "OP_RETURN"}, {SCRIPT_ERR_SCRIPT_SIZE, "SCRIPT_SIZE"}, {SCRIPT_ERR_PUSH_SIZE, "PUSH_SIZE"}, {SCRIPT_ERR_OP_COUNT, "OP_COUNT"}, {SCRIPT_ERR_STACK_SIZE, "STACK_SIZE"}, {SCRIPT_ERR_SIG_COUNT, "SIG_COUNT"}, {SCRIPT_ERR_PUBKEY_COUNT, "PUBKEY_COUNT"}, {SCRIPT_ERR_VERIFY, "VERIFY"}, {SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"}, {SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"}, {SCRIPT_ERR_CHECKSIGVERIFY, "CHECKSIGVERIFY"}, {SCRIPT_ERR_NUMEQUALVERIFY, "NUMEQUALVERIFY"}, {SCRIPT_ERR_BAD_OPCODE, "BAD_OPCODE"}, {SCRIPT_ERR_DISABLED_OPCODE, "DISABLED_OPCODE"}, {SCRIPT_ERR_INVALID_STACK_OPERATION, "INVALID_STACK_OPERATION"}, {SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, "INVALID_ALTSTACK_OPERATION"}, {SCRIPT_ERR_UNBALANCED_CONDITIONAL, "UNBALANCED_CONDITIONAL"}, {SCRIPT_ERR_NEGATIVE_LOCKTIME, "NEGATIVE_LOCKTIME"}, {SCRIPT_ERR_UNSATISFIED_LOCKTIME, "UNSATISFIED_LOCKTIME"}, {SCRIPT_ERR_SIG_HASHTYPE, "SIG_HASHTYPE"}, {SCRIPT_ERR_SIG_DER, "SIG_DER"}, {SCRIPT_ERR_MINIMALDATA, "MINIMALDATA"}, {SCRIPT_ERR_SIG_PUSHONLY, "SIG_PUSHONLY"}, {SCRIPT_ERR_SIG_HIGH_S, "SIG_HIGH_S"}, {SCRIPT_ERR_SIG_NULLDUMMY, "SIG_NULLDUMMY"}, {SCRIPT_ERR_PUBKEYTYPE, "PUBKEYTYPE"}, {SCRIPT_ERR_CLEANSTACK, "CLEANSTACK"}, {SCRIPT_ERR_MINIMALIF, "MINIMALIF"}, {SCRIPT_ERR_SIG_NULLFAIL, "NULLFAIL"}, {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "DISCOURAGE_UPGRADABLE_NOPS"}, {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"}, {SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH, "WITNESS_PROGRAM_WRONG_LENGTH"}, {SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY, "WITNESS_PROGRAM_WITNESS_EMPTY"}, {SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH, "WITNESS_PROGRAM_MISMATCH"}, {SCRIPT_ERR_WITNESS_MALLEATED, "WITNESS_MALLEATED"}, {SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"}, {SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"}, {SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"}, }; const char *FormatScriptError(ScriptError_t err) { for (unsigned int i=0; i& vchSig) { // Parse the signature. std::vector r, s; r = std::vector(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); s = std::vector(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); // Really ugly to implement mod-n negation here, but it would be feature creep to expose such functionality from libsecp256k1. static const unsigned char order[33] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }; while (s.size() < 33) { s.insert(s.begin(), 0x00); } int carry = 0; for (int p = 32; p >= 1; p--) { int n = (int)order[p] - s[p] - carry; s[p] = (n + 256) & 0xFF; carry = (n < 0); } assert(carry == 0); if (s.size() > 1 && s[0] == 0 && s[1] < 0x80) { s.erase(s.begin()); } // Reconstruct the signature. vchSig.clear(); vchSig.push_back(0x30); vchSig.push_back(4 + r.size() + s.size()); vchSig.push_back(0x02); vchSig.push_back(r.size()); vchSig.insert(vchSig.end(), r.begin(), r.end()); vchSig.push_back(0x02); vchSig.push_back(s.size()); vchSig.insert(vchSig.end(), s.begin(), s.end()); } namespace { const unsigned char vchKey0[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; const unsigned char vchKey1[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; const unsigned char vchKey2[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0}; struct KeyData { CKey key0, key0C, key1, key1C, key2, key2C; CPubKey pubkey0, pubkey0C, pubkey0H; CPubKey pubkey1, pubkey1C; CPubKey pubkey2, pubkey2C; KeyData() { key0.Set(vchKey0, vchKey0 + 32, false); key0C.Set(vchKey0, vchKey0 + 32, true); pubkey0 = key0.GetPubKey(); pubkey0H = key0.GetPubKey(); pubkey0C = key0C.GetPubKey(); *const_cast(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1); key1.Set(vchKey1, vchKey1 + 32, false); key1C.Set(vchKey1, vchKey1 + 32, true); pubkey1 = key1.GetPubKey(); pubkey1C = key1C.GetPubKey(); key2.Set(vchKey2, vchKey2 + 32, false); key2C.Set(vchKey2, vchKey2 + 32, true); pubkey2 = key2.GetPubKey(); pubkey2C = key2C.GetPubKey(); } }; enum WitnessMode { WITNESS_NONE, WITNESS_PKH, WITNESS_SH }; class TestBuilder { private: //! Actually executed script CScript script; //! The P2SH redeemscript CScript redeemscript; //! The Witness embedded script CScript witscript; - CScriptWitness scriptWitness; CTransactionRef creditTx; CMutableTransaction spendTx; bool havePush; std::vector push; std::string comment; int flags; int scriptError; CAmount nValue; void DoPush() { if (havePush) { spendTx.vin[0].scriptSig << push; havePush = false; } } void DoPush(const std::vector& data) { DoPush(); push = data; havePush = true; } public: TestBuilder(const CScript& script_, const std::string& comment_, int flags_, bool P2SH = false, WitnessMode wm = WITNESS_NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK), nValue(nValue_) { CScript scriptPubKey = script; if (wm == WITNESS_PKH) { uint160 hash; CHash160().Write(&script[1], script.size() - 1).Finalize(hash.begin()); script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(hash) << OP_EQUALVERIFY << OP_CHECKSIG; scriptPubKey = CScript() << witnessversion << ToByteVector(hash); } else if (wm == WITNESS_SH) { witscript = scriptPubKey; uint256 hash; CSHA256().Write(&witscript[0], witscript.size()).Finalize(hash.begin()); scriptPubKey = CScript() << witnessversion << ToByteVector(hash); } if (P2SH) { redeemscript = scriptPubKey; scriptPubKey = CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL; } creditTx = MakeTransactionRef(BuildCreditingTransaction(scriptPubKey, nValue)); - spendTx = BuildSpendingTransaction(CScript(), CScriptWitness(), *creditTx); + spendTx = BuildSpendingTransaction(CScript(), *creditTx); } TestBuilder& ScriptError(ScriptError_t err) { scriptError = err; return *this; } TestBuilder& Add(const CScript& _script) { DoPush(); spendTx.vin[0].scriptSig += _script; return *this; } TestBuilder& Num(int num) { DoPush(); spendTx.vin[0].scriptSig << num; return *this; } TestBuilder& Push(const std::string& hex) { DoPush(ParseHex(hex)); return *this; } TestBuilder& Push(const CScript& _script) { DoPush(std::vector(_script.begin(), _script.end())); return *this; } TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SIGVERSION_BASE, CAmount amount = 0) { uint256 hash = SignatureHash(script, spendTx, 0, nHashType, amount, sigversion); std::vector vchSig, r, s; uint32_t iter = 0; do { key.Sign(hash, vchSig, iter++); if ((lenS == 33) != (vchSig[5 + vchSig[3]] == 33)) { NegateSignatureS(vchSig); } r = std::vector(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); s = std::vector(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); } while (lenR != r.size() || lenS != s.size()); vchSig.push_back(static_cast(nHashType)); DoPush(vchSig); return *this; } - TestBuilder& PushWitSig(const CKey& key, CAmount amount = -1, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SIGVERSION_WITNESS_V0) - { - if (amount == -1) - amount = nValue; - return PushSig(key, nHashType, lenR, lenS, sigversion, amount).AsWit(); - } - TestBuilder& Push(const CPubKey& pubkey) { DoPush(std::vector(pubkey.begin(), pubkey.end())); return *this; } TestBuilder& PushRedeem() { DoPush(std::vector(redeemscript.begin(), redeemscript.end())); return *this; } - TestBuilder& PushWitRedeem() - { - DoPush(std::vector(witscript.begin(), witscript.end())); - return AsWit(); - } - TestBuilder& EditPush(unsigned int pos, const std::string& hexin, const std::string& hexout) { assert(havePush); std::vector datain = ParseHex(hexin); std::vector dataout = ParseHex(hexout); assert(pos + datain.size() <= push.size()); BOOST_CHECK_MESSAGE(std::vector(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment); push.erase(push.begin() + pos, push.begin() + pos + datain.size()); push.insert(push.begin() + pos, dataout.begin(), dataout.end()); return *this; } TestBuilder& DamagePush(unsigned int pos) { assert(havePush); assert(pos < push.size()); push[pos] ^= 1; return *this; } TestBuilder& Test() { TestBuilder copy = *this; // Make a copy so we can rollback the push. DoPush(); - DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, scriptWitness, flags, comment, scriptError, nValue); + DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, comment, scriptError, nValue); *this = copy; return *this; } - TestBuilder& AsWit() - { - assert(havePush); - scriptWitness.stack.push_back(push); - havePush = false; - return *this; - } - UniValue GetJSON() { DoPush(); UniValue array(UniValue::VARR); - if (!scriptWitness.stack.empty()) { - UniValue wit(UniValue::VARR); - for (unsigned i = 0; i < scriptWitness.stack.size(); i++) { - wit.push_back(HexStr(scriptWitness.stack[i])); - } - wit.push_back(ValueFromAmount(nValue)); - array.push_back(wit); - } array.push_back(FormatScript(spendTx.vin[0].scriptSig)); array.push_back(FormatScript(creditTx->vout[0].scriptPubKey)); array.push_back(FormatScriptFlags(flags)); array.push_back(FormatScriptError((ScriptError_t)scriptError)); array.push_back(comment); return array; } std::string GetComment() { return comment; } const CScript& GetScriptPubKey() { return creditTx->vout[0].scriptPubKey; } }; std::string JSONPrettyPrint(const UniValue& univalue) { std::string ret = univalue.write(4); // Workaround for libunivalue pretty printer, which puts a space between commas and newlines size_t pos = 0; while ((pos = ret.find(" \n", pos)) != std::string::npos) { ret.replace(pos, 2, "\n"); pos++; } return ret; } } BOOST_AUTO_TEST_CASE(script_build) { const KeyData keys; std::vector tests; tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK", 0 ).PushSig(keys.key0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK, bad sig", 0 ).PushSig(keys.key0).DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH", 0 ).PushSig(keys.key1).Push(keys.pubkey1C)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH, bad pubkey", 0 ).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5).ScriptError(SCRIPT_ERR_EQUALVERIFY)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay", 0 ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay marked with normal hashtype", 0 ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01").ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true ).PushSig(keys.key0).PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true ).PushSig(keys.key0).PushRedeem().DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH)", SCRIPT_VERIFY_P2SH, true ).PushSig(keys.key0).Push(keys.pubkey0).PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true ).PushSig(keys.key0).DamagePush(10).PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true ).PushSig(keys.key0).DamagePush(10).PushRedeem().ScriptError(SCRIPT_ERR_EQUALVERIFY)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3", 0 ).Num(0).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3, 2 sigs", 0 ).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true ).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true ).Num(0).PushSig(keys.key1).Num(0).PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding but no DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding but no DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100")); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding", SCRIPT_VERIFY_DERSIG ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding but no DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding but no DERSIG", 0 ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding", SCRIPT_VERIFY_DERSIG ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10).ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding but no DERSIG", 0 ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, without DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, without DERSIG", 0 ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, without DERSIG", 0 ).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, without DERSIG", 0 ).Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, without DERSIG", 0 ).Num(1).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(1).ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, without DERSIG", 0 ).Num(1)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(1).ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, without DERSIG", 0 ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, without DERSIG", 0 ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, without DERSIG", 0 ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, without DERSIG", 0 ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, without DERSIG", 0 ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, without DERSIG", 0 ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, with DERSIG", SCRIPT_VERIFY_DERSIG ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, without DERSIG", 0 ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101")); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, with DERSIG", SCRIPT_VERIFY_DERSIG ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101").ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S but no LOW_S", 0 ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S", SCRIPT_VERIFY_LOW_S ).PushSig(keys.key2, SIGHASH_ALL, 32, 33).ScriptError(SCRIPT_ERR_SIG_HIGH_S)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey but no STRICTENC", 0 ).PushSig(keys.key0, SIGHASH_ALL)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey but no STRICTENC", 0 ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC ).PushSig(keys.key0, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0 ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0 ).Num(0).PushSig(keys.key1, SIGHASH_ALL)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC ).Num(0).PushSig(keys.key1, SIGHASH_ALL)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC ).Num(0).PushSig(keys.key1, SIGHASH_ALL).ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype but no STRICTENC", 0 ).PushSig(keys.key1, 5)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC ).PushSig(keys.key1, 5).ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0 ).PushSig(keys.key1, 5).DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC ).PushSig(keys.key1, 5).DamagePush(10).ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy but no NULLDUMMY", 0 ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0 ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10).ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY", 0 ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP).ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY", 0, true ).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with non-push scriptSig but with P2SH validation", 0 ).PushSig(keys.key2).Add(CScript() << OP_NOP8)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", SCRIPT_VERIFY_P2SH, true ).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but not P2SH", SCRIPT_VERIFY_SIGPUSHONLY, true ).PushSig(keys.key2).Add(CScript() << OP_NOP8).PushRedeem().ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY ).Num(0).PushSig(keys.key1).PushSig(keys.key1)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH ).Num(11).PushSig(keys.key0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH ).Num(11).PushSig(keys.key0).ScriptError(SCRIPT_ERR_CLEANSTACK)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true ).Num(11).PushSig(keys.key0).PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true ).Num(11).PushSig(keys.key0).PushRedeem().ScriptError(SCRIPT_ERR_CLEANSTACK)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true ).PushSig(keys.key0).PushRedeem()); std::set tests_set; { UniValue json_tests = read_json(std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < json_tests.size(); idx++) { const UniValue& tv = json_tests[idx]; tests_set.insert(JSONPrettyPrint(tv.get_array())); } } std::string strGen; BOOST_FOREACH(TestBuilder& test, tests) { test.Test(); std::string str = JSONPrettyPrint(test.GetJSON()); #ifndef UPDATE_JSON_TESTS if (tests_set.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); } #endif strGen += str + ",\n"; } #ifdef UPDATE_JSON_TESTS FILE* file = fopen("script_tests.json.gen", "w"); fputs(strGen.c_str(), file); fclose(file); #endif } BOOST_AUTO_TEST_CASE(script_json_test) { // Read tests from test/data/script_tests.json // Format is an array of arrays // Inner arrays are [ ["wit"..., nValue]?, "scriptSig", "scriptPubKey", "flags", "expected_scripterror" ] // ... where scriptSig and scriptPubKey are stringified // scripts. - // If a witness is given, then the last value in the array should be the - // amount (nValue) to use in the crediting tx UniValue tests = read_json(std::string(json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; std::string strTest = test.write(); - CScriptWitness witness; CAmount nValue = 0; unsigned int pos = 0; if (test.size() > 0 && test[pos].isArray()) { - unsigned int i=0; - for (i = 0; i < test[pos].size()-1; i++) { - witness.stack.push_back(ParseHex(test[pos][i].get_str())); - } - nValue = AmountFromValue(test[pos][i]); + nValue = AmountFromValue(test[pos][0]); pos++; } if (test.size() < 4 + pos) // Allow size > 3; extra stuff ignored (useful for comments) { if (test.size() != 1) { BOOST_ERROR("Bad test: " << strTest); } continue; } std::string scriptSigString = test[pos++].get_str(); CScript scriptSig = ParseScript(scriptSigString); std::string scriptPubKeyString = test[pos++].get_str(); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str()); int scriptError = ParseScriptError(test[pos++].get_str()); - DoTest(scriptPubKey, scriptSig, witness, scriptflags, strTest, scriptError, nValue); + DoTest(scriptPubKey, scriptSig, scriptflags, strTest, scriptError, nValue); } } BOOST_AUTO_TEST_CASE(script_PushData) { // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on // the stack as the 1-75 opcodes do. static const unsigned char direct[] = { 1, 0x5a }; static const unsigned char pushdata1[] = { OP_PUSHDATA1, 1, 0x5a }; static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a }; static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; ScriptError err; std::vector > directStack; BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata1Stack; BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata2Stack; BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata4Stack; BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) { uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); CScript result; // // NOTE: CHECKMULTISIG has an unfortunate bug; it requires // one extra item on the stack, before the signatures. // Putting OP_0 on the stack is the workaround; // fixing the bug would mean splitting the block chain (old // clients would not accept new CHECKMULTISIG transactions, // and vice-versa) // result << OP_0; BOOST_FOREACH(const CKey &key, keys) { std::vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); result << vchSig; } return result; } CScript sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) { std::vector keys; keys.push_back(key); return sign_multisig(scriptPubKey, keys, transaction); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) { ScriptError err; CKey key1, key2, key3; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); CScript scriptPubKey12; scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12); - CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom12); + CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = 2; BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) { ScriptError err; CKey key1, key2, key3, key4; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); key4.MakeNewKey(false); CScript scriptPubKey23; scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG; CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23); - CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom23); + CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23); std::vector keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_combineSigs) { // Test the CombineSignatures function CAmount amount = 0; CBasicKeyStore keystore; std::vector keys; std::vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; key.MakeNewKey(i%2 == 1); keys.push_back(key); pubkeys.push_back(key.GetPubKey()); keystore.AddKey(key); } CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID())); - CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom); + CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom); CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; CScript& scriptSig = txTo.vin[0].scriptSig; SignatureData empty; SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty); BOOST_CHECK(combined.scriptSig.empty()); // Single signature case: SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // changes scriptSig combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; keystore.AddCScript(pkSingle); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); scriptSigCopy = scriptSig; SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: scriptSigCopy = CScript() << OP_0 << std::vector(pkSingle.begin(), pkSingle.end()); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy)); BOOST_CHECK(combined.scriptSig == scriptSig); // Hardest case: Multisig 2-of-3 scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); // A couple of partially-signed versions: std::vector sig1; uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); std::vector sig2; uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); std::vector sig3; uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); // Not fussy about order (or even existence) of placeholders or signatures: CScript partial1a = CScript() << OP_0 << sig1 << OP_0; CScript partial1b = CScript() << OP_0 << OP_0 << sig1; CScript partial2a = CScript() << OP_0 << sig2; CScript partial2b = CScript() << sig2 << OP_0; CScript partial3a = CScript() << sig3; CScript partial3b = CScript() << OP_0 << OP_0 << sig3; CScript partial3c = CScript() << OP_0 << sig3 << OP_0; CScript complete12 = CScript() << OP_0 << sig1 << sig2; CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b)); BOOST_CHECK(combined.scriptSig == partial1a); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b)); BOOST_CHECK(combined.scriptSig == complete13); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a)); BOOST_CHECK(combined.scriptSig == complete23); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b)); BOOST_CHECK(combined.scriptSig == complete23); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a)); BOOST_CHECK(combined.scriptSig == partial3c); } BOOST_AUTO_TEST_CASE(script_standard_push) { ScriptError err; for (int i=0; i<67000; i++) { CScript script; script << i; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) { std::vector data(i, '\111'); CScript script; script << data; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } } BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts) { // IsPushOnly returns false when given a script containing only pushes that // are invalid due to truncation. IsPushOnly() is consensus critical // because P2SH evaluation uses it, although this specific behavior should // not be consensus critical as the P2SH evaluation would fail first due to // the invalid push. Still, it doesn't hurt to test it explicitly. static const unsigned char direct[] = { 1 }; BOOST_CHECK(!CScript(direct, direct+sizeof(direct)).IsPushOnly()); } BOOST_AUTO_TEST_CASE(script_GetScriptAsm) { BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); std::string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090"); std::string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); std::vector vchPubKey = ToByteVector(ParseHex(pubKey)); BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "[ALL] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "[NONE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "[SINGLE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "[ALL|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "[NONE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "[SINGLE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "01 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "02 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "03 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "81 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "82 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); } static CScript ScriptFromHex(const char* hex) { std::vector data = ParseHex(hex); return CScript(data.begin(), data.end()); } BOOST_AUTO_TEST_CASE(script_FindAndDelete) { // Exercise the FindAndDelete functionality CScript s; CScript d; CScript expect; s = CScript() << OP_1 << OP_2; d = CScript(); // delete nothing should be a no-op expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = CScript() << OP_1 << OP_2 << OP_3; d = CScript() << OP_2; expect = CScript() << OP_1 << OP_3; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3; d = CScript() << OP_3; expect = CScript() << OP_1 << OP_4; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff03"); // PUSH 0x02ff03 onto stack d = ScriptFromHex("0302ff03"); expect = CScript(); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); // PUSH 0x2ff03 PUSH 0x2ff03 d = ScriptFromHex("0302ff03"); expect = CScript(); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("02"); expect = s; // FindAndDelete matches entire opcodes BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("ff"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); // This is an odd edge case: strip of the push-three-bytes // prefix, leaving 02ff03 which is push-two-bytes: s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("03"); expect = CScript() << ParseHex("ff03") << ParseHex("ff03"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); // Byte sequence that spans multiple opcodes: s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY d = ScriptFromHex("feed51"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); // doesn't match 'inside' opcodes BOOST_CHECK(s == expect); s = ScriptFromHex("02feed5169"); // PUSH(0xfeed) OP_1 OP_VERIFY d = ScriptFromHex("02feed51"); expect = ScriptFromHex("69"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("516902feed5169"); d = ScriptFromHex("feed51"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = ScriptFromHex("516902feed5169"); d = ScriptFromHex("02feed51"); expect = ScriptFromHex("516969"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_0 << OP_0 << OP_1 << OP_1; d = CScript() << OP_0 << OP_1; expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1; d = CScript() << OP_0 << OP_1; expect = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); // Another weird edge case: // End with invalid push (not enough data)... s = ScriptFromHex("0003feed"); d = ScriptFromHex("03feed"); // ... can remove the invalid push expect = ScriptFromHex("00"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("0003feed"); d = ScriptFromHex("00"); expect = ScriptFromHex("03feed"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 6252eb44a9..a24bbdc1bc 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -1,156 +1,155 @@ // Copyright (c) 2012-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. #include "validation.h" #include "pubkey.h" #include "key.h" #include "script/script.h" #include "script/standard.h" #include "uint256.h" #include "test/test_bitcoin.h" #include #include #include // Helpers: static std::vector Serialize(const CScript& s) { std::vector sSerialized(s.begin(), s.end()); return sSerialized; } BOOST_FIXTURE_TEST_SUITE(sigopcount_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(GetSigOpCount) { // Test CScript::GetSigOpCount() CScript s1; BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0U); BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0U); uint160 dummy; s1 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2U); s1 << OP_IF << OP_CHECKSIG << OP_ENDIF; BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U); BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U); CScript p2sh = GetScriptForDestination(CScriptID(s1)); CScript scriptSig; scriptSig << OP_0 << Serialize(s1); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); std::vector keys; for (int i = 0; i < 3; i++) { CKey k; k.MakeNewKey(true); keys.push_back(k.GetPubKey()); } CScript s2 = GetScriptForMultisig(1, keys); BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U); BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U); p2sh = GetScriptForDestination(CScriptID(s2)); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U); CScript scriptSig2; scriptSig2 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << Serialize(s2); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); } /** * Verifies script execution of the zeroth scriptPubKey of tx output and * zeroth scriptSig and witness of tx input. */ ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction& input, int flags) { ScriptError error; CTransaction inputi(input); bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue), &error); BOOST_CHECK((ret == true) == (error == SCRIPT_ERR_OK)); return error; } /** * Builds a creationTx from scriptPubKey and a spendingTx from scriptSig * and witness such that spendingTx spends output zero of creationTx. * Also inserts creationTx's output into the coins view. */ -void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& witness) +void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableTransaction& creationTx, const CScript& scriptPubKey, const CScript& scriptSig) { creationTx.nVersion = 1; creationTx.vin.resize(1); creationTx.vin[0].prevout.SetNull(); creationTx.vin[0].scriptSig = CScript(); creationTx.vout.resize(1); creationTx.vout[0].nValue = 1; creationTx.vout[0].scriptPubKey = scriptPubKey; spendingTx.nVersion = 1; spendingTx.vin.resize(1); spendingTx.vin[0].prevout.hash = creationTx.GetId(); spendingTx.vin[0].prevout.n = 0; spendingTx.vin[0].scriptSig = scriptSig; - spendingTx.vin[0].scriptWitness = witness; spendingTx.vout.resize(1); spendingTx.vout[0].nValue = 1; spendingTx.vout[0].scriptPubKey = CScript(); coins.ModifyCoins(creationTx.GetId())->FromTx(creationTx, 0); } BOOST_AUTO_TEST_CASE(GetTxSigOpCost) { // Transaction creates outputs CMutableTransaction creationTx; // Transaction that spends outputs and whose // sig op cost is going to be tested CMutableTransaction spendingTx; // Create utxo set CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); // Create key CKey key; key.MakeNewKey(true); CPubKey pubkey = key.GetPubKey(); // Default flags int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH; // Multisig script (legacy counting) { CScript scriptPubKey = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; // Do not use a valid signature to avoid using wallet operations. CScript scriptSig = CScript() << OP_0 << OP_0; - BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness()); + BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig); // Legacy counting only includes signature operations in scriptSigs and scriptPubKeys // of a transaction and does not take the actual executed sig operations into account. // spendingTx in itself does not contain a signature operation. assert(GetTransactionSigOpCount(CTransaction(spendingTx), coins, flags) == 0); // creationTx contains two signature operations in its scriptPubKey, but legacy counting // is not accurate. assert(GetTransactionSigOpCount(CTransaction(creationTx), coins, flags) == MAX_PUBKEYS_PER_MULTISIG); // Sanity check: script verification fails because of an invalid signature. assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY); } // Multisig nested in P2SH { CScript redeemScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript); - BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness()); + BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig); assert(GetTransactionSigOpCount(CTransaction(spendingTx), coins, flags) == 2); assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6c65a38115..53ab90057f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1,3967 +1,3966 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-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. #include "wallet/wallet.h" #include "base58.h" #include "checkpoints.h" #include "chain.h" #include "wallet/coincontrol.h" #include "consensus/consensus.h" #include "consensus/validation.h" #include "key.h" #include "keystore.h" #include "validation.h" #include "net.h" #include "policy/policy.h" #include "primitives/block.h" #include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" #include "timedata.h" #include "txmempool.h" #include "util.h" #include "ui_interface.h" #include "utilmoneystr.h" #include #include #include #include using namespace std; CWallet* pwalletMain = NULL; /** Transaction fee set by the user */ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS; const char * DEFAULT_WALLET_DAT = "wallet.dat"; const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; /** * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) * Override with -mintxfee */ CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE); /** * If fee estimation does not have enough data to provide estimates, use this fee instead. * Has no effect if not using fee estimation * Override with -fallbackfee */ CFeeRate CWallet::fallbackFee = CFeeRate(DEFAULT_FALLBACK_FEE); const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); /** @defgroup mapWallet * * @{ */ struct CompareValueOnly { bool operator()(const pair >& t1, const pair >& t2) const { return t1.first < t2.first; } }; std::string COutput::ToString() const { return strprintf("COutput(%s, %d, %d) [%s]", tx->GetId().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue)); } const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const { LOCK(cs_wallet); std::map::const_iterator it = mapWallet.find(hash); if (it == mapWallet.end()) return NULL; return &(it->second); } CPubKey CWallet::GenerateNewKey() { AssertLockHeld(cs_wallet); // mapKeyMetadata bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets CKey secret; // Create new metadata int64_t nCreationTime = GetTime(); CKeyMetadata metadata(nCreationTime); // use HD key derivation if HD was enabled during wallet creation if (IsHDEnabled()) { DeriveNewChildKey(metadata, secret); } else { secret.MakeNewKey(fCompressed); } // Compressed public keys were introduced in version 0.6.0 if (fCompressed) SetMinVersion(FEATURE_COMPRPUBKEY); CPubKey pubkey = secret.GetPubKey(); assert(secret.VerifyPubKey(pubkey)); mapKeyMetadata[pubkey.GetID()] = metadata; UpdateTimeFirstKey(nCreationTime); if (!AddKeyPubKey(secret, pubkey)) throw std::runtime_error(std::string(__func__) + ": AddKey failed"); return pubkey; } void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret) { // for now we use a fixed keypath scheme of m/0'/0'/k CKey key; //master key seed (256bit) CExtKey masterKey; //hd master key CExtKey accountKey; //key at m/0' CExtKey externalChainChildKey; //key at m/0'/0' CExtKey childKey; //key at m/0'/0'/' // try to get the master key if (!GetKey(hdChain.masterKeyID, key)) throw std::runtime_error(std::string(__func__) + ": Master key not found"); masterKey.SetMaster(key.begin(), key.size()); // derive m/0' // use hardened derivation (child keys >= 0x80000000 are hardened after bip32) masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT); // derive m/0'/0' accountKey.Derive(externalChainChildKey, BIP32_HARDENED_KEY_LIMIT); // derive child key at next index, skip keys already known to the wallet do { // always derive hardened keys // childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range // example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649 externalChainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT); metadata.hdKeypath = "m/0'/0'/" + std::to_string(hdChain.nExternalChainCounter) + "'"; metadata.hdMasterKeyID = hdChain.masterKeyID; // increment childkey index hdChain.nExternalChainCounter++; } while (HaveKey(childKey.key.GetPubKey().GetID())); secret = childKey.key; // update the chain model in the database if (!CWalletDB(strWalletFile).WriteHDChain(hdChain)) throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed"); } bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) { AssertLockHeld(cs_wallet); // mapKeyMetadata if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) return false; // check if we need to remove from watch-only CScript script; script = GetScriptForDestination(pubkey.GetID()); if (HaveWatchOnly(script)) RemoveWatchOnly(script); script = GetScriptForRawPubKey(pubkey); if (HaveWatchOnly(script)) RemoveWatchOnly(script); if (!fFileBacked) return true; if (!IsCrypted()) { return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]); } return true; } bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector &vchCryptedSecret) { if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) return false; if (!fFileBacked) return true; { LOCK(cs_wallet); if (pwalletdbEncryption) return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); else return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); } return false; } bool CWallet::LoadKeyMetadata(const CTxDestination& keyID, const CKeyMetadata &meta) { AssertLockHeld(cs_wallet); // mapKeyMetadata UpdateTimeFirstKey(meta.nCreateTime); mapKeyMetadata[keyID] = meta; return true; } bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } void CWallet::UpdateTimeFirstKey(int64_t nCreateTime) { AssertLockHeld(cs_wallet); if (nCreateTime <= 1) { // Cannot determine birthday information, so set the wallet birthday to // the beginning of time. nTimeFirstKey = 1; } else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) { nTimeFirstKey = nCreateTime; } } bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) return false; if (!fFileBacked) return true; return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript); } bool CWallet::LoadCScript(const CScript& redeemScript) { /* A sanity check was added in pull #3843 to avoid adding redeemScripts * that never can be redeemed. However, old wallets may still contain * these. Do not add them to the wallet and warn. */ if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { std::string strAddr = CBitcoinAddress(CScriptID(redeemScript)).ToString(); LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr); return true; } return CCryptoKeyStore::AddCScript(redeemScript); } bool CWallet::AddWatchOnly(const CScript& dest) { if (!CCryptoKeyStore::AddWatchOnly(dest)) return false; const CKeyMetadata& meta = mapKeyMetadata[CScriptID(dest)]; UpdateTimeFirstKey(meta.nCreateTime); NotifyWatchonlyChanged(true); if (!fFileBacked) return true; return CWalletDB(strWalletFile).WriteWatchOnly(dest, meta); } bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime) { mapKeyMetadata[CScriptID(dest)].nCreateTime = nCreateTime; return AddWatchOnly(dest); } bool CWallet::RemoveWatchOnly(const CScript &dest) { AssertLockHeld(cs_wallet); if (!CCryptoKeyStore::RemoveWatchOnly(dest)) return false; if (!HaveWatchOnly()) NotifyWatchonlyChanged(false); if (fFileBacked) if (!CWalletDB(strWalletFile).EraseWatchOnly(dest)) return false; return true; } bool CWallet::LoadWatchOnly(const CScript &dest) { return CCryptoKeyStore::AddWatchOnly(dest); } bool CWallet::Unlock(const SecureString& strWalletPassphrase) { CCrypter crypter; CKeyingMaterial vMasterKey; { LOCK(cs_wallet); BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) { if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) continue; // try another master key if (CCryptoKeyStore::Unlock(vMasterKey)) return true; } } return false; } bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase) { bool fWasLocked = IsLocked(); { LOCK(cs_wallet); Lock(); CCrypter crypter; CKeyingMaterial vMasterKey; BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys) { if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) return false; if (CCryptoKeyStore::Unlock(vMasterKey)) { int64_t nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime))); nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2; if (pMasterKey.second.nDeriveIterations < 25000) pMasterKey.second.nDeriveIterations = 25000; LogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations); if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey)) return false; CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second); if (fWasLocked) Lock(); return true; } } } return false; } void CWallet::SetBestChain(const CBlockLocator& loc) { CWalletDB walletdb(strWalletFile); walletdb.WriteBestBlock(loc); } bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit) { LOCK(cs_wallet); // nWalletVersion if (nWalletVersion >= nVersion) return true; // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way if (fExplicit && nVersion > nWalletMaxVersion) nVersion = FEATURE_LATEST; nWalletVersion = nVersion; if (nVersion > nWalletMaxVersion) nWalletMaxVersion = nVersion; if (fFileBacked) { CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile); if (nWalletVersion > 40000) pwalletdb->WriteMinVersion(nWalletVersion); if (!pwalletdbIn) delete pwalletdb; } return true; } bool CWallet::SetMaxVersion(int nVersion) { LOCK(cs_wallet); // nWalletVersion, nWalletMaxVersion // cannot downgrade below current version if (nWalletVersion > nVersion) return false; nWalletMaxVersion = nVersion; return true; } set CWallet::GetConflicts(const uint256& txid) const { set result; AssertLockHeld(cs_wallet); std::map::const_iterator it = mapWallet.find(txid); if (it == mapWallet.end()) return result; const CWalletTx& wtx = it->second; std::pair range; BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { if (mapTxSpends.count(txin.prevout) <= 1) continue; // No conflict if zero or one spends range = mapTxSpends.equal_range(txin.prevout); for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) result.insert(_it->second); } return result; } bool CWallet::HasWalletSpend(const uint256& txid) const { AssertLockHeld(cs_wallet); auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0)); return (iter != mapTxSpends.end() && iter->first.hash == txid); } void CWallet::Flush(bool shutdown) { bitdb.Flush(shutdown); } bool CWallet::Verify() { if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) return true; LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); LogPrintf("Using wallet %s\n", walletFile); uiInterface.InitMessage(_("Verifying wallet...")); // Wallet file must be a plain filename without a directory if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile)) return InitError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, GetDataDir().string())); if (!bitdb.Open(GetDataDir())) { // try moving the database env out of the way boost::filesystem::path pathDatabase = GetDataDir() / "database"; boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime()); try { boost::filesystem::rename(pathDatabase, pathDatabaseBak); LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string()); } catch (const boost::filesystem::filesystem_error&) { // failure is ok (well, not really, but it's not worse than what we started with) } // try again if (!bitdb.Open(GetDataDir())) { // if it still fails, it probably means we can't even create the database env return InitError(strprintf(_("Error initializing wallet database environment %s!"), GetDataDir())); } } if (GetBoolArg("-salvagewallet", false)) { // Recover readable keypairs: if (!CWalletDB::Recover(bitdb, walletFile, true)) return false; } if (boost::filesystem::exists(GetDataDir() / walletFile)) { CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) { InitWarning(strprintf(_("Warning: Wallet file corrupt, data salvaged!" " Original %s saved as %s in %s; if" " your balance or transactions are incorrect you should" " restore from a backup."), walletFile, "wallet.{timestamp}.bak", GetDataDir())); } if (r == CDBEnv::RECOVER_FAIL) return InitError(strprintf(_("%s corrupt, salvage failed"), walletFile)); } return true; } void CWallet::SyncMetaData(pair range) { // We want all the wallet transactions in range to have the same metadata as // the oldest (smallest nOrderPos). // So: find smallest nOrderPos: int nMinOrderPos = std::numeric_limits::max(); const CWalletTx* copyFrom = NULL; for (TxSpends::iterator it = range.first; it != range.second; ++it) { const uint256& hash = it->second; int n = mapWallet[hash].nOrderPos; if (n < nMinOrderPos) { nMinOrderPos = n; copyFrom = &mapWallet[hash]; } } // Now copy data from copyFrom to rest: for (TxSpends::iterator it = range.first; it != range.second; ++it) { const uint256& hash = it->second; CWalletTx* copyTo = &mapWallet[hash]; if (copyFrom == copyTo) continue; if (!copyFrom->IsEquivalentTo(*copyTo)) continue; copyTo->mapValue = copyFrom->mapValue; copyTo->vOrderForm = copyFrom->vOrderForm; // fTimeReceivedIsTxTime not copied on purpose // nTimeReceived not copied on purpose copyTo->nTimeSmart = copyFrom->nTimeSmart; copyTo->fFromMe = copyFrom->fFromMe; copyTo->strFromAccount = copyFrom->strFromAccount; // nOrderPos not copied on purpose // cached members not copied on purpose } } /** * Outpoint is spent if any non-conflicted transaction * spends it: */ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const { const COutPoint outpoint(hash, n); pair range; range = mapTxSpends.equal_range(outpoint); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) { const uint256& wtxid = it->second; std::map::const_iterator mit = mapWallet.find(wtxid); if (mit != mapWallet.end()) { int depth = mit->second.GetDepthInMainChain(); if (depth > 0 || (depth == 0 && !mit->second.isAbandoned())) return true; // Spent } } return false; } void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid) { mapTxSpends.insert(make_pair(outpoint, wtxid)); pair range; range = mapTxSpends.equal_range(outpoint); SyncMetaData(range); } void CWallet::AddToSpends(const uint256& wtxid) { assert(mapWallet.count(wtxid)); CWalletTx& thisTx = mapWallet[wtxid]; if (thisTx.IsCoinBase()) // Coinbases don't spend anything! return; BOOST_FOREACH(const CTxIn& txin, thisTx.tx->vin) AddToSpends(txin.prevout, wtxid); } bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) { if (IsCrypted()) return false; CKeyingMaterial vMasterKey; vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); CMasterKey kMasterKey; kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE); GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); CCrypter crypter; int64_t nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod); kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime)); nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod); kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2; if (kMasterKey.nDeriveIterations < 25000) kMasterKey.nDeriveIterations = 25000; LogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations); if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod)) return false; if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey)) return false; { LOCK(cs_wallet); mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; if (fFileBacked) { assert(!pwalletdbEncryption); pwalletdbEncryption = new CWalletDB(strWalletFile); if (!pwalletdbEncryption->TxnBegin()) { delete pwalletdbEncryption; pwalletdbEncryption = NULL; return false; } pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey); } if (!EncryptKeys(vMasterKey)) { if (fFileBacked) { pwalletdbEncryption->TxnAbort(); delete pwalletdbEncryption; } // We now probably have half of our keys encrypted in memory, and half not... // die and let the user reload the unencrypted wallet. assert(false); } // Encryption was introduced in version 0.4.0 SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true); if (fFileBacked) { if (!pwalletdbEncryption->TxnCommit()) { delete pwalletdbEncryption; // We now have keys encrypted in memory, but not on disk... // die to avoid confusion and let the user reload the unencrypted wallet. assert(false); } delete pwalletdbEncryption; pwalletdbEncryption = NULL; } Lock(); Unlock(strWalletPassphrase); // if we are using HD, replace the HD master key (seed) with a new one if (IsHDEnabled()) { CKey key; CPubKey masterPubKey = GenerateNewHDMasterKey(); if (!SetHDMasterKey(masterPubKey)) return false; } NewKeyPool(); Lock(); // Need to completely rewrite the wallet file; if we don't, bdb might keep // bits of the unencrypted private key in slack space in the database file. CDB::Rewrite(strWalletFile); } NotifyStatusChanged(this); return true; } DBErrors CWallet::ReorderTransactions() { LOCK(cs_wallet); CWalletDB walletdb(strWalletFile); // Old wallets didn't have any defined order for transactions // Probably a bad idea to change the output of this // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap. typedef pair TxPair; typedef multimap TxItems; TxItems txByTime; for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { CWalletTx* wtx = &((*it).second); txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0))); } list acentries; walletdb.ListAccountCreditDebit("", acentries); BOOST_FOREACH(CAccountingEntry& entry, acentries) { txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); } nOrderPosNext = 0; std::vector nOrderPosOffsets; for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it) { CWalletTx *const pwtx = (*it).second.first; CAccountingEntry *const pacentry = (*it).second.second; int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos; if (nOrderPos == -1) { nOrderPos = nOrderPosNext++; nOrderPosOffsets.push_back(nOrderPos); if (pwtx) { if (!walletdb.WriteTx(*pwtx)) return DB_LOAD_FAIL; } else if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) return DB_LOAD_FAIL; } else { int64_t nOrderPosOff = 0; BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets) { if (nOrderPos >= nOffsetStart) ++nOrderPosOff; } nOrderPos += nOrderPosOff; nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1); if (!nOrderPosOff) continue; // Since we're changing the order, write it back if (pwtx) { if (!walletdb.WriteTx(*pwtx)) return DB_LOAD_FAIL; } else if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) return DB_LOAD_FAIL; } } walletdb.WriteOrderPosNext(nOrderPosNext); return DB_LOAD_OK; } int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { AssertLockHeld(cs_wallet); // nOrderPosNext int64_t nRet = nOrderPosNext++; if (pwalletdb) { pwalletdb->WriteOrderPosNext(nOrderPosNext); } else { CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext); } return nRet; } bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment) { CWalletDB walletdb(strWalletFile); if (!walletdb.TxnBegin()) return false; int64_t nNow = GetAdjustedTime(); // Debit CAccountingEntry debit; debit.nOrderPos = IncOrderPosNext(&walletdb); debit.strAccount = strFrom; debit.nCreditDebit = -nAmount; debit.nTime = nNow; debit.strOtherAccount = strTo; debit.strComment = strComment; AddAccountingEntry(debit, &walletdb); // Credit CAccountingEntry credit; credit.nOrderPos = IncOrderPosNext(&walletdb); credit.strAccount = strTo; credit.nCreditDebit = nAmount; credit.nTime = nNow; credit.strOtherAccount = strFrom; credit.strComment = strComment; AddAccountingEntry(credit, &walletdb); if (!walletdb.TxnCommit()) return false; return true; } bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew) { CWalletDB walletdb(strWalletFile); CAccount account; walletdb.ReadAccount(strAccount, account); if (!bForceNew) { if (!account.vchPubKey.IsValid()) bForceNew = true; else { // Check if the current key has been used CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); for (map::iterator it = mapWallet.begin(); it != mapWallet.end() && account.vchPubKey.IsValid(); ++it) BOOST_FOREACH(const CTxOut& txout, (*it).second.tx->vout) if (txout.scriptPubKey == scriptPubKey) { bForceNew = true; break; } } } // Generate a new key if (bForceNew) { if (!GetKeyFromPool(account.vchPubKey)) return false; SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive"); walletdb.WriteAccount(strAccount, account); } pubKey = account.vchPubKey; return true; } void CWallet::MarkDirty() { { LOCK(cs_wallet); BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) item.second.MarkDirty(); } } bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash) { LOCK(cs_wallet); auto mi = mapWallet.find(originalHash); // There is a bug if MarkReplaced is not called on an existing wallet transaction. assert(mi != mapWallet.end()); CWalletTx& wtx = (*mi).second; // Ensure for now that we're not overwriting data assert(wtx.mapValue.count("replaced_by_txid") == 0); wtx.mapValue["replaced_by_txid"] = newHash.ToString(); CWalletDB walletdb(strWalletFile, "r+"); bool success = true; if (!walletdb.WriteTx(wtx)) { LogPrintf("%s: Updating walletdb tx %s failed", __func__, wtx.GetId().ToString()); success = false; } NotifyTransactionChanged(this, originalHash, CT_UPDATED); return success; } bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) { LOCK(cs_wallet); CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose); uint256 hash = wtxIn.GetId(); // Inserts only if not already there, returns tx inserted or tx found pair::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; wtx.BindWallet(this); bool fInsertedNew = ret.second; if (fInsertedNew) { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(&walletdb); wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); wtx.nTimeSmart = wtx.nTimeReceived; if (!wtxIn.hashUnset()) { if (mapBlockIndex.count(wtxIn.hashBlock)) { int64_t latestNow = wtx.nTimeReceived; int64_t latestEntry = 0; { // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future int64_t latestTolerated = latestNow + 300; const TxItems & txOrdered = wtxOrdered; for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx == &wtx) continue; CAccountingEntry *const pacentry = (*it).second.second; int64_t nSmartTime; if (pwtx) { nSmartTime = pwtx->nTimeSmart; if (!nSmartTime) nSmartTime = pwtx->nTimeReceived; } else nSmartTime = pacentry->nTime; if (nSmartTime <= latestTolerated) { latestEntry = nSmartTime; if (nSmartTime > latestNow) latestNow = nSmartTime; break; } } } int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime(); wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); } else LogPrintf("AddToWallet(): found %s in block %s not in index\n", wtxIn.GetId().ToString(), wtxIn.hashBlock.ToString()); } AddToSpends(hash); } bool fUpdated = false; if (!fInsertedNew) { // Merge if (!wtxIn.hashUnset() && wtxIn.hashBlock != wtx.hashBlock) { wtx.hashBlock = wtxIn.hashBlock; fUpdated = true; } // If no longer abandoned, update if (wtxIn.hashBlock.IsNull() && wtx.isAbandoned()) { wtx.hashBlock = wtxIn.hashBlock; fUpdated = true; } if (wtxIn.nIndex != -1 && (wtxIn.nIndex != wtx.nIndex)) { wtx.nIndex = wtxIn.nIndex; fUpdated = true; } if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) { wtx.fFromMe = wtxIn.fFromMe; fUpdated = true; } } //// debug print LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetId().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); // Write to disk if (fInsertedNew || fUpdated) if (!walletdb.WriteTx(wtx)) return false; // Break debit/credit balance caches: wtx.MarkDirty(); // Notify UI of new or updated transaction NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); // notify an external script when a wallet transaction comes in or is updated std::string strCmd = GetArg("-walletnotify", ""); if ( !strCmd.empty()) { boost::replace_all(strCmd, "%s", wtxIn.GetId().GetHex()); boost::thread t(runCommand, strCmd); // thread runs free } return true; } bool CWallet::LoadToWallet(const CWalletTx& wtxIn) { uint256 txid = wtxIn.GetId(); mapWallet[txid] = wtxIn; CWalletTx& wtx = mapWallet[txid]; wtx.BindWallet(this); wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); AddToSpends(txid); BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { if (mapWallet.count(txin.prevout.hash)) { CWalletTx& prevtx = mapWallet[txin.prevout.hash]; if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { MarkConflicted(prevtx.hashBlock, wtx.GetId()); } } } return true; } /** * Add a transaction to the wallet, or update it. pIndex and posInBlock should * be set when the transaction was known to be included in a block. When * posInBlock = SYNC_TRANSACTION_NOT_IN_BLOCK (-1) , then wallet state is not * updated in AddToWallet, but notifications happen and cached balances are * marked dirty. * If fUpdate is true, existing transactions will be updated. * TODO: One exception to this is that the abandoned state is cleared under the * assumption that any further notification of a transaction that was considered * abandoned is an indication that it is not safe to be considered abandoned. * Abandoned state should probably be more carefuly tracked via different * posInBlock signals or by checking mempool presence when necessary. */ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) { { AssertLockHeld(cs_wallet); if (posInBlock != -1) { BOOST_FOREACH(const CTxIn& txin, tx.vin) { std::pair range = mapTxSpends.equal_range(txin.prevout); while (range.first != range.second) { if (range.first->second != tx.GetId()) { LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetId().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n); MarkConflicted(pIndex->GetBlockHash(), range.first->second); } range.first++; } } } bool fExisted = mapWallet.count(tx.GetId()) != 0; if (fExisted && !fUpdate) return false; if (fExisted || IsMine(tx) || IsFromMe(tx)) { CWalletTx wtx(this, MakeTransactionRef(tx)); // Get merkle branch if transaction was found in a block if (posInBlock != -1) wtx.SetMerkleBranch(pIndex, posInBlock); return AddToWallet(wtx, false); } } return false; } bool CWallet::AbandonTransaction(const uint256& hashTx) { LOCK2(cs_main, cs_wallet); CWalletDB walletdb(strWalletFile, "r+"); std::set todo; std::set done; // Can't mark abandoned if confirmed or in mempool assert(mapWallet.count(hashTx)); CWalletTx& origtx = mapWallet[hashTx]; if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) { return false; } todo.insert(hashTx); while (!todo.empty()) { uint256 now = *todo.begin(); todo.erase(now); done.insert(now); assert(mapWallet.count(now)); CWalletTx& wtx = mapWallet[now]; int currentconfirm = wtx.GetDepthInMainChain(); // If the orig tx was not in block, none of its spends can be assert(currentconfirm <= 0); // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon} if (currentconfirm == 0 && !wtx.isAbandoned()) { // If the orig tx was not in block/mempool, none of its spends can be in mempool assert(!wtx.InMempool()); wtx.nIndex = -1; wtx.setAbandoned(); wtx.MarkDirty(); walletdb.WriteTx(wtx); NotifyTransactionChanged(this, wtx.GetId(), CT_UPDATED); // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0)); while (iter != mapTxSpends.end() && iter->first.hash == now) { if (!done.count(iter->second)) { todo.insert(iter->second); } iter++; } // If a transaction changes 'conflicted' state, that changes the balance // available of the outputs it spends. So force those to be recomputed BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { if (mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); } } } return true; } void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) { LOCK2(cs_main, cs_wallet); int conflictconfirms = 0; if (mapBlockIndex.count(hashBlock)) { CBlockIndex* pindex = mapBlockIndex[hashBlock]; if (chainActive.Contains(pindex)) { conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1); } } // If number of conflict confirms cannot be determined, this means // that the block is still unknown or not yet part of the main chain, // for example when loading the wallet during a reindex. Do nothing in that // case. if (conflictconfirms >= 0) return; // Do not flush the wallet here for performance reasons CWalletDB walletdb(strWalletFile, "r+", false); std::set todo; std::set done; todo.insert(hashTx); while (!todo.empty()) { uint256 now = *todo.begin(); todo.erase(now); done.insert(now); assert(mapWallet.count(now)); CWalletTx& wtx = mapWallet[now]; int currentconfirm = wtx.GetDepthInMainChain(); if (conflictconfirms < currentconfirm) { // Block is 'more conflicted' than current confirm; update. // Mark transaction as conflicted with this block. wtx.nIndex = -1; wtx.hashBlock = hashBlock; wtx.MarkDirty(); walletdb.WriteTx(wtx); // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0)); while (iter != mapTxSpends.end() && iter->first.hash == now) { if (!done.count(iter->second)) { todo.insert(iter->second); } iter++; } // If a transaction changes 'conflicted' state, that changes the balance // available of the outputs it spends. So force those to be recomputed BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { if (mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); } } } } void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock) { LOCK2(cs_main, cs_wallet); if (!AddToWalletIfInvolvingMe(tx, pindex, posInBlock, true)) return; // Not one of ours // If a transaction changes 'conflicted' state, that changes the balance // available of the outputs it spends. So force those to be // recomputed, also: BOOST_FOREACH(const CTxIn& txin, tx.vin) { if (mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); } } isminetype CWallet::IsMine(const CTxIn &txin) const { { LOCK(cs_wallet); map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; if (txin.prevout.n < prev.tx->vout.size()) return IsMine(prev.tx->vout[txin.prevout.n]); } } return ISMINE_NO; } // Note that this function doesn't distinguish between a 0-valued input, // and a not-"is mine" (according to the filter) input. CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const { { LOCK(cs_wallet); map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; if (txin.prevout.n < prev.tx->vout.size()) if (IsMine(prev.tx->vout[txin.prevout.n]) & filter) return prev.tx->vout[txin.prevout.n].nValue; } } return 0; } isminetype CWallet::IsMine(const CTxOut& txout) const { return ::IsMine(*this, txout.scriptPubKey); } CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const { if (!MoneyRange(txout.nValue)) throw std::runtime_error(std::string(__func__) + ": value out of range"); return ((IsMine(txout) & filter) ? txout.nValue : 0); } bool CWallet::IsChange(const CTxOut& txout) const { // TODO: fix handling of 'change' outputs. The assumption is that any // payment to a script that is ours, but is not in the address book // is change. That assumption is likely to break when we implement multisignature // wallets that return change back into a multi-signature-protected address; // a better way of identifying which outputs are 'the send' and which are // 'the change' will need to be implemented (maybe extend CWalletTx to remember // which output, if any, was change). if (::IsMine(*this, txout.scriptPubKey)) { CTxDestination address; if (!ExtractDestination(txout.scriptPubKey, address)) return true; LOCK(cs_wallet); if (!mapAddressBook.count(address)) return true; } return false; } CAmount CWallet::GetChange(const CTxOut& txout) const { if (!MoneyRange(txout.nValue)) throw std::runtime_error(std::string(__func__) + ": value out of range"); return (IsChange(txout) ? txout.nValue : 0); } bool CWallet::IsMine(const CTransaction& tx) const { BOOST_FOREACH(const CTxOut& txout, tx.vout) if (IsMine(txout)) return true; return false; } bool CWallet::IsFromMe(const CTransaction& tx) const { return (GetDebit(tx, ISMINE_ALL) > 0); } CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const { CAmount nDebit = 0; BOOST_FOREACH(const CTxIn& txin, tx.vin) { nDebit += GetDebit(txin, filter); if (!MoneyRange(nDebit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } return nDebit; } bool CWallet::IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const { LOCK(cs_wallet); BOOST_FOREACH(const CTxIn& txin, tx.vin) { auto mi = mapWallet.find(txin.prevout.hash); if (mi == mapWallet.end()) return false; // any unknown inputs can't be from us const CWalletTx& prev = (*mi).second; if (txin.prevout.n >= prev.tx->vout.size()) return false; // invalid input! if (!(IsMine(prev.tx->vout[txin.prevout.n]) & filter)) return false; } return true; } CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const { CAmount nCredit = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { nCredit += GetCredit(txout, filter); if (!MoneyRange(nCredit)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } return nCredit; } CAmount CWallet::GetChange(const CTransaction& tx) const { CAmount nChange = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { nChange += GetChange(txout); if (!MoneyRange(nChange)) throw std::runtime_error(std::string(__func__) + ": value out of range"); } return nChange; } 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(std::string(__func__) + ": AddKeyPubKey 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 keyid (hash160) together with // the child index counter in the database // as a hdchain object CHDChain newHdChain; newHdChain.masterKeyID = pubkey.GetID(); SetHDChain(newHdChain, false); return true; } bool CWallet::SetHDChain(const CHDChain& chain, bool memonly) { LOCK(cs_wallet); if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain)) throw runtime_error(std::string(__func__) + ": writing chain failed"); hdChain = chain; return true; } bool CWallet::IsHDEnabled() { return !hdChain.masterKeyID.IsNull(); } int64_t CWalletTx::GetTxTime() const { int64_t n = nTimeSmart; return n ? n : nTimeReceived; } int CWalletTx::GetRequestCount() const { // Returns -1 if it wasn't being tracked int nRequests = -1; { LOCK(pwallet->cs_wallet); if (IsCoinBase()) { // Generated block if (!hashUnset()) { map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; } } else { // Did anyone request this transaction? map::const_iterator mi = pwallet->mapRequestCount.find(GetId()); if (mi != pwallet->mapRequestCount.end()) { nRequests = (*mi).second; // How about the block it's in? if (nRequests == 0 && !hashUnset()) { map::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock); if (_mi != pwallet->mapRequestCount.end()) nRequests = (*_mi).second; else nRequests = 1; // If it's in someone else's block it must have got out } } } } return nRequests; } void CWalletTx::GetAmounts(list& listReceived, list& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const { nFee = 0; listReceived.clear(); listSent.clear(); strSentAccount = strFromAccount; // Compute fee: CAmount nDebit = GetDebit(filter); if (nDebit > 0) // debit>0 means we signed/sent this transaction { CAmount nValueOut = tx->GetValueOut(); nFee = nDebit - nValueOut; } // Sent/received. for (unsigned int i = 0; i < tx->vout.size(); ++i) { const CTxOut& txout = tx->vout[i]; isminetype fIsMine = pwallet->IsMine(txout); // Only need to handle txouts if AT LEAST one of these is true: // 1) they debit from us (sent) // 2) the output is to us (received) if (nDebit > 0) { // Don't report 'change' txouts if (pwallet->IsChange(txout)) continue; } else if (!(fIsMine & filter)) continue; // In either case, we need to get the destination address CTxDestination address; if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable()) { LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetId().ToString()); address = CNoDestination(); } COutputEntry output = {address, txout.nValue, (int)i}; // If we are debited by the transaction, add the output as a "sent" entry if (nDebit > 0) listSent.push_back(output); // If we are receiving the output, add it as a "received" entry if (fIsMine & filter) listReceived.push_back(output); } } void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, CAmount& nSent, CAmount& nFee, const isminefilter& filter) const { nReceived = nSent = nFee = 0; CAmount allFee; string strSentAccount; list listReceived; list listSent; GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); if (strAccount == strSentAccount) { BOOST_FOREACH(const COutputEntry& s, listSent) nSent += s.amount; nFee = allFee; } { LOCK(pwallet->cs_wallet); BOOST_FOREACH(const COutputEntry& r, listReceived) { if (pwallet->mapAddressBook.count(r.destination)) { map::const_iterator mi = pwallet->mapAddressBook.find(r.destination); if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount) nReceived += r.amount; } else if (strAccount.empty()) { nReceived += r.amount; } } } } /** * Scan the block chain (starting in pindexStart) for transactions * from or to us. If fUpdate is true, found transactions that already * exist in the wallet will be updated. * * Returns pointer to the first block in the last contiguous range that was * successfully scanned. * */ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) { CBlockIndex* ret = nullptr; int64_t nNow = GetTime(); const CChainParams& chainParams = Params(); CBlockIndex* pindex = pindexStart; { LOCK2(cs_main, cs_wallet); // no need to read and scan block, if block was created before // our wallet birthday (as adjusted for block time variability) while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200))) pindex = chainActive.Next(pindex); ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup double dProgressStart = GuessVerificationProgress(chainParams.TxData(), pindex); double dProgressTip = GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()); while (pindex) { if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((GuessVerificationProgress(chainParams.TxData(), pindex) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) { AddToWalletIfInvolvingMe(*block.vtx[posInBlock], pindex, posInBlock, fUpdate); } if (!ret) { ret = pindex; } } else { ret = nullptr; } pindex = chainActive.Next(pindex); if (GetTime() >= nNow + 60) { nNow = GetTime(); LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex)); } } ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI } return ret; } void CWallet::ReacceptWalletTransactions() { // If transactions aren't being broadcasted, don't let them into local mempool either if (!fBroadcastTransactions) return; LOCK2(cs_main, cs_wallet); std::map mapSorted; // Sort pending wallet transactions based on their initial wallet insertion order BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) { const uint256& wtxid = item.first; CWalletTx& wtx = item.second; assert(wtx.GetId() == wtxid); int nDepth = wtx.GetDepthInMainChain(); if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) { mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); } } // Try to add wallet transactions to memory pool BOOST_FOREACH(PAIRTYPE(const int64_t, CWalletTx*)& item, mapSorted) { CWalletTx& wtx = *(item.second); LOCK(mempool.cs); CValidationState state; wtx.AcceptToMemoryPool(maxTxFee, state); } } bool CWalletTx::RelayWalletTransaction(CConnman* connman) { assert(pwallet->GetBroadcastTransactions()); if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0) { CValidationState state; /* GetDepthInMainChain already catches known conflicts. */ if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) { LogPrintf("Relaying wtx %s\n", GetId().ToString()); if (connman) { CInv inv(MSG_TX, GetId()); connman->ForEachNode([&inv](CNode* pnode) { pnode->PushInventory(inv); }); return true; } } } return false; } set CWalletTx::GetConflicts() const { set result; if (pwallet != NULL) { uint256 myHash = GetId(); result = pwallet->GetConflicts(myHash); result.erase(myHash); } return result; } CAmount CWalletTx::GetDebit(const isminefilter& filter) const { if (tx->vin.empty()) return 0; CAmount debit = 0; if(filter & ISMINE_SPENDABLE) { if (fDebitCached) debit += nDebitCached; else { nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE); fDebitCached = true; debit += nDebitCached; } } if(filter & ISMINE_WATCH_ONLY) { if(fWatchDebitCached) debit += nWatchDebitCached; else { nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY); fWatchDebitCached = true; debit += nWatchDebitCached; } } return debit; } CAmount CWalletTx::GetCredit(const isminefilter& filter) const { // Must wait until coinbase is safely deep enough in the chain before valuing it if (IsCoinBase() && GetBlocksToMaturity() > 0) return 0; CAmount credit = 0; if (filter & ISMINE_SPENDABLE) { // GetBalance can assume transactions in mapWallet won't change if (fCreditCached) credit += nCreditCached; else { nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); fCreditCached = true; credit += nCreditCached; } } if (filter & ISMINE_WATCH_ONLY) { if (fWatchCreditCached) credit += nWatchCreditCached; else { nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); fWatchCreditCached = true; credit += nWatchCreditCached; } } return credit; } CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const { if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { if (fUseCache && fImmatureCreditCached) return nImmatureCreditCached; nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); fImmatureCreditCached = true; return nImmatureCreditCached; } return 0; } CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const { if (pwallet == 0) return 0; // Must wait until coinbase is safely deep enough in the chain before valuing it if (IsCoinBase() && GetBlocksToMaturity() > 0) return 0; if (fUseCache && fAvailableCreditCached) return nAvailableCreditCached; CAmount nCredit = 0; uint256 hashTx = GetId(); for (unsigned int i = 0; i < tx->vout.size(); i++) { if (!pwallet->IsSpent(hashTx, i)) { const CTxOut &txout = tx->vout[i]; nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); if (!MoneyRange(nCredit)) throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); } } nAvailableCreditCached = nCredit; fAvailableCreditCached = true; return nCredit; } CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const { if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { if (fUseCache && fImmatureWatchCreditCached) return nImmatureWatchCreditCached; nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); fImmatureWatchCreditCached = true; return nImmatureWatchCreditCached; } return 0; } CAmount CWalletTx::GetAvailableWatchOnlyCredit(const bool& fUseCache) const { if (pwallet == 0) return 0; // Must wait until coinbase is safely deep enough in the chain before valuing it if (IsCoinBase() && GetBlocksToMaturity() > 0) return 0; if (fUseCache && fAvailableWatchCreditCached) return nAvailableWatchCreditCached; CAmount nCredit = 0; for (unsigned int i = 0; i < tx->vout.size(); i++) { if (!pwallet->IsSpent(GetId(), i)) { const CTxOut &txout = tx->vout[i]; nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY); if (!MoneyRange(nCredit)) throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); } } nAvailableWatchCreditCached = nCredit; fAvailableWatchCreditCached = true; return nCredit; } CAmount CWalletTx::GetChange() const { if (fChangeCached) return nChangeCached; nChangeCached = pwallet->GetChange(*this); fChangeCached = true; return nChangeCached; } bool CWalletTx::InMempool() const { LOCK(mempool.cs); if (mempool.exists(GetId())) { return true; } return false; } bool CWalletTx::IsTrusted() const { // Quick answer in most cases if (!CheckFinalTx(*this)) return false; int nDepth = GetDepthInMainChain(); if (nDepth >= 1) return true; if (nDepth < 0) return false; if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit return false; // Don't trust unconfirmed transactions from us unless they are in the mempool. if (!InMempool()) return false; // Trusted if all inputs are from us and are in the mempool: BOOST_FOREACH(const CTxIn& txin, tx->vin) { // Transactions not sent by us: not trusted const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash); if (parent == NULL) return false; const CTxOut& parentOut = parent->tx->vout[txin.prevout.n]; if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE) return false; } return true; } bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const { CMutableTransaction tx1 = *this->tx; CMutableTransaction tx2 = *_tx.tx; for (unsigned int i = 0; i < tx1.vin.size(); i++) tx1.vin[i].scriptSig = CScript(); for (unsigned int i = 0; i < tx2.vin.size(); i++) tx2.vin[i].scriptSig = CScript(); return CTransaction(tx1) == CTransaction(tx2); } std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman) { std::vector result; LOCK(cs_wallet); // Sort them in chronological order multimap mapSorted; BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) { CWalletTx& wtx = item.second; // Don't rebroadcast if newer than nTime: if (wtx.nTimeReceived > nTime) continue; mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); } BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) { CWalletTx& wtx = *item.second; if (wtx.RelayWalletTransaction(connman)) result.push_back(wtx.GetId()); } return result; } void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) { // Do this infrequently and randomly to avoid giving away // that these are our transactions. if (GetTime() < nNextResend || !fBroadcastTransactions) return; bool fFirst = (nNextResend == 0); nNextResend = GetTime() + GetRand(30 * 60); if (fFirst) return; // Only do it if there's been a new block since last time if (nBestBlockTime < nLastResend) return; nLastResend = GetTime(); // Rebroadcast unconfirmed txes older than 5 minutes before the last // block was found: std::vector relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman); if (!relayed.empty()) LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size()); } /** @} */ // end of mapWallet /** @defgroup Actions * * @{ */ CAmount CWallet::GetBalance() const { CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) nTotal += pcoin->GetAvailableCredit(); } } return nTotal; } CAmount CWallet::GetUnconfirmedBalance() const { CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool()) nTotal += pcoin->GetAvailableCredit(); } } return nTotal; } CAmount CWallet::GetImmatureBalance() const { CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; nTotal += pcoin->GetImmatureCredit(); } } return nTotal; } CAmount CWallet::GetWatchOnlyBalance() const { CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) nTotal += pcoin->GetAvailableWatchOnlyCredit(); } } return nTotal; } CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const { CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool()) nTotal += pcoin->GetAvailableWatchOnlyCredit(); } } return nTotal; } CAmount CWallet::GetImmatureWatchOnlyBalance() const { CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; nTotal += pcoin->GetImmatureWatchOnlyCredit(); } } return nTotal; } void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const { vCoins.clear(); { LOCK2(cs_main, cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const uint256& wtxid = it->first; const CWalletTx* pcoin = &(*it).second; if (!CheckFinalTx(*pcoin)) continue; if (fOnlyConfirmed && !pcoin->IsTrusted()) continue; if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; int nDepth = pcoin->GetDepthInMainChain(); if (nDepth < 0) continue; // We should not consider coins which aren't at least in our mempool // It's possible for these to be conflicted via ancestors which we may never be able to detect if (nDepth == 0 && !pcoin->InMempool()) continue; // We should not consider coins from transactions that are replacing // other transactions. // // Example: There is a transaction A which is replaced by bumpfee // transaction B. In this case, we want to prevent creation of // a transaction B' which spends an output of B. // // Reason: If transaction A were initially confirmed, transactions B // and B' would no longer be valid, so the user would have to create // a new transaction C to replace B'. However, in the case of a // one-block reorg, transactions B' and C might BOTH be accepted, // when the user only wanted one of them. Specifically, there could // be a 1-block reorg away from the chain where transactions A and C // were accepted to another chain where B, B', and C were all // accepted. if (nDepth == 0 && fOnlyConfirmed && pcoin->mapValue.count("replaces_txid")) { continue; } // Similarly, we should not consider coins from transactions that // have been replaced. In the example above, we would want to prevent // creation of a transaction A' spending an output of A, because if // transaction B were initially confirmed, conflicting with A and // A', we wouldn't want to the user to create a transaction D // intending to replace A', but potentially resulting in a scenario // where A, A', and D could all be accepted (instead of just B and // D, or just A and A' like the user would want). if (nDepth == 0 && fOnlyConfirmed && pcoin->mapValue.count("replaced_by_txid")) { continue; } for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { isminetype mine = IsMine(pcoin->tx->vout[i]); if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && !IsLockedCoin((*it).first, i) && (pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) && (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected(COutPoint((*it).first, i)))) vCoins.push_back(COutput(pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO), (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO)); } } } } static void ApproximateBestSubset(vector > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, vector& vfBest, CAmount& nBest, int iterations = 1000) { vector vfIncluded; vfBest.assign(vValue.size(), true); nBest = nTotalLower; FastRandomContext insecure_rand; for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++) { vfIncluded.assign(vValue.size(), false); CAmount nTotal = 0; bool fReachedTarget = false; for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++) { for (unsigned int i = 0; i < vValue.size(); i++) { //The solver here uses a randomized algorithm, //the randomness serves no real security purpose but is just //needed to prevent degenerate behavior and it is important //that the rng is fast. We do not use a constant random sequence, //because there may be some privacy improvement by making //the selection random. if (nPass == 0 ? insecure_rand.rand32()&1 : !vfIncluded[i]) { nTotal += vValue[i].first; vfIncluded[i] = true; if (nTotal >= nTargetValue) { fReachedTarget = true; if (nTotal < nBest) { nBest = nTotal; vfBest = vfIncluded; } nTotal -= vValue[i].first; vfIncluded[i] = false; } } } } } } bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, vector vCoins, set >& setCoinsRet, CAmount& nValueRet) const { setCoinsRet.clear(); nValueRet = 0; // List of values less than target pair > coinLowestLarger; coinLowestLarger.first = std::numeric_limits::max(); coinLowestLarger.second.first = NULL; vector > > vValue; CAmount nTotalLower = 0; random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); BOOST_FOREACH(const COutput &output, vCoins) { if (!output.fSpendable) continue; const CWalletTx *pcoin = output.tx; if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs)) continue; if (!mempool.TransactionWithinChainLimit(pcoin->GetId(), nMaxAncestors)) continue; int i = output.i; CAmount n = pcoin->tx->vout[i].nValue; pair > coin = make_pair(n,make_pair(pcoin, i)); if (n == nTargetValue) { setCoinsRet.insert(coin.second); nValueRet += coin.first; return true; } else if (n < nTargetValue + MIN_CHANGE) { vValue.push_back(coin); nTotalLower += n; } else if (n < coinLowestLarger.first) { coinLowestLarger = coin; } } if (nTotalLower == nTargetValue) { for (unsigned int i = 0; i < vValue.size(); ++i) { setCoinsRet.insert(vValue[i].second); nValueRet += vValue[i].first; } return true; } if (nTotalLower < nTargetValue) { if (coinLowestLarger.second.first == NULL) return false; setCoinsRet.insert(coinLowestLarger.second); nValueRet += coinLowestLarger.first; return true; } // Solve subset sum by stochastic approximation std::sort(vValue.begin(), vValue.end(), CompareValueOnly()); std::reverse(vValue.begin(), vValue.end()); vector vfBest; CAmount nBest; ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest); if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) ApproximateBestSubset(vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest); // If we have a bigger coin and (either the stochastic approximation didn't find a good solution, // or the next bigger coin is closer), return the bigger coin if (coinLowestLarger.second.first && ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger.first <= nBest)) { setCoinsRet.insert(coinLowestLarger.second); nValueRet += coinLowestLarger.first; } else { for (unsigned int i = 0; i < vValue.size(); i++) if (vfBest[i]) { setCoinsRet.insert(vValue[i].second); nValueRet += vValue[i].first; } LogPrint("selectcoins", "SelectCoins() best subset: "); for (unsigned int i = 0; i < vValue.size(); i++) if (vfBest[i]) LogPrint("selectcoins", "%s ", FormatMoney(vValue[i].first)); LogPrint("selectcoins", "total %s\n", FormatMoney(nBest)); } return true; } bool CWallet::SelectCoins(const vector& vAvailableCoins, const CAmount& nTargetValue, set >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const { vector vCoins(vAvailableCoins); // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) { BOOST_FOREACH(const COutput& out, vCoins) { if (!out.fSpendable) continue; nValueRet += out.tx->tx->vout[out.i].nValue; setCoinsRet.insert(make_pair(out.tx, out.i)); } return (nValueRet >= nTargetValue); } // calculate value from preset inputs and store them set > setPresetCoins; CAmount nValueFromPresetInputs = 0; std::vector vPresetInputs; if (coinControl) coinControl->ListSelected(vPresetInputs); BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs) { map::const_iterator it = mapWallet.find(outpoint.hash); if (it != mapWallet.end()) { const CWalletTx* pcoin = &it->second; // Clearly invalid input, fail if (pcoin->tx->vout.size() <= outpoint.n) return false; nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue; setPresetCoins.insert(make_pair(pcoin, outpoint.n)); } else return false; // TODO: Allow non-wallet inputs } // remove preset inputs from vCoins for (vector::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();) { if (setPresetCoins.count(make_pair(it->tx, it->i))) it = vCoins.erase(it); else ++it; } size_t nMaxChainLength = std::min(GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT), GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)); bool fRejectLongChains = GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS); bool res = nTargetValue <= nValueFromPresetInputs || SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet) || SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet) || (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet)) || (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet)) || (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet)) || (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet)) || (bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits::max(), vCoins, setCoinsRet, nValueRet)); // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end()); // add preset inputs to the total value selected nValueRet += nValueFromPresetInputs; return res; } bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set& setSubtractFeeFromOutputs, bool keepReserveKey, const CTxDestination& destChange) { vector vecSend; // Turn the txout set into a CRecipient vector for (size_t idx = 0; idx < tx.vout.size(); idx++) { const CTxOut& txOut = tx.vout[idx]; CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1}; vecSend.push_back(recipient); } CCoinControl coinControl; coinControl.destChange = destChange; coinControl.fAllowOtherInputs = true; coinControl.fAllowWatchOnly = includeWatching; coinControl.fOverrideFeeRate = overrideEstimatedFeeRate; coinControl.nFeeRate = specificFeeRate; BOOST_FOREACH(const CTxIn& txin, tx.vin) coinControl.Select(txin.prevout); CReserveKey reservekey(this); CWalletTx wtx; if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, &coinControl, false)) return false; if (nChangePosInOut != -1) tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]); // Copy output sizes from new transaction; they may have had the fee subtracted from them for (unsigned int idx = 0; idx < tx.vout.size(); idx++) tx.vout[idx].nValue = wtx.tx->vout[idx].nValue; // Add new txins (keeping original txin scriptSig/order) BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { if (!coinControl.IsSelected(txin.prevout)) { tx.vin.push_back(txin); if (lockUnspents) { LOCK2(cs_main, cs_wallet); LockCoin(txin.prevout); } } } // optionally keep the change output key if (keepReserveKey) reservekey.KeepKey(); return true; } bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign) { CAmount nValue = 0; int nChangePosRequest = nChangePosInOut; unsigned int nSubtractFeeFromAmount = 0; for (const auto& recipient : vecSend) { if (nValue < 0 || recipient.nAmount < 0) { strFailReason = _("Transaction amounts must not be negative"); return false; } nValue += recipient.nAmount; if (recipient.fSubtractFeeFromAmount) nSubtractFeeFromAmount++; } if (vecSend.empty()) { strFailReason = _("Transaction must have at least one recipient"); return false; } wtxNew.fTimeReceivedIsTxTime = true; wtxNew.BindWallet(this); CMutableTransaction txNew; // Discourage fee sniping. // // For a large miner the value of the transactions in the best block and // the mempool can exceed the cost of deliberately attempting to mine two // blocks to orphan the current best block. By setting nLockTime such that // only the next block can include the transaction, we discourage this // practice as the height restricted and limited blocksize gives miners // considering fee sniping fewer options for pulling off this attack. // // A simple way to think about this is from the wallet's point of view we // always want the blockchain to move forward. By setting nLockTime this // way we're basically making the statement that we only want this // transaction to appear in the next block; we don't want to potentially // encourage reorgs by allowing transactions to appear at lower heights // than the next block in forks of the best chain. // // Of course, the subsidy is high enough, and transaction volume low // enough, that fee sniping isn't a problem yet, but by implementing a fix // now we ensure code won't be written that makes assumptions about // nLockTime that preclude a fix later. txNew.nLockTime = chainActive.Height(); // Secondly occasionally randomly pick a nLockTime even further back, so // that transactions that are delayed after signing for whatever reason, // e.g. high-latency mix networks and some CoinJoin implementations, have // better privacy. if (GetRandInt(10) == 0) txNew.nLockTime = std::max(0, (int)txNew.nLockTime - GetRandInt(100)); assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); assert(txNew.nLockTime < LOCKTIME_THRESHOLD); { set > setCoins; LOCK2(cs_main, cs_wallet); { std::vector vAvailableCoins; AvailableCoins(vAvailableCoins, true, coinControl); nFeeRet = 0; // Start with no fee and loop until there is enough fee while (true) { nChangePosInOut = nChangePosRequest; txNew.vin.clear(); txNew.vout.clear(); wtxNew.fFromMe = true; bool fFirst = true; CAmount nValueToSelect = nValue; if (nSubtractFeeFromAmount == 0) nValueToSelect += nFeeRet; double dPriority = 0; // vouts to the payees for (const auto& recipient : vecSend) { CTxOut txout(recipient.nAmount, recipient.scriptPubKey); if (recipient.fSubtractFeeFromAmount) { txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient if (fFirst) // first receiver pays the remainder not divisible by output count { fFirst = false; txout.nValue -= nFeeRet % nSubtractFeeFromAmount; } } if (txout.IsDust(dustRelayFee)) { if (recipient.fSubtractFeeFromAmount && nFeeRet > 0) { if (txout.nValue < 0) strFailReason = _("The transaction amount is too small to pay the fee"); else strFailReason = _("The transaction amount is too small to send after the fee has been deducted"); } else strFailReason = _("Transaction amount too small"); return false; } txNew.vout.push_back(txout); } // Choose coins to use CAmount nValueIn = 0; setCoins.clear(); if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl)) { strFailReason = _("Insufficient funds"); return false; } for (const auto& pcoin : setCoins) { CAmount nCredit = pcoin.first->tx->vout[pcoin.second].nValue; //The coin age after the next block (depth+1) is used instead of the current, //reflecting an assumption the user would accept a bit more delay for //a chance at a free transaction. //But mempool inputs might still be in the mempool, so their age stays 0 int age = pcoin.first->GetDepthInMainChain(); assert(age >= 0); if (age != 0) age += 1; dPriority += (double)nCredit * age; } const CAmount nChange = nValueIn - nValueToSelect; if (nChange > 0) { // Fill a vout to ourself // TODO: pass in scriptChange instead of reservekey so // change transaction isn't always pay-to-bitcoin-address CScript scriptChange; // coin control: send change to custom address if (coinControl && !boost::get(&coinControl->destChange)) scriptChange = GetScriptForDestination(coinControl->destChange); // no coin control: send change to newly generated address else { // Note: We use a new key here to keep it from being obvious which side is the change. // The drawback is that by not reusing a previous key, the change may be lost if a // backup is restored, if the backup doesn't have the new private key for the change. // If we reused the old key, it would be possible to add code to look for and // rediscover unknown transactions that were written with keys of ours to recover // post-backup change. // Reserve a new key pair from key pool CPubKey vchPubKey; bool ret; ret = reservekey.GetReservedKey(vchPubKey); if (!ret) { strFailReason = _("Keypool ran out, please call keypoolrefill first"); return false; } scriptChange = GetScriptForDestination(vchPubKey.GetID()); } CTxOut newTxOut(nChange, scriptChange); // We do not move dust-change to fees, because the sender would end up paying more than requested. // This would be against the purpose of the all-inclusive feature. // So instead we raise the change and deduct from the recipient. if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(dustRelayFee)) { CAmount nDust = newTxOut.GetDustThreshold(dustRelayFee) - newTxOut.nValue; newTxOut.nValue += nDust; // raise change until no more dust for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient { if (vecSend[i].fSubtractFeeFromAmount) { txNew.vout[i].nValue -= nDust; if (txNew.vout[i].IsDust(dustRelayFee)) { strFailReason = _("The transaction amount is too small to send after the fee has been deducted"); return false; } break; } } } // Never create dust outputs; if we would, just // add the dust to the fee. if (newTxOut.IsDust(dustRelayFee)) { nChangePosInOut = -1; nFeeRet += nChange; reservekey.ReturnKey(); } else { if (nChangePosInOut == -1) { // Insert change txn at random position: nChangePosInOut = GetRandInt(txNew.vout.size()+1); } else if ((unsigned int)nChangePosInOut > txNew.vout.size()) { strFailReason = _("Change index out of range"); return false; } vector::iterator position = txNew.vout.begin()+nChangePosInOut; txNew.vout.insert(position, newTxOut); } } else reservekey.ReturnKey(); // Fill vin // // Note how the sequence number is set to non-maxint so that // the nLockTime set above actually works. for (const auto& coin : setCoins) txNew.vin.push_back(CTxIn(coin.first->GetId(),coin.second,CScript(), std::numeric_limits::max() - 1)); // Fill in dummy signatures for fee calculation. if (!DummySignTx(txNew, setCoins)) { strFailReason = _("Signing transaction failed"); return false; } unsigned int nBytes = GetTransactionSize(txNew); CTransaction txNewConst(txNew); dPriority = txNewConst.ComputePriority(dPriority, nBytes); // Remove scriptSigs to eliminate the fee calculation dummy signatures for (auto& vin : txNew.vin) { vin.scriptSig = CScript(); - vin.scriptWitness.SetNull(); } // Allow to override the default confirmation target over the CoinControl instance int currentConfirmationTarget = nTxConfirmTarget; if (coinControl && coinControl->nConfirmTarget > 0) currentConfirmationTarget = coinControl->nConfirmTarget; // Can we complete this as a free transaction? if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE) { // Not enough fee: enough priority? double dPriorityNeeded = mempool.estimateSmartPriority(currentConfirmationTarget); // Require at least hard-coded AllowFree. if (dPriority >= dPriorityNeeded && AllowFree(dPriority)) break; } CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool); if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) { nFeeNeeded = coinControl->nMinimumTotalFee; } if (coinControl && coinControl->fOverrideFeeRate) nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes); // If we made it here and we aren't even able to meet the relay fee on the next pass, give up // because we must be at the maximum allowed fee. if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes)) { strFailReason = _("Transaction too large for fee policy"); return false; } if (nFeeRet >= nFeeNeeded) { // Reduce fee to only the needed amount if we have change // output to increase. This prevents potential overpayment // in fees if the coins selected to meet nFeeNeeded result // in a transaction that requires less fee than the prior // iteration. // TODO: The case where nSubtractFeeFromAmount > 0 remains // to be addressed because it requires returning the fee to // the payees and not the change output. // TODO: The case where there is no change output remains // to be addressed so we avoid creating too small an output. if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) { CAmount extraFeePaid = nFeeRet - nFeeNeeded; vector::iterator change_position = txNew.vout.begin()+nChangePosInOut; change_position->nValue += extraFeePaid; nFeeRet -= extraFeePaid; } break; // Done, enough fee included. } // Try to reduce change to include necessary fee if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) { CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet; vector::iterator change_position = txNew.vout.begin()+nChangePosInOut; // Only reduce change if remaining amount is still a large enough output. if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) { change_position->nValue -= additionalFeeNeeded; nFeeRet += additionalFeeNeeded; break; // Done, able to increase fee from change } } // Include more fee and try again. nFeeRet = nFeeNeeded; continue; } } if (sign) { CTransaction txNewConst(txNew); int nIn = 0; for (const auto& coin : setCoins) { const CScript& scriptPubKey = coin.first->tx->vout[coin.second].scriptPubKey; SignatureData sigdata; if (!ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->tx->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata)) { strFailReason = _("Signing transaction failed"); return false; } else { UpdateTransaction(txNew, nIn, sigdata); } nIn++; } } // Embed the constructed transaction data in wtxNew. wtxNew.SetTx(MakeTransactionRef(std::move(txNew))); // Limit size if (GetTransactionSize(wtxNew) >= MAX_STANDARD_TX_SIZE) { strFailReason = _("Transaction too large"); return false; } } if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { // Lastly, ensure this tx will pass the mempool's chain limits LockPoints lp; CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, false, 0, lp); CTxMemPool::setEntries setAncestors; size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000; size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000; std::string errString; if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) { strFailReason = _("Transaction has too long of a mempool chain"); return false; } } return true; } /** * Call after CreateTransaction unless you want to abort */ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state) { { LOCK2(cs_main, cs_wallet); LogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString()); { // Take key pair from key pool so it won't be used again reservekey.KeepKey(); // Add tx to wallet, because if it has change it's also ours, // otherwise just for transaction history. AddToWallet(wtxNew); // Notify that old coins are spent BOOST_FOREACH(const CTxIn& txin, wtxNew.tx->vin) { CWalletTx &coin = mapWallet[txin.prevout.hash]; coin.BindWallet(this); NotifyTransactionChanged(this, coin.GetId(), CT_UPDATED); } } // Track how many getdata requests our transaction gets mapRequestCount[wtxNew.GetId()] = 0; if (fBroadcastTransactions) { // Broadcast if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) { LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason()); // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure. } else { wtxNew.RelayWalletTransaction(connman); } } } return true; } void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list& entries) { CWalletDB walletdb(strWalletFile); return walletdb.ListAccountCreditDebit(strAccount, entries); } bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry) { CWalletDB walletdb(strWalletFile); return AddAccountingEntry(acentry, &walletdb); } bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwalletdb) { if (!pwalletdb->WriteAccountingEntry_Backend(acentry)) return false; laccentries.push_back(acentry); CAccountingEntry & entry = laccentries.back(); wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); return true; } CAmount CWallet::GetRequiredFee(unsigned int nTxBytes) { return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes)); } CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool) { // payTxFee is the user-set global for desired feerate return GetMinimumFee(nTxBytes, nConfirmTarget, pool, payTxFee.GetFee(nTxBytes)); } CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, CAmount targetFee) { CAmount nFeeNeeded = targetFee; // User didn't set: use -txconfirmtarget to estimate... if (nFeeNeeded == 0) { int estimateFoundTarget = nConfirmTarget; nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes); // ... unless we don't have enough mempool data for estimatefee, then use fallbackFee if (nFeeNeeded == 0) nFeeNeeded = fallbackFee.GetFee(nTxBytes); } // prevent user from paying a fee below minRelayTxFee or minTxFee nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes)); // But always obey the maximum if (nFeeNeeded > maxTxFee) nFeeNeeded = maxTxFee; return nFeeNeeded; } DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) return DB_LOAD_OK; fFirstRunRet = false; DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); if (nLoadWalletRet == DB_NEED_REWRITE) { if (CDB::Rewrite(strWalletFile, "\x04pool")) { LOCK(cs_wallet); setKeyPool.clear(); // Note: can't top-up keypool here, because wallet is locked. // User will be prompted to unlock wallet the next operation // that requires a new key. } } if (nLoadWalletRet != DB_LOAD_OK) return nLoadWalletRet; fFirstRunRet = !vchDefaultKey.IsValid(); uiInterface.LoadWallet(this); return DB_LOAD_OK; } DBErrors CWallet::ZapSelectTx(vector& vHashIn, vector& vHashOut) { if (!fFileBacked) return DB_LOAD_OK; DBErrors nZapSelectTxRet = CWalletDB(strWalletFile,"cr+").ZapSelectTx(this, vHashIn, vHashOut); if (nZapSelectTxRet == DB_NEED_REWRITE) { if (CDB::Rewrite(strWalletFile, "\x04pool")) { LOCK(cs_wallet); setKeyPool.clear(); // Note: can't top-up keypool here, because wallet is locked. // User will be prompted to unlock wallet the next operation // that requires a new key. } } if (nZapSelectTxRet != DB_LOAD_OK) return nZapSelectTxRet; MarkDirty(); return DB_LOAD_OK; } DBErrors CWallet::ZapWalletTx(std::vector& vWtx) { if (!fFileBacked) return DB_LOAD_OK; DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx); if (nZapWalletTxRet == DB_NEED_REWRITE) { if (CDB::Rewrite(strWalletFile, "\x04pool")) { LOCK(cs_wallet); setKeyPool.clear(); // Note: can't top-up keypool here, because wallet is locked. // User will be prompted to unlock wallet the next operation // that requires a new key. } } if (nZapWalletTxRet != DB_LOAD_OK) return nZapWalletTxRet; return DB_LOAD_OK; } bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose) { bool fUpdated = false; { LOCK(cs_wallet); // mapAddressBook std::map::iterator mi = mapAddressBook.find(address); fUpdated = mi != mapAddressBook.end(); mapAddressBook[address].name = strName; if (!strPurpose.empty()) /* update purpose only if requested */ mapAddressBook[address].purpose = strPurpose; } NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO, strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) ); if (!fFileBacked) return false; if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose)) return false; return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName); } bool CWallet::DelAddressBook(const CTxDestination& address) { { LOCK(cs_wallet); // mapAddressBook if(fFileBacked) { // Delete destdata tuples associated with address std::string strAddress = CBitcoinAddress(address).ToString(); BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata) { CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); } } mapAddressBook.erase(address); } NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED); if (!fFileBacked) return false; CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString()); return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); } bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) { if (fFileBacked) { if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey)) return false; } vchDefaultKey = vchPubKey; return true; } /** * Mark old keypool keys as used, * and generate all new keys */ bool CWallet::NewKeyPool() { { LOCK(cs_wallet); CWalletDB walletdb(strWalletFile); BOOST_FOREACH(int64_t nIndex, setKeyPool) walletdb.ErasePool(nIndex); setKeyPool.clear(); if (IsLocked()) return false; int64_t nKeys = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0); for (int i = 0; i < nKeys; i++) { int64_t nIndex = i+1; walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey())); setKeyPool.insert(nIndex); } LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys); } return true; } bool CWallet::TopUpKeyPool(unsigned int kpSize) { { LOCK(cs_wallet); if (IsLocked()) return false; CWalletDB walletdb(strWalletFile); // Top up key pool unsigned int nTargetSize; if (kpSize > 0) nTargetSize = kpSize; else nTargetSize = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0); while (setKeyPool.size() < (nTargetSize + 1)) { int64_t nEnd = 1; if (!setKeyPool.empty()) nEnd = *(--setKeyPool.end()) + 1; if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) throw runtime_error(std::string(__func__) + ": writing generated key failed"); setKeyPool.insert(nEnd); LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size()); } } return true; } void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool) { nIndex = -1; keypool.vchPubKey = CPubKey(); { LOCK(cs_wallet); if (!IsLocked()) TopUpKeyPool(); // Get the oldest key if(setKeyPool.empty()) return; CWalletDB walletdb(strWalletFile); nIndex = *(setKeyPool.begin()); setKeyPool.erase(setKeyPool.begin()); if (!walletdb.ReadPool(nIndex, keypool)) throw runtime_error(std::string(__func__) + ": read failed"); if (!HaveKey(keypool.vchPubKey.GetID())) throw runtime_error(std::string(__func__) + ": unknown key in key pool"); assert(keypool.vchPubKey.IsValid()); LogPrintf("keypool reserve %d\n", nIndex); } } void CWallet::KeepKey(int64_t nIndex) { // Remove from key pool if (fFileBacked) { CWalletDB walletdb(strWalletFile); walletdb.ErasePool(nIndex); } LogPrintf("keypool keep %d\n", nIndex); } void CWallet::ReturnKey(int64_t nIndex) { // Return to key pool { LOCK(cs_wallet); setKeyPool.insert(nIndex); } LogPrintf("keypool return %d\n", nIndex); } bool CWallet::GetKeyFromPool(CPubKey& result) { int64_t nIndex = 0; CKeyPool keypool; { LOCK(cs_wallet); ReserveKeyFromKeyPool(nIndex, keypool); if (nIndex == -1) { if (IsLocked()) return false; result = GenerateNewKey(); return true; } KeepKey(nIndex); result = keypool.vchPubKey; } return true; } int64_t CWallet::GetOldestKeyPoolTime() { LOCK(cs_wallet); // if the keypool is empty, return if (setKeyPool.empty()) return GetTime(); // load oldest key from keypool, get time and return CKeyPool keypool; CWalletDB walletdb(strWalletFile); int64_t nIndex = *(setKeyPool.begin()); if (!walletdb.ReadPool(nIndex, keypool)) throw runtime_error(std::string(__func__) + ": read oldest key in keypool failed"); assert(keypool.vchPubKey.IsValid()); return keypool.nTime; } std::map CWallet::GetAddressBalances() { map balances; { LOCK(cs_wallet); BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) { CWalletTx *pcoin = &walletEntry.second; if (!pcoin->IsTrusted()) continue; if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; int nDepth = pcoin->GetDepthInMainChain(); if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1)) continue; for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { CTxDestination addr; if (!IsMine(pcoin->tx->vout[i])) continue; if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr)) continue; CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue; if (!balances.count(addr)) balances[addr] = 0; balances[addr] += n; } } } return balances; } set< set > CWallet::GetAddressGroupings() { AssertLockHeld(cs_wallet); // mapWallet set< set > groupings; set grouping; BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) { CWalletTx *pcoin = &walletEntry.second; if (pcoin->tx->vin.size() > 0) { bool any_mine = false; // group all input addresses with each other BOOST_FOREACH(CTxIn txin, pcoin->tx->vin) { CTxDestination address; if(!IsMine(txin)) /* If this input isn't mine, ignore it */ continue; if(!ExtractDestination(mapWallet[txin.prevout.hash].tx->vout[txin.prevout.n].scriptPubKey, address)) continue; grouping.insert(address); any_mine = true; } // group change with input addresses if (any_mine) { BOOST_FOREACH(CTxOut txout, pcoin->tx->vout) if (IsChange(txout)) { CTxDestination txoutAddr; if(!ExtractDestination(txout.scriptPubKey, txoutAddr)) continue; grouping.insert(txoutAddr); } } if (grouping.size() > 0) { groupings.insert(grouping); grouping.clear(); } } // group lone addrs by themselves for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) if (IsMine(pcoin->tx->vout[i])) { CTxDestination address; if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, address)) continue; grouping.insert(address); groupings.insert(grouping); grouping.clear(); } } set< set* > uniqueGroupings; // a set of pointers to groups of addresses map< CTxDestination, set* > setmap; // map addresses to the unique group containing it BOOST_FOREACH(set _grouping, groupings) { // make a set of all the groups hit by this new group set< set* > hits; map< CTxDestination, set* >::iterator it; BOOST_FOREACH(CTxDestination address, _grouping) if ((it = setmap.find(address)) != setmap.end()) hits.insert((*it).second); // merge all hit groups into a new single group and delete old groups set* merged = new set(_grouping); BOOST_FOREACH(set* hit, hits) { merged->insert(hit->begin(), hit->end()); uniqueGroupings.erase(hit); delete hit; } uniqueGroupings.insert(merged); // update setmap BOOST_FOREACH(CTxDestination element, *merged) setmap[element] = merged; } set< set > ret; BOOST_FOREACH(set* uniqueGrouping, uniqueGroupings) { ret.insert(*uniqueGrouping); delete uniqueGrouping; } return ret; } CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter) { CWalletDB walletdb(strWalletFile); return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); } CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter) { CAmount nBalance = 0; // Tally wallet transactions for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) continue; CAmount nReceived, nSent, nFee; wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter); if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) nBalance += nReceived; nBalance -= nSent + nFee; } // Tally internal accounting entries nBalance += walletdb.GetAccountCreditDebit(strAccount); return nBalance; } std::set CWallet::GetAccountAddresses(const std::string& strAccount) const { LOCK(cs_wallet); set result; BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook) { const CTxDestination& address = item.first; const string& strName = item.second.name; if (strName == strAccount) result.insert(address); } return result; } bool CReserveKey::GetReservedKey(CPubKey& pubkey) { if (nIndex == -1) { CKeyPool keypool; pwallet->ReserveKeyFromKeyPool(nIndex, keypool); if (nIndex != -1) vchPubKey = keypool.vchPubKey; else { return false; } } assert(vchPubKey.IsValid()); pubkey = vchPubKey; return true; } void CReserveKey::KeepKey() { if (nIndex != -1) pwallet->KeepKey(nIndex); nIndex = -1; vchPubKey = CPubKey(); } void CReserveKey::ReturnKey() { if (nIndex != -1) pwallet->ReturnKey(nIndex); nIndex = -1; vchPubKey = CPubKey(); } void CWallet::GetAllReserveKeys(set& setAddress) const { setAddress.clear(); CWalletDB walletdb(strWalletFile); LOCK2(cs_main, cs_wallet); BOOST_FOREACH(const int64_t& id, setKeyPool) { CKeyPool keypool; if (!walletdb.ReadPool(id, keypool)) throw runtime_error(std::string(__func__) + ": read failed"); assert(keypool.vchPubKey.IsValid()); CKeyID keyID = keypool.vchPubKey.GetID(); if (!HaveKey(keyID)) throw runtime_error(std::string(__func__) + ": unknown key in key pool"); setAddress.insert(keyID); } } void CWallet::UpdatedTransaction(const uint256 &hashTx) { { LOCK(cs_wallet); // Only notify UI if this transaction is in this wallet map::const_iterator mi = mapWallet.find(hashTx); if (mi != mapWallet.end()) NotifyTransactionChanged(this, hashTx, CT_UPDATED); } } void CWallet::GetScriptForMining(boost::shared_ptr &script) { boost::shared_ptr rKey(new CReserveKey(this)); CPubKey pubkey; if (!rKey->GetReservedKey(pubkey)) return; script = rKey; script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; } void CWallet::LockCoin(const COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.insert(output); } void CWallet::UnlockCoin(const COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.erase(output); } void CWallet::UnlockAllCoins() { AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.clear(); } bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const { AssertLockHeld(cs_wallet); // setLockedCoins COutPoint outpt(hash, n); return (setLockedCoins.count(outpt) > 0); } void CWallet::ListLockedCoins(std::vector& vOutpts) { AssertLockHeld(cs_wallet); // setLockedCoins for (std::set::iterator it = setLockedCoins.begin(); it != setLockedCoins.end(); it++) { COutPoint outpt = (*it); vOutpts.push_back(outpt); } } /** @} */ // end of Actions class CAffectedKeysVisitor : public boost::static_visitor { private: const CKeyStore &keystore; std::vector &vKeys; public: CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {} void Process(const CScript &script) { txnouttype type; std::vector vDest; int nRequired; if (ExtractDestinations(script, type, vDest, nRequired)) { BOOST_FOREACH(const CTxDestination &dest, vDest) boost::apply_visitor(*this, dest); } } void operator()(const CKeyID &keyId) { if (keystore.HaveKey(keyId)) vKeys.push_back(keyId); } void operator()(const CScriptID &scriptId) { CScript script; if (keystore.GetCScript(scriptId, script)) Process(script); } void operator()(const CNoDestination &none) {} }; void CWallet::GetKeyBirthTimes(std::map &mapKeyBirth) const { AssertLockHeld(cs_wallet); // mapKeyMetadata mapKeyBirth.clear(); // get birth times for keys with metadata for (const auto& entry : mapKeyMetadata) { if (entry.second.nCreateTime) { mapKeyBirth[entry.first] = entry.second.nCreateTime; } } // map in which we'll infer heights of other keys CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin std::map mapKeyFirstBlock; std::set setKeys; GetKeys(setKeys); BOOST_FOREACH(const CKeyID &keyid, setKeys) { if (mapKeyBirth.count(keyid) == 0) mapKeyFirstBlock[keyid] = pindexMax; } setKeys.clear(); // if there are no such keys, we're done if (mapKeyFirstBlock.empty()) return; // find first block that affects those keys, if there are any left std::vector vAffected; for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { // iterate over all wallet transactions... const CWalletTx &wtx = (*it).second; BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) { // ... which are already in a block int nHeight = blit->second->nHeight; BOOST_FOREACH(const CTxOut &txout, wtx.tx->vout) { // iterate over all their outputs CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey); BOOST_FOREACH(const CKeyID &keyid, vAffected) { // ... and all their affected keys std::map::iterator rit = mapKeyFirstBlock.find(keyid); if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight) rit->second = blit->second; } vAffected.clear(); } } } // Extract block timestamps for those keys for (std::map::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++) mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off } bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value) { if (boost::get(&dest)) return false; mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); if (!fFileBacked) return true; return CWalletDB(strWalletFile).WriteDestData(CBitcoinAddress(dest).ToString(), key, value); } bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key) { if (!mapAddressBook[dest].destdata.erase(key)) return false; if (!fFileBacked) return true; return CWalletDB(strWalletFile).EraseDestData(CBitcoinAddress(dest).ToString(), key); } bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) { mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); return true; } bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const { std::map::const_iterator i = mapAddressBook.find(dest); if(i != mapAddressBook.end()) { CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key); if(j != i->second.destdata.end()) { if(value) *value = j->second; return true; } } return false; } std::string CWallet::GetWalletHelpString(bool showDebug) { std::string strUsage = HelpMessageGroup(_("Wallet options:")); strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), DEFAULT_KEYPOOL_SIZE)); strUsage += HelpMessageOpt("-fallbackfee=", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE))); strUsage += HelpMessageOpt("-mintxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); strUsage += HelpMessageOpt("-paytxfee=", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup")); if (showDebug) strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS)); strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); strUsage += HelpMessageOpt("-txconfirmtarget=", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET)); strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup")); strUsage += HelpMessageOpt("-wallet=", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT)); strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST)); strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)")); strUsage += HelpMessageOpt("-zapwallettxes=", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") + " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)")); if (showDebug) { strUsage += HelpMessageGroup(_("Wallet debugging/testing options:")); strUsage += HelpMessageOpt("-dblogsize=", strprintf("Flush wallet database activity from memory to disk log every megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET)); strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB)); strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS)); } return strUsage; } CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) { // needed to restore wallet transaction meta data after -zapwallettxes std::vector vWtx; if (GetBoolArg("-zapwallettxes", false)) { uiInterface.InitMessage(_("Zapping all transactions from wallet...")); CWallet *tempWallet = new CWallet(walletFile); DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); if (nZapWalletRet != DB_LOAD_OK) { InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); return NULL; } delete tempWallet; tempWallet = NULL; } uiInterface.InitMessage(_("Loading wallet...")); int64_t nStart = GetTimeMillis(); bool fFirstRun = true; CWallet *walletInstance = new CWallet(walletFile); DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); if (nLoadWalletRet != DB_LOAD_OK) { if (nLoadWalletRet == DB_CORRUPT) { InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); return NULL; } else if (nLoadWalletRet == DB_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) { InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME))); return NULL; } else if (nLoadWalletRet == DB_NEED_REWRITE) { InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME))); return NULL; } else { InitError(strprintf(_("Error loading %s"), walletFile)); return NULL; } } if (GetBoolArg("-upgradewallet", fFirstRun)) { int nMaxVersion = GetArg("-upgradewallet", 0); if (nMaxVersion == 0) // the -upgradewallet without argument case { LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); nMaxVersion = CLIENT_VERSION; walletInstance->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately } else LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); if (nMaxVersion < walletInstance->GetVersion()) { InitError(_("Cannot downgrade wallet")); return NULL; } walletInstance->SetMaxVersion(nMaxVersion); } if (fFirstRun) { // Create new keyUser and set as default key if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) { // generate a new master key CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey(); if (!walletInstance->SetHDMasterKey(masterPubKey)) throw std::runtime_error(std::string(__func__) + ": Storing master key failed"); } CPubKey newDefaultKey; if (walletInstance->GetKeyFromPool(newDefaultKey)) { walletInstance->SetDefaultKey(newDefaultKey); if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) { InitError(_("Cannot write default address") += "\n"); return NULL; } } walletInstance->SetBestChain(chainActive.GetLocator()); } else if (IsArgSet("-usehd")) { bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET); if (walletInstance->IsHDEnabled() && !useHD) { InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile)); return NULL; } if (!walletInstance->IsHDEnabled() && useHD) { InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile)); return NULL; } } LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); RegisterValidationInterface(walletInstance); CBlockIndex *pindexRescan = chainActive.Tip(); if (GetBoolArg("-rescan", false)) pindexRescan = chainActive.Genesis(); else { CWalletDB walletdb(walletFile); CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) pindexRescan = FindForkInGlobalIndex(chainActive, locator); else pindexRescan = chainActive.Genesis(); } if (chainActive.Tip() && chainActive.Tip() != pindexRescan) { //We can't rescan beyond non-pruned blocks, stop and throw an error //this might happen if a user uses a old wallet within a pruned node // or if he ran -disablewallet for a longer time, then decided to re-enable if (fPruneMode) { CBlockIndex *block = chainActive.Tip(); while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block) block = block->pprev; if (pindexRescan != block) { InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); return NULL; } } uiInterface.InitMessage(_("Rescanning...")); LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); nStart = GetTimeMillis(); walletInstance->ScanForWalletTransactions(pindexRescan, true); LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); walletInstance->SetBestChain(chainActive.GetLocator()); CWalletDB::IncrementUpdateCounter(); // Restore wallet transaction metadata after -zapwallettxes=1 if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") { CWalletDB walletdb(walletFile); BOOST_FOREACH(const CWalletTx& wtxOld, vWtx) { uint256 txid = wtxOld.GetId(); std::map::iterator mi = walletInstance->mapWallet.find(txid); if (mi != walletInstance->mapWallet.end()) { const CWalletTx* copyFrom = &wtxOld; CWalletTx* copyTo = &mi->second; copyTo->mapValue = copyFrom->mapValue; copyTo->vOrderForm = copyFrom->vOrderForm; copyTo->nTimeReceived = copyFrom->nTimeReceived; copyTo->nTimeSmart = copyFrom->nTimeSmart; copyTo->fFromMe = copyFrom->fFromMe; copyTo->strFromAccount = copyFrom->strFromAccount; copyTo->nOrderPos = copyFrom->nOrderPos; walletdb.WriteTx(*copyTo); } } } } walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); { LOCK(walletInstance->cs_wallet); LogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize()); LogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size()); LogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size()); } return walletInstance; } bool CWallet::InitLoadWallet() { if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { pwalletMain = NULL; LogPrintf("Wallet disabled!\n"); return true; } std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); CWallet * const pwallet = CreateWalletFromFile(walletFile); if (!pwallet) { return false; } pwalletMain = pwallet; return true; } std::atomic CWallet::fFlushThreadRunning(false); void CWallet::postInitProcess(boost::thread_group& threadGroup) { // Add wallet transactions that aren't already in a block to mempool // Do this here as mempool requires genesis block to be loaded ReacceptWalletTransactions(); // Run a thread to flush wallet periodically if (!CWallet::fFlushThreadRunning.exchange(true)) { threadGroup.create_thread(ThreadFlushWalletDB); } } bool CWallet::ParameterInteraction() { if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) return true; if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && SoftSetBoolArg("-walletbroadcast", false)) { LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); } if (GetBoolArg("-salvagewallet", false) && SoftSetBoolArg("-rescan", true)) { // Rewrite just private keys: rescan to find transactions LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__); } // -zapwallettx implies a rescan if (GetBoolArg("-zapwallettxes", false) && SoftSetBoolArg("-rescan", true)) { LogPrintf("%s: parameter interaction: -zapwallettxes= -> setting -rescan=1\n", __func__); } if (GetBoolArg("-sysperms", false)) return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); if (GetArg("-prune", 0) && GetBoolArg("-rescan", false)) return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB) InitWarning(AmountHighWarn("-minrelaytxfee") + " " + _("The wallet will avoid paying less than the minimum relay fee.")); if (IsArgSet("-mintxfee")) { CAmount n = 0; if (!ParseMoney(GetArg("-mintxfee", ""), n) || 0 == n) return InitError(AmountErrMsg("mintxfee", GetArg("-mintxfee", ""))); if (n > HIGH_TX_FEE_PER_KB) InitWarning(AmountHighWarn("-mintxfee") + " " + _("This is the minimum transaction fee you pay on every transaction.")); CWallet::minTxFee = CFeeRate(n); } if (IsArgSet("-fallbackfee")) { CAmount nFeePerK = 0; if (!ParseMoney(GetArg("-fallbackfee", ""), nFeePerK)) return InitError(strprintf(_("Invalid amount for -fallbackfee=: '%s'"), GetArg("-fallbackfee", ""))); if (nFeePerK > HIGH_TX_FEE_PER_KB) InitWarning(AmountHighWarn("-fallbackfee") + " " + _("This is the transaction fee you may pay when fee estimates are not available.")); CWallet::fallbackFee = CFeeRate(nFeePerK); } if (IsArgSet("-paytxfee")) { CAmount nFeePerK = 0; if (!ParseMoney(GetArg("-paytxfee", ""), nFeePerK)) return InitError(AmountErrMsg("paytxfee", GetArg("-paytxfee", ""))); if (nFeePerK > HIGH_TX_FEE_PER_KB) InitWarning(AmountHighWarn("-paytxfee") + " " + _("This is the transaction fee you will pay if you send a transaction.")); payTxFee = CFeeRate(nFeePerK, 1000); if (payTxFee < ::minRelayTxFee) { return InitError(strprintf(_("Invalid amount for -paytxfee=: '%s' (must be at least %s)"), GetArg("-paytxfee", ""), ::minRelayTxFee.ToString())); } } if (IsArgSet("-maxtxfee")) { CAmount nMaxFee = 0; if (!ParseMoney(GetArg("-maxtxfee", ""), nMaxFee)) return InitError(AmountErrMsg("maxtxfee", GetArg("-maxtxfee", ""))); if (nMaxFee > HIGH_MAX_TX_FEE) InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); maxTxFee = nMaxFee; if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) { return InitError(strprintf(_("Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString())); } } nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS); if (fSendFreeTransactions && GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0) return InitError("Creation of free transactions with their relay disabled is not supported."); return true; } bool CWallet::BackupWallet(const std::string& strDest) { if (!fFileBacked) return false; while (true) { { LOCK(bitdb.cs_db); if (!bitdb.mapFileUseCount.count(strWalletFile) || bitdb.mapFileUseCount[strWalletFile] == 0) { // Flush log data to the dat file bitdb.CloseDb(strWalletFile); bitdb.CheckpointLSN(strWalletFile); bitdb.mapFileUseCount.erase(strWalletFile); // Copy wallet file boost::filesystem::path pathSrc = GetDataDir() / strWalletFile; boost::filesystem::path pathDest(strDest); if (boost::filesystem::is_directory(pathDest)) pathDest /= strWalletFile; try { #if BOOST_VERSION >= 104000 boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists); #else boost::filesystem::copy_file(pathSrc, pathDest); #endif LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string()); return true; } catch (const boost::filesystem::filesystem_error& e) { LogPrintf("error copying %s to %s - %s\n", strWalletFile, pathDest.string(), e.what()); return false; } } } MilliSleep(100); } return false; } CKeyPool::CKeyPool() { nTime = GetTime(); } CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn) { nTime = GetTime(); vchPubKey = vchPubKeyIn; } CWalletKey::CWalletKey(int64_t nExpires) { nTimeCreated = (nExpires ? GetTime() : 0); nTimeExpires = nExpires; } void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock) { // Update the tx's hashBlock hashBlock = pindex->GetBlockHash(); // set the position of the transaction in the block nIndex = posInBlock; } int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const { if (hashUnset()) return 0; AssertLockHeld(cs_main); // Find the block it claims to be in BlockMap::iterator mi = mapBlockIndex.find(hashBlock); if (mi == mapBlockIndex.end()) return 0; CBlockIndex* pindex = (*mi).second; if (!pindex || !chainActive.Contains(pindex)) return 0; pindexRet = pindex; return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1); } int CMerkleTx::GetBlocksToMaturity() const { if (!IsCoinBase()) return 0; return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain()); } bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state) { return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee); }