aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/gitian-downloader/jonasschnelli-key.pgpbin0 -> 2230 bytes
-rw-r--r--contrib/gitian-downloader/jonasschnelli.pgpbin4460 -> 0 bytes
-rwxr-xr-xqa/rpc-tests/bipdersig.py90
-rwxr-xr-xqa/rpc-tests/getblocktemplate_proposals.py1
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/chainparams.cpp20
-rw-r--r--src/checkqueue.h12
-rw-r--r--src/crypter.cpp39
-rw-r--r--src/crypter.h3
-rw-r--r--src/init.cpp22
-rw-r--r--src/keystore.cpp2
-rw-r--r--src/keystore.h5
-rw-r--r--src/main.cpp38
-rw-r--r--src/main.h2
-rw-r--r--src/net.cpp2
-rw-r--r--src/primitives/block.h2
-rw-r--r--src/qt/bitcoinamountfield.cpp1
-rw-r--r--src/qt/forms/helpmessagedialog.ui82
-rw-r--r--src/qt/sendcoinsdialog.cpp4
-rw-r--r--src/qt/utilitydialog.cpp1
-rw-r--r--src/qt/walletmodel.cpp4
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/rpcblockchain.cpp19
-rw-r--r--src/rpcdump.cpp10
-rw-r--r--src/rpcmining.cpp19
-rw-r--r--src/rpcmisc.cpp16
-rw-r--r--src/rpcnet.cpp10
-rw-r--r--src/rpcrawtransaction.cpp16
-rw-r--r--src/rpcserver.cpp242
-rw-r--r--src/rpcserver.h11
-rw-r--r--src/rpcwallet.cpp69
-rw-r--r--src/script/bitcoinconsensus.cpp2
-rw-r--r--src/script/bitcoinconsensus.h1
-rw-r--r--src/script/interpreter.cpp132
-rw-r--r--src/script/interpreter.h16
-rw-r--r--src/script/sigcache.cpp4
-rw-r--r--src/script/sigcache.h4
-rw-r--r--src/script/sign.cpp4
-rw-r--r--src/script/standard.h3
-rw-r--r--src/sync.h11
-rw-r--r--src/test/data/script_invalid.json106
-rw-r--r--src/test/data/script_valid.json58
-rw-r--r--src/test/multisig_tests.cpp16
-rw-r--r--src/test/script_P2SH_tests.cpp2
-rw-r--r--src/test/script_tests.cpp101
-rw-r--r--src/test/transaction_tests.cpp12
-rw-r--r--src/test/util_tests.cpp18
-rw-r--r--src/wallet.cpp199
-rw-r--r--src/wallet.h825
49 files changed, 1437 insertions, 823 deletions
diff --git a/contrib/gitian-downloader/jonasschnelli-key.pgp b/contrib/gitian-downloader/jonasschnelli-key.pgp
new file mode 100644
index 0000000000..fe44c0fbd4
--- /dev/null
+++ b/contrib/gitian-downloader/jonasschnelli-key.pgp
Binary files differ
diff --git a/contrib/gitian-downloader/jonasschnelli.pgp b/contrib/gitian-downloader/jonasschnelli.pgp
deleted file mode 100644
index 96140fe171..0000000000
--- a/contrib/gitian-downloader/jonasschnelli.pgp
+++ /dev/null
Binary files differ
diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py
new file mode 100755
index 0000000000..9f2cc84601
--- /dev/null
+++ b/qa/rpc-tests/bipdersig.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python2
+# Copyright (c) 2014 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#
+# Test the BIP66 changeover logic
+#
+
+from test_framework import BitcoinTestFramework
+from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
+from util import *
+import os
+import shutil
+
+class BIP66Test(BitcoinTestFramework):
+
+ def setup_network(self):
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, []))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=2"]))
+ self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=3"]))
+ connect_nodes(self.nodes[1], 0)
+ connect_nodes(self.nodes[2], 0)
+ self.is_network_split = False
+ self.sync_all()
+
+ def run_test(self):
+ cnt = self.nodes[0].getblockcount()
+
+ # Mine some old-version blocks
+ self.nodes[1].setgenerate(True, 100)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 100):
+ raise AssertionError("Failed to mine 100 version=2 blocks")
+
+ # Mine 750 new-version blocks
+ for i in xrange(15):
+ self.nodes[2].setgenerate(True, 50)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 850):
+ raise AssertionError("Failed to mine 750 version=3 blocks")
+
+ # TODO: check that new DERSIG rules are not enforced
+
+ # Mine 1 new-version block
+ self.nodes[2].setgenerate(True, 1)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 851):
+ raise AssertionFailure("Failed to mine a version=3 blocks")
+
+ # TODO: check that new DERSIG rules are enforced
+
+ # Mine 198 new-version blocks
+ for i in xrange(2):
+ self.nodes[2].setgenerate(True, 99)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1049):
+ raise AssertionError("Failed to mine 198 version=3 blocks")
+
+ # Mine 1 old-version block
+ self.nodes[1].setgenerate(True, 1)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1050):
+ raise AssertionError("Failed to mine a version=2 block after 949 version=3 blocks")
+
+ # Mine 1 new-version blocks
+ self.nodes[2].setgenerate(True, 1)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1051):
+ raise AssertionError("Failed to mine a version=3 block")
+
+ # Mine 1 old-version blocks
+ try:
+ self.nodes[1].setgenerate(True, 1)
+ raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks")
+ except JSONRPCException:
+ pass
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1051):
+ raise AssertionError("Accepted a version=2 block after 950 version=3 blocks")
+
+ # Mine 1 new-version blocks
+ self.nodes[2].setgenerate(True, 1)
+ self.sync_all()
+ if (self.nodes[0].getblockcount() != cnt + 1052):
+ raise AssertionError("Failed to mine a version=3 block")
+
+if __name__ == '__main__':
+ BIP66Test().main()
diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py
index 22fe2ce044..f65162002d 100755
--- a/qa/rpc-tests/getblocktemplate_proposals.py
+++ b/qa/rpc-tests/getblocktemplate_proposals.py
@@ -95,6 +95,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0]
+ node.setgenerate(True, 1) # Mine a block to leave initial block download
tmpl = node.getblocktemplate()
if 'coinbasetxn' not in tmpl:
rawcoinbase = encodeUNum(tmpl['height'])
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 01ace1e2b2..c1622cf5d3 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -436,7 +436,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
BOOST_FOREACH(const CTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
- if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(mergedTx, i)))
+ if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
fComplete = false;
}
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index d32d96c56b..1fd3b01681 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -156,11 +156,11 @@ public:
vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com"));
vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org"));
- base58Prefixes[PUBKEY_ADDRESS] = boost::assign::list_of(0);
- base58Prefixes[SCRIPT_ADDRESS] = boost::assign::list_of(5);
- base58Prefixes[SECRET_KEY] = boost::assign::list_of(128);
- base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E);
- base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4);
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
+ base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container<std::vector<unsigned char> >();
+ base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container<std::vector<unsigned char> >();
convertSeed6(vFixedSeeds, pnSeed6_main, ARRAYLEN(pnSeed6_main));
@@ -214,11 +214,11 @@ public:
vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
- base58Prefixes[PUBKEY_ADDRESS] = boost::assign::list_of(111);
- base58Prefixes[SCRIPT_ADDRESS] = boost::assign::list_of(196);
- base58Prefixes[SECRET_KEY] = boost::assign::list_of(239);
- base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF);
- base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94);
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
+ base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >();
+ base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >();
convertSeed6(vFixedSeeds, pnSeed6_test, ARRAYLEN(pnSeed6_test));
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 7ca825c16f..6f6b97e3a7 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -161,7 +161,12 @@ public:
{
}
- friend class CCheckQueueControl<T>;
+ bool IsIdle()
+ {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ return (nTotal == nIdle && nTodo == 0 && fAllOk == true);
+ }
+
};
/**
@@ -180,9 +185,8 @@ public:
{
// passed queue is supposed to be unused, or NULL
if (pqueue != NULL) {
- assert(pqueue->nTotal == pqueue->nIdle);
- assert(pqueue->nTodo == 0);
- assert(pqueue->fAllOk == true);
+ bool isIdle = pqueue->IsIdle();
+ assert(isIdle);
}
}
diff --git a/src/crypter.cpp b/src/crypter.cpp
index 00f7f7f1bd..75d84dbf13 100644
--- a/src/crypter.cpp
+++ b/src/crypter.cpp
@@ -102,7 +102,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
}
-bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
+static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
@@ -112,7 +112,7 @@ bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vch
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
}
-bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
+static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
@@ -122,6 +122,19 @@ bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
}
+static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
+{
+ CKeyingMaterial vchSecret;
+ if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
+ return false;
+
+ if (vchSecret.size() != 32)
+ return false;
+
+ key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
+ return key.VerifyPubKey(vchPubKey);
+}
+
bool CCryptoKeyStore::SetCrypted()
{
LOCK(cs_KeyStore);
@@ -161,20 +174,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- CKeyingMaterial vchSecret;
- if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
- {
- keyFail = true;
- break;
- }
- if (vchSecret.size() != 32)
- {
- keyFail = true;
- break;
- }
CKey key;
- key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
- if (key.GetPubKey() != vchPubKey)
+ if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
{
keyFail = true;
break;
@@ -243,13 +244,7 @@ bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- CKeyingMaterial vchSecret;
- if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
- return false;
- if (vchSecret.size() != 32)
- return false;
- keyOut.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
- return true;
+ return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
}
}
return false;
diff --git a/src/crypter.h b/src/crypter.h
index 7b4c2f2613..cbaf1562f0 100644
--- a/src/crypter.h
+++ b/src/crypter.h
@@ -107,9 +107,6 @@ public:
}
};
-bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
-bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
-
/** Keystore which keeps the private keys encrypted.
* It derives from the basic key store, which is used if no encryption is active.
*/
diff --git a/src/init.cpp b/src/init.cpp
index c2af23139c..c8f32d8bfd 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -234,6 +234,26 @@ bool static Bind(const CService &addr, unsigned int flags) {
return true;
}
+void OnRPCStopped()
+{
+ cvBlockChange.notify_all();
+ LogPrint("rpc", "RPC stopped.\n");
+}
+
+void OnRPCPreCommand(const CRPCCommand& cmd)
+{
+#ifdef ENABLE_WALLET
+ if (cmd.reqWallet && !pwalletMain)
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
+#endif
+
+ // Observe safe mode
+ string strWarning = GetWarnings("rpc");
+ if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
+ !cmd.okSafeMode)
+ throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
+}
+
std::string HelpMessage(HelpMessageMode mode)
{
// When adding new options to the categories, please keep and ensure alphabetical ordering.
@@ -802,6 +822,8 @@ bool AppInit2(boost::thread_group& threadGroup)
if (fServer)
{
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
+ RPCServer::OnStopped(&OnRPCStopped);
+ RPCServer::OnPreCommand(&OnRPCPreCommand);
StartRPCThreads();
}
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 22cd08f30c..7531737e04 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -7,8 +7,6 @@
#include "crypter.h"
#include "key.h"
-#include "script/script.h"
-#include "script/standard.h"
#include "util.h"
#include <boost/foreach.hpp>
diff --git a/src/keystore.h b/src/keystore.h
index 6655264d72..4a4b6d20af 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -8,14 +8,13 @@
#include "key.h"
#include "pubkey.h"
+#include "script/script.h"
+#include "script/standard.h"
#include "sync.h"
#include <boost/signals2/signal.hpp>
#include <boost/variant.hpp>
-class CScript;
-class CScriptID;
-
/** A virtual base class for key stores */
class CKeyStore
{
diff --git a/src/main.cpp b/src/main.cpp
index f43d8c58b6..43e5a2d024 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -904,7 +904,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fRejectInsaneFee)
+ bool* pfMissingInputs, bool fRejectAbsurdFee)
{
AssertLockHeld(cs_main);
if (pfMissingInputs)
@@ -1063,8 +1063,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
dFreeCount += nSize;
}
- if (fRejectInsaneFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
- return error("AcceptToMemoryPool: insane fees %s, %d > %d",
+ if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
+ return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",
hash.ToString(),
nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
@@ -1422,7 +1422,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
- if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore), &error)) {
+ if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) {
return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
}
return true;
@@ -1764,6 +1764,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
+ // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded:
+ if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, Params().EnforceBlockUpgradeMajority())) {
+ flags |= SCRIPT_VERIFY_DERSIG;
+ }
+
CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
@@ -2601,6 +2606,13 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
REJECT_OBSOLETE, "bad-version");
}
+ // Reject block.nVersion=2 blocks when 95% (75% on testnet) of the network has upgraded:
+ if (block.nVersion < 3 && IsSuperMajority(3, pindexPrev, Params().RejectBlockOutdatedMajority()))
+ {
+ return state.Invalid(error("%s : rejected nVersion=2 block", __func__),
+ REJECT_OBSOLETE, "bad-version");
+ }
+
return true;
}
@@ -3438,7 +3450,7 @@ void static ProcessGetData(CNode* pfrom)
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
{
RandAddSeedPerfmon();
- LogPrint("net", "received: %s (%u bytes) peer=%d\n", strCommand, vRecv.size(), pfrom->id);
+ LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
@@ -4273,7 +4285,7 @@ bool ProcessMessages(CNode* pfrom)
// Scan for message start
if (memcmp(msg.hdr.pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0) {
- LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", msg.hdr.GetCommand(), pfrom->id);
+ LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id);
fOk = false;
break;
}
@@ -4282,7 +4294,7 @@ bool ProcessMessages(CNode* pfrom)
CMessageHeader& hdr = msg.hdr;
if (!hdr.IsValid())
{
- LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", hdr.GetCommand(), pfrom->id);
+ LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id);
continue;
}
string strCommand = hdr.GetCommand();
@@ -4298,7 +4310,7 @@ bool ProcessMessages(CNode* pfrom)
if (nChecksum != hdr.nChecksum)
{
LogPrintf("ProcessMessages(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
- strCommand, nMessageSize, nChecksum, hdr.nChecksum);
+ SanitizeString(strCommand), nMessageSize, nChecksum, hdr.nChecksum);
continue;
}
@@ -4315,12 +4327,12 @@ bool ProcessMessages(CNode* pfrom)
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from under-length message on vRecv
- LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand, nMessageSize, e.what());
+ LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", SanitizeString(strCommand), nMessageSize, e.what());
}
else if (strstr(e.what(), "size too large"))
{
// Allow exceptions from over-long size
- LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught\n", strCommand, nMessageSize, e.what());
+ LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught\n", SanitizeString(strCommand), nMessageSize, e.what());
}
else
{
@@ -4337,7 +4349,7 @@ bool ProcessMessages(CNode* pfrom)
}
if (!fRet)
- LogPrintf("ProcessMessage(%s, %u bytes) FAILED peer=%d\n", strCommand, nMessageSize, pfrom->id);
+ LogPrintf("ProcessMessage(%s, %u bytes) FAILED peer=%d\n", SanitizeString(strCommand), nMessageSize, pfrom->id);
break;
}
@@ -4534,12 +4546,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id);
pto->fDisconnect = true;
}
- // In case there is a block that has been in flight from this peer for (1 + 0.5 * N) times the block interval
+ // In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval
// (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
// being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
// to unreasonably increase our timeout.
- if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * Params().TargetSpacing() * (2 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) {
+ if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * Params().TargetSpacing() * (4 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) {
LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id);
pto->fDisconnect = true;
}
diff --git a/src/main.h b/src/main.h
index a7360d2f70..936cd43e99 100644
--- a/src/main.h
+++ b/src/main.h
@@ -205,7 +205,7 @@ void FlushStateToDisk();
/** (try to) add transaction to memory pool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
- bool* pfMissingInputs, bool fRejectInsaneFee=false);
+ bool* pfMissingInputs, bool fRejectAbsurdFee=false);
struct CNodeStateStats {
diff --git a/src/net.cpp b/src/net.cpp
index e4ab9d706d..3c3666615e 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1971,7 +1971,7 @@ void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSen
ENTER_CRITICAL_SECTION(cs_vSend);
assert(ssSend.size() == 0);
ssSend << CMessageHeader(pszCommand, 0);
- LogPrint("net", "sending: %s ", pszCommand);
+ LogPrint("net", "sending: %s ", SanitizeString(pszCommand));
}
void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
diff --git a/src/primitives/block.h b/src/primitives/block.h
index d77ab162e0..c7ed6f723a 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -24,7 +24,7 @@ class CBlockHeader
{
public:
// header
- static const int32_t CURRENT_VERSION=2;
+ static const int32_t CURRENT_VERSION=3;
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index 4c00aca985..d31a1e018b 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -278,7 +278,6 @@ void BitcoinAmountField::setValue(const CAmount& value)
void BitcoinAmountField::setReadOnly(bool fReadOnly)
{
amount->setReadOnly(fReadOnly);
- unit->setEnabled(!fReadOnly);
}
void BitcoinAmountField::unitChanged(int idx)
diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui
index 37008f047e..dc7df9d6c8 100644
--- a/src/qt/forms/helpmessagedialog.ui
+++ b/src/qt/forms/helpmessagedialog.ui
@@ -14,6 +14,69 @@
<string notr="true">Bitcoin Core - Command-line options</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>12</number>
+ </property>
+ <property name="topMargin">
+ <number>12</number>
+ </property>
+ <property name="rightMargin">
+ <number>12</number>
+ </property>
+ <property name="bottomMargin">
+ <number>12</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayoutLogo" stretch="0,0">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>4</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="aboutLogo">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Ignored">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="../bitcoin.qrc">:/icons/bitcoin</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
@@ -25,6 +88,9 @@
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
@@ -57,6 +123,22 @@
</widget>
</item>
<item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>4</width>
+ <height>4</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
<widget class="QDialogButtonBox" name="okButton">
<property name="orientation">
<enum>Qt::Horizontal</enum>
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 9e8743d805..5aef2d7539 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -526,8 +526,8 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
msgParams.second = CClientUIInterface::MSG_ERROR;
break;
- case WalletModel::InsaneFee:
- msgParams.first = tr("A fee higher than %1 is considered an insanely high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000));
+ case WalletModel::AbsurdFee:
+ msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000));
break;
case WalletModel::PaymentRequestExpired:
msgParams.first = tr("Payment request expired!");
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 4ef42b927e..63dd6efb52 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -137,6 +137,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
ui->helpMessage->moveCursor(QTextCursor::Start);
ui->scrollArea->setVisible(false);
+ ui->aboutLogo->setVisible(false);
}
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 4a7abf999c..79f5191fc0 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -279,9 +279,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return TransactionCreationFailed;
}
- // reject insane fee > 0.1 bitcoin
+ // reject absurdly high fee > 0.1 bitcoin
if (nFeeRequired > 10000000)
- return InsaneFee;
+ return AbsurdFee;
}
return SendCoinsReturn(OK);
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 9916d11f93..4a9a12beaa 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -111,7 +111,7 @@ public:
DuplicateAddress,
TransactionCreationFailed, // Error returned when wallet is still locked
TransactionCommitFailed,
- InsaneFee,
+ AbsurdFee,
PaymentRequestExpired
};
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index cfc559d198..293d6d5619 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -105,6 +105,7 @@ Value getblockcount(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockcount", "")
);
+ LOCK(cs_main);
return chainActive.Height();
}
@@ -121,6 +122,7 @@ Value getbestblockhash(const Array& params, bool fHelp)
+ HelpExampleRpc("getbestblockhash", "")
);
+ LOCK(cs_main);
return chainActive.Tip()->GetBlockHash().GetHex();
}
@@ -137,6 +139,7 @@ Value getdifficulty(const Array& params, bool fHelp)
+ HelpExampleRpc("getdifficulty", "")
);
+ LOCK(cs_main);
return GetDifficulty();
}
@@ -173,6 +176,8 @@ Value getrawmempool(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawmempool", "true")
);
+ LOCK(cs_main);
+
bool fVerbose = false;
if (params.size() > 0)
fVerbose = params[0].get_bool();
@@ -233,6 +238,8 @@ Value getblockhash(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockhash", "1000")
);
+ LOCK(cs_main);
+
int nHeight = params[0].get_int();
if (nHeight < 0 || nHeight > chainActive.Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
@@ -277,6 +284,8 @@ Value getblock(const Array& params, bool fHelp)
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
);
+ LOCK(cs_main);
+
std::string strHash = params[0].get_str();
uint256 hash(uint256S(strHash));
@@ -326,6 +335,8 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("gettxoutsetinfo", "")
);
+ LOCK(cs_main);
+
Object ret;
CCoinsStats stats;
@@ -380,6 +391,8 @@ Value gettxout(const Array& params, bool fHelp)
+ HelpExampleRpc("gettxout", "\"txid\", 1")
);
+ LOCK(cs_main);
+
Object ret;
std::string strHash = params[0].get_str();
@@ -436,6 +449,8 @@ Value verifychain(const Array& params, bool fHelp)
+ HelpExampleRpc("verifychain", "")
);
+ LOCK(cs_main);
+
int nCheckLevel = GetArg("-checklevel", 3);
int nCheckDepth = GetArg("-checkblocks", 288);
if (params.size() > 0)
@@ -467,6 +482,8 @@ Value getblockchaininfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockchaininfo", "")
);
+ LOCK(cs_main);
+
Object obj;
obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("blocks", (int)chainActive.Height()));
@@ -526,6 +543,8 @@ Value getchaintips(const Array& params, bool fHelp)
+ HelpExampleRpc("getchaintips", "")
);
+ LOCK(cs_main);
+
/* Build up a list of chain tips. We start with the list of all
known blocks, and successively remove blocks that appear as pprev
of another block. */
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 8666779cc1..b9c92a06c5 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -91,6 +91,8 @@ Value importprivkey(const Array& params, bool fHelp)
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
string strSecret = params[0].get_str();
@@ -158,6 +160,8 @@ Value importaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CScript script;
CBitcoinAddress address(params[0].get_str());
@@ -223,6 +227,8 @@ Value importwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("importwallet", "\"test\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
ifstream file;
@@ -322,6 +328,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
string strAddress = params[0].get_str();
@@ -351,6 +359,8 @@ Value dumpwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("dumpwallet", "\"test\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
ofstream file;
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index f1c4016575..e3ae5cff42 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -88,6 +88,7 @@ Value getnetworkhashps(const Array& params, bool fHelp)
+ HelpExampleRpc("getnetworkhashps", "")
);
+ LOCK(cs_main);
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
}
@@ -107,6 +108,7 @@ Value getgenerate(const Array& params, bool fHelp)
+ HelpExampleRpc("getgenerate", "")
);
+ LOCK(cs_main);
return GetBoolArg("-gen", false);
}
@@ -200,7 +202,6 @@ Value setgenerate(const Array& params, bool fHelp)
return Value::null;
}
-
#endif
@@ -228,6 +229,9 @@ Value getmininginfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getmininginfo", "")
);
+
+ LOCK(cs_main);
+
Object obj;
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
@@ -268,8 +272,9 @@ Value prioritisetransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
);
- uint256 hash = ParseHashStr(params[0].get_str(), "txid");
+ LOCK(cs_main);
+ uint256 hash = ParseHashStr(params[0].get_str(), "txid");
CAmount nAmount = params[2].get_int64();
mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
@@ -358,6 +363,8 @@ Value getblocktemplate(const Array& params, bool fHelp)
+ HelpExampleRpc("getblocktemplate", "")
);
+ LOCK(cs_main);
+
std::string strMode = "template";
Value lpval = Value::null;
if (params.size() > 0)
@@ -439,10 +446,6 @@ Value getblocktemplate(const Array& params, bool fHelp)
}
// Release the wallet and main lock while waiting
-#ifdef ENABLE_WALLET
- if(pwalletMain)
- LEAVE_CRITICAL_SECTION(pwalletMain->cs_wallet);
-#endif
LEAVE_CRITICAL_SECTION(cs_main);
{
checktxtime = boost::get_system_time() + boost::posix_time::minutes(1);
@@ -460,10 +463,6 @@ Value getblocktemplate(const Array& params, bool fHelp)
}
}
ENTER_CRITICAL_SECTION(cs_main);
-#ifdef ENABLE_WALLET
- if(pwalletMain)
- ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet);
-#endif
if (!IsRPCRunning())
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index 3d647a0d2d..8d260b1cc9 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -69,6 +69,12 @@ Value getinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getinfo", "")
);
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+#else
+ LOCK(cs_main);
+#endif
+
proxyType proxy;
GetProxy(NET_IPV4, proxy);
@@ -172,6 +178,12 @@ Value validateaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
);
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+#else
+ LOCK(cs_main);
+#endif
+
CBitcoinAddress address(params[0].get_str());
bool isValid = address.IsValid();
@@ -329,6 +341,8 @@ Value verifymessage(const Array& params, bool fHelp)
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
);
+ LOCK(cs_main);
+
string strAddress = params[0].get_str();
string strSign = params[1].get_str();
string strMessage = params[2].get_str();
@@ -372,6 +386,8 @@ Value setmocktime(const Array& params, bool fHelp)
if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only");
+ LOCK(cs_main);
+
RPCTypeCheck(params, boost::assign::list_of(int_type));
SetMockTime(params[0].get_int64());
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index f0fadb5987..6306fd4406 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -34,7 +34,8 @@ Value getconnectioncount(const Array& params, bool fHelp)
+ HelpExampleRpc("getconnectioncount", "")
);
- LOCK(cs_vNodes);
+ LOCK2(cs_main, cs_vNodes);
+
return (int)vNodes.size();
}
@@ -52,7 +53,8 @@ Value ping(const Array& params, bool fHelp)
);
// Request that each node send a ping during next message processing pass
- LOCK(cs_vNodes);
+ LOCK2(cs_main, cs_vNodes);
+
BOOST_FOREACH(CNode* pNode, vNodes) {
pNode->fPingQueued = true;
}
@@ -113,6 +115,8 @@ Value getpeerinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getpeerinfo", "")
);
+ LOCK(cs_main);
+
vector<CNodeStats> vstats;
CopyNodeStats(vstats);
@@ -411,6 +415,8 @@ Value getnetworkinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getnetworkinfo", "")
);
+ LOCK(cs_main);
+
Object obj;
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion",
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 2b108bf588..4a079f5c81 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -169,6 +169,8 @@ Value getrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
);
+ LOCK(cs_main);
+
uint256 hash = ParseHashV(params[0], "parameter 1");
bool fVerbose = false;
@@ -256,6 +258,7 @@ Value listunspent(const Array& params, bool fHelp)
Array results;
vector<COutput> vecOutputs;
assert(pwalletMain != NULL);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(vecOutputs, false);
BOOST_FOREACH(const COutput& out, vecOutputs) {
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
@@ -334,6 +337,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type));
Array inputs = params[0].get_array();
@@ -428,6 +432,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type));
CTransaction tx;
@@ -466,6 +471,7 @@ Value decodescript(const Array& params, bool fHelp)
+ HelpExampleRpc("decodescript", "\"hexstring\"")
);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type));
Object r;
@@ -532,6 +538,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
);
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+#else
+ LOCK(cs_main);
+#endif
RPCTypeCheck(params, boost::assign::list_of(str_type)(array_type)(array_type)(str_type), true);
vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
@@ -591,7 +602,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
}
#ifdef ENABLE_WALLET
- else
+ else if (pwalletMain)
EnsureWalletIsUnlocked();
#endif
@@ -688,7 +699,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
- if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(mergedTx, i)))
+ if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
fComplete = false;
}
@@ -722,6 +733,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type));
// parse hex string from parameter
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index e4f23d56d2..20e9252d7e 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -7,9 +7,11 @@
#include "base58.h"
#include "init.h"
-#include "main.h"
+#include "random.h"
+#include "sync.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#endif
@@ -23,11 +25,13 @@
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
#include "json/json_spirit_writer_template.h"
using namespace boost::asio;
using namespace json_spirit;
+using namespace RPCServer;
using namespace std;
static std::string strRPCUserColonPass;
@@ -46,6 +50,34 @@ static boost::asio::io_service::work *rpc_dummy_work = NULL;
static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
static std::vector< boost::shared_ptr<ip::tcp::acceptor> > rpc_acceptors;
+static struct CRPCSignals
+{
+ boost::signals2::signal<void ()> Started;
+ boost::signals2::signal<void ()> Stopped;
+ boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
+ boost::signals2::signal<void (const CRPCCommand&)> PostCommand;
+} g_rpcSignals;
+
+void RPCServer::OnStarted(boost::function<void ()> slot)
+{
+ g_rpcSignals.Started.connect(slot);
+}
+
+void RPCServer::OnStopped(boost::function<void ()> slot)
+{
+ g_rpcSignals.Stopped.connect(slot);
+}
+
+void RPCServer::OnPreCommand(boost::function<void (const CRPCCommand&)> slot)
+{
+ g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
+}
+
+void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
+{
+ g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
+}
+
void RPCTypeCheck(const Array& params,
const list<Value_type>& typesExpected,
bool fAllowNull)
@@ -239,112 +271,110 @@ Value stop(const Array& params, bool fHelp)
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafeMode threadSafe reqWallet
- // --------------------- ------------------------ ----------------------- ---------- ---------- ---------
+{ // category name actor (function) okSafeMode reqWallet
+ // --------------------- ------------------------ ----------------------- ---------- ---------
/* Overall control/query calls */
- { "control", "getinfo", &getinfo, true, false, false }, /* uses wallet if enabled */
- { "control", "help", &help, true, true, false },
- { "control", "stop", &stop, true, true, false },
+ { "control", "getinfo", &getinfo, true, false }, /* uses wallet if enabled */
+ { "control", "help", &help, true, false },
+ { "control", "stop", &stop, true, false },
/* P2P networking */
- { "network", "getnetworkinfo", &getnetworkinfo, true, false, false },
- { "network", "addnode", &addnode, true, true, false },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true, true, false },
- { "network", "getconnectioncount", &getconnectioncount, true, false, false },
- { "network", "getnettotals", &getnettotals, true, true, false },
- { "network", "getpeerinfo", &getpeerinfo, true, false, false },
- { "network", "ping", &ping, true, false, false },
+ { "network", "getnetworkinfo", &getnetworkinfo, true, false },
+ { "network", "addnode", &addnode, true, false },
+ { "network", "getaddednodeinfo", &getaddednodeinfo, true, false },
+ { "network", "getconnectioncount", &getconnectioncount, true, false },
+ { "network", "getnettotals", &getnettotals, true, false },
+ { "network", "getpeerinfo", &getpeerinfo, true, false },
+ { "network", "ping", &ping, true, false },
/* Block chain and UTXO */
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true, false, false },
- { "blockchain", "getbestblockhash", &getbestblockhash, true, false, false },
- { "blockchain", "getblockcount", &getblockcount, true, false, false },
- { "blockchain", "getblock", &getblock, true, false, false },
- { "blockchain", "getblockhash", &getblockhash, true, false, false },
- { "blockchain", "getchaintips", &getchaintips, true, false, false },
- { "blockchain", "getdifficulty", &getdifficulty, true, false, false },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false },
- { "blockchain", "getrawmempool", &getrawmempool, true, false, false },
- { "blockchain", "gettxout", &gettxout, true, false, false },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
- { "blockchain", "verifychain", &verifychain, true, false, false },
- { "blockchain", "invalidateblock", &invalidateblock, true, true, false },
- { "blockchain", "reconsiderblock", &reconsiderblock, true, true, false },
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, true, false },
+ { "blockchain", "getbestblockhash", &getbestblockhash, true, false },
+ { "blockchain", "getblockcount", &getblockcount, true, false },
+ { "blockchain", "getblock", &getblock, true, false },
+ { "blockchain", "getblockhash", &getblockhash, true, false },
+ { "blockchain", "getchaintips", &getchaintips, true, false },
+ { "blockchain", "getdifficulty", &getdifficulty, true, false },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, true, false },
+ { "blockchain", "getrawmempool", &getrawmempool, true, false },
+ { "blockchain", "gettxout", &gettxout, true, false },
+ { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false },
+ { "blockchain", "verifychain", &verifychain, true, false },
/* Mining */
- { "mining", "getblocktemplate", &getblocktemplate, true, false, false },
- { "mining", "getmininginfo", &getmininginfo, true, false, false },
- { "mining", "getnetworkhashps", &getnetworkhashps, true, false, false },
- { "mining", "prioritisetransaction", &prioritisetransaction, true, false, false },
- { "mining", "submitblock", &submitblock, true, true, false },
+ { "mining", "getblocktemplate", &getblocktemplate, true, false },
+ { "mining", "getmininginfo", &getmininginfo, true, false },
+ { "mining", "getnetworkhashps", &getnetworkhashps, true, false },
+ { "mining", "prioritisetransaction", &prioritisetransaction, true, false },
+ { "mining", "submitblock", &submitblock, true, false },
#ifdef ENABLE_WALLET
/* Coin generation */
- { "generating", "getgenerate", &getgenerate, true, false, false },
- { "generating", "setgenerate", &setgenerate, true, true, false },
+ { "generating", "getgenerate", &getgenerate, true, false },
+ { "generating", "setgenerate", &setgenerate, true, false },
#endif
/* Raw transactions */
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true, false, false },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false, false },
- { "rawtransactions", "decodescript", &decodescript, true, false, false },
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true, false, false },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false, false },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false, false, false }, /* uses wallet if enabled */
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, true, false },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false },
+ { "rawtransactions", "decodescript", &decodescript, true, false },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, true, false },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false },
+ { "rawtransactions", "signrawtransaction", &signrawtransaction, false, false }, /* uses wallet if enabled */
/* Utility functions */
- { "util", "createmultisig", &createmultisig, true, true , false },
- { "util", "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */
- { "util", "verifymessage", &verifymessage, true, false, false },
- { "util", "estimatefee", &estimatefee, true, true, false },
- { "util", "estimatepriority", &estimatepriority, true, true, false },
+ { "util", "createmultisig", &createmultisig, true, false },
+ { "util", "validateaddress", &validateaddress, true, false }, /* uses wallet if enabled */
+ { "util", "verifymessage", &verifymessage, true, false },
+ { "util", "estimatefee", &estimatefee, true, false },
+ { "util", "estimatepriority", &estimatepriority, true, false },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true, true, false },
- { "hidden", "reconsiderblock", &reconsiderblock, true, true, false },
- { "hidden", "setmocktime", &setmocktime, true, false, false },
+ { "hidden", "invalidateblock", &invalidateblock, true, false },
+ { "hidden", "reconsiderblock", &reconsiderblock, true, false },
+ { "hidden", "setmocktime", &setmocktime, true, false },
#ifdef ENABLE_WALLET
/* Wallet */
- { "wallet", "addmultisigaddress", &addmultisigaddress, true, false, true },
- { "wallet", "backupwallet", &backupwallet, true, false, true },
- { "wallet", "dumpprivkey", &dumpprivkey, true, false, true },
- { "wallet", "dumpwallet", &dumpwallet, true, false, true },
- { "wallet", "encryptwallet", &encryptwallet, true, false, true },
- { "wallet", "getaccountaddress", &getaccountaddress, true, false, true },
- { "wallet", "getaccount", &getaccount, true, false, true },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, false, true },
- { "wallet", "getbalance", &getbalance, false, false, true },
- { "wallet", "getnewaddress", &getnewaddress, true, false, true },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, false, true },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, false, true },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, false, true },
- { "wallet", "gettransaction", &gettransaction, false, false, true },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, false, true },
- { "wallet", "getwalletinfo", &getwalletinfo, false, false, true },
- { "wallet", "importprivkey", &importprivkey, true, false, true },
- { "wallet", "importwallet", &importwallet, true, false, true },
- { "wallet", "importaddress", &importaddress, true, false, true },
- { "wallet", "keypoolrefill", &keypoolrefill, true, false, true },
- { "wallet", "listaccounts", &listaccounts, false, false, true },
- { "wallet", "listaddressgroupings", &listaddressgroupings, false, false, true },
- { "wallet", "listlockunspent", &listlockunspent, false, false, true },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, false, true },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, false, true },
- { "wallet", "listsinceblock", &listsinceblock, false, false, true },
- { "wallet", "listtransactions", &listtransactions, false, false, true },
- { "wallet", "listunspent", &listunspent, false, false, true },
- { "wallet", "lockunspent", &lockunspent, true, false, true },
- { "wallet", "move", &movecmd, false, false, true },
- { "wallet", "sendfrom", &sendfrom, false, false, true },
- { "wallet", "sendmany", &sendmany, false, false, true },
- { "wallet", "sendtoaddress", &sendtoaddress, false, false, true },
- { "wallet", "setaccount", &setaccount, true, false, true },
- { "wallet", "settxfee", &settxfee, true, false, true },
- { "wallet", "signmessage", &signmessage, true, false, true },
- { "wallet", "walletlock", &walletlock, true, false, true },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, false, true },
- { "wallet", "walletpassphrase", &walletpassphrase, true, false, true },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, true, true },
+ { "wallet", "backupwallet", &backupwallet, true, true },
+ { "wallet", "dumpprivkey", &dumpprivkey, true, true },
+ { "wallet", "dumpwallet", &dumpwallet, true, true },
+ { "wallet", "encryptwallet", &encryptwallet, true, true },
+ { "wallet", "getaccountaddress", &getaccountaddress, true, true },
+ { "wallet", "getaccount", &getaccount, true, true },
+ { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, true },
+ { "wallet", "getbalance", &getbalance, false, true },
+ { "wallet", "getnewaddress", &getnewaddress, true, true },
+ { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, true },
+ { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, true },
+ { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, true },
+ { "wallet", "gettransaction", &gettransaction, false, true },
+ { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, true },
+ { "wallet", "getwalletinfo", &getwalletinfo, false, true },
+ { "wallet", "importprivkey", &importprivkey, true, true },
+ { "wallet", "importwallet", &importwallet, true, true },
+ { "wallet", "importaddress", &importaddress, true, true },
+ { "wallet", "keypoolrefill", &keypoolrefill, true, true },
+ { "wallet", "listaccounts", &listaccounts, false, true },
+ { "wallet", "listaddressgroupings", &listaddressgroupings, false, true },
+ { "wallet", "listlockunspent", &listlockunspent, false, true },
+ { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, true },
+ { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, true },
+ { "wallet", "listsinceblock", &listsinceblock, false, true },
+ { "wallet", "listtransactions", &listtransactions, false, true },
+ { "wallet", "listunspent", &listunspent, false, true },
+ { "wallet", "lockunspent", &lockunspent, true, true },
+ { "wallet", "move", &movecmd, false, true },
+ { "wallet", "sendfrom", &sendfrom, false, true },
+ { "wallet", "sendmany", &sendmany, false, true },
+ { "wallet", "sendtoaddress", &sendtoaddress, false, true },
+ { "wallet", "setaccount", &setaccount, true, true },
+ { "wallet", "settxfee", &settxfee, true, true },
+ { "wallet", "signmessage", &signmessage, true, true },
+ { "wallet", "walletlock", &walletlock, true, true },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, true },
+ { "wallet", "walletpassphrase", &walletpassphrase, true, true },
#endif // ENABLE_WALLET
};
@@ -693,6 +723,7 @@ void StartRPCThreads()
for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
rpc_worker_group->create_thread(boost::bind(&boost::asio::io_service::run, rpc_io_service));
fRPCRunning = true;
+ g_rpcSignals.Started();
}
void StartDummyRPCThread()
@@ -735,7 +766,7 @@ void StopRPCThreads()
deadlineTimers.clear();
rpc_io_service->stop();
- cvBlockChange.notify_all();
+ g_rpcSignals.Stopped();
if (rpc_worker_group != NULL)
rpc_worker_group->join_all();
delete rpc_dummy_work; rpc_dummy_work = NULL;
@@ -818,7 +849,7 @@ void JSONRequest::parse(const Value& valRequest)
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
strMethod = valMethod.get_str();
if (strMethod != "getblocktemplate")
- LogPrint("rpc", "ThreadRPCServer method=%s\n", strMethod);
+ LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
// Parse params
Value valParams = find_value(request, "params");
@@ -978,45 +1009,20 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
const CRPCCommand *pcmd = tableRPC[strMethod];
if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
-#ifdef ENABLE_WALLET
- if (pcmd->reqWallet && !pwalletMain)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
-#endif
- // Observe safe mode
- string strWarning = GetWarnings("rpc");
- if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
- !pcmd->okSafeMode)
- throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
+ g_rpcSignals.PreCommand(*pcmd);
try
{
// Execute
- Value result;
- {
- if (pcmd->threadSafe)
- result = pcmd->actor(params, false);
-#ifdef ENABLE_WALLET
- else if (!pwalletMain) {
- LOCK(cs_main);
- result = pcmd->actor(params, false);
- } else {
- LOCK2(cs_main, pwalletMain->cs_wallet);
- result = pcmd->actor(params, false);
- }
-#else // ENABLE_WALLET
- else {
- LOCK(cs_main);
- result = pcmd->actor(params, false);
- }
-#endif // !ENABLE_WALLET
- }
- return result;
+ return pcmd->actor(params, false);
}
catch (const std::exception& e)
{
throw JSONRPCError(RPC_MISC_ERROR, e.what());
}
+
+ g_rpcSignals.PostCommand(*pcmd);
}
std::string HelpExampleCli(string methodname, string args){
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 1b94b758f2..f63438ecb8 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -19,6 +19,16 @@
#include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.h"
+class CRPCCommand;
+
+namespace RPCServer
+{
+ void OnStarted(boost::function<void ()> slot);
+ void OnStopped(boost::function<void ()> slot);
+ void OnPreCommand(boost::function<void (const CRPCCommand&)> slot);
+ void OnPostCommand(boost::function<void (const CRPCCommand&)> slot);
+}
+
class CBlockIndex;
class CNetAddr;
@@ -88,7 +98,6 @@ public:
std::string name;
rpcfn_type actor;
bool okSafeMode;
- bool threadSafe;
bool reqWallet;
};
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 28371771a9..1afc3c910e 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -90,6 +90,8 @@ Value getnewaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getnewaddress", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Parse the account first so we don't generate a key if there's an error
string strAccount;
if (params.size() > 0)
@@ -164,13 +166,14 @@ Value getaccountaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getaccountaddress", "\"myaccount\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Parse the account first so we don't generate a key if there's an error
string strAccount = AccountFromValue(params[0]);
Value ret;
ret = GetAccountAddress(strAccount).ToString();
-
return ret;
}
@@ -189,6 +192,8 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawchangeaddress", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (!pwalletMain->IsLocked())
pwalletMain->TopUpKeyPool();
@@ -219,11 +224,12 @@ Value setaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
-
string strAccount;
if (params.size() > 1)
strAccount = AccountFromValue(params[1]);
@@ -262,6 +268,8 @@ Value getaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -292,6 +300,8 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount = AccountFromValue(params[0]);
// Find all addresses that have the given account
@@ -363,6 +373,8 @@ Value sendtoaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -409,6 +421,8 @@ Value listaddressgroupings(const Array& params, bool fHelp)
+ HelpExampleRpc("listaddressgroupings", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
Array jsonGroupings;
map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
@@ -454,6 +468,8 @@ Value signmessage(const Array& params, bool fHelp)
+ HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
string strAddress = params[0].get_str();
@@ -504,6 +520,8 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Bitcoin address
CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
if (!address.IsValid())
@@ -557,6 +575,8 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 1)
@@ -643,6 +663,8 @@ Value getbalance(const Array& params, bool fHelp)
+ HelpExampleRpc("getbalance", "\"*\", 6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (params.size() == 0)
return ValueFromAmount(pwalletMain->GetBalance());
@@ -695,6 +717,9 @@ Value getunconfirmedbalance(const Array &params, bool fHelp)
throw runtime_error(
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
}
@@ -721,6 +746,8 @@ Value movecmd(const Array& params, bool fHelp)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]);
CAmount nAmount = AmountFromValue(params[2]);
@@ -793,6 +820,8 @@ Value sendfrom(const Array& params, bool fHelp)
+ HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount = AccountFromValue(params[0]);
CBitcoinAddress address(params[1].get_str());
if (!address.IsValid())
@@ -850,6 +879,8 @@ Value sendmany(const Array& params, bool fHelp)
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount = AccountFromValue(params[0]);
Object sendTo = params[1].get_obj();
int nMinDepth = 1;
@@ -935,6 +966,8 @@ Value addmultisigaddress(const Array& params, bool fHelp)
throw runtime_error(msg);
}
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount;
if (params.size() > 2)
strAccount = AccountFromValue(params[2]);
@@ -1110,6 +1143,8 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
return ListReceived(params, false);
}
@@ -1141,6 +1176,8 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
return ListReceived(params, true);
}
@@ -1292,6 +1329,8 @@ Value listtransactions(const Array& params, bool fHelp)
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount = "*";
if (params.size() > 0)
strAccount = params[0].get_str();
@@ -1372,6 +1411,8 @@ Value listaccounts(const Array& params, bool fHelp)
+ HelpExampleRpc("listaccounts", "6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
@@ -1460,6 +1501,8 @@ Value listsinceblock(const Array& params, bool fHelp)
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CBlockIndex *pindex = NULL;
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
@@ -1546,6 +1589,8 @@ Value gettransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
uint256 hash;
hash.SetHex(params[0].get_str());
@@ -1594,6 +1639,8 @@ Value backupwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strDest = params[0].get_str();
if (!BackupWallet(*pwalletMain, strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
@@ -1616,6 +1663,8 @@ Value keypoolrefill(const Array& params, bool fHelp)
+ HelpExampleRpc("keypoolrefill", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
unsigned int kpSize = 0;
if (params.size() > 0) {
@@ -1663,6 +1712,8 @@ Value walletpassphrase(const Array& params, bool fHelp)
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
@@ -1710,6 +1761,8 @@ Value walletpassphrasechange(const Array& params, bool fHelp)
+ HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
@@ -1756,6 +1809,8 @@ Value walletlock(const Array& params, bool fHelp)
+ HelpExampleRpc("walletlock", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
@@ -1797,6 +1852,8 @@ Value encryptwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (fHelp)
return true;
if (pwalletMain->IsCrypted())
@@ -1861,6 +1918,8 @@ Value lockunspent(const Array& params, bool fHelp)
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (params.size() == 1)
RPCTypeCheck(params, boost::assign::list_of(bool_type));
else
@@ -1930,6 +1989,8 @@ Value listlockunspent(const Array& params, bool fHelp)
+ HelpExampleRpc("listlockunspent", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
vector<COutPoint> vOutpts;
pwalletMain->ListLockedCoins(vOutpts);
@@ -1961,6 +2022,8 @@ Value settxfee(const Array& params, bool fHelp)
+ HelpExampleRpc("settxfee", "0.00001")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Amount
CAmount nAmount = 0;
if (params[0].get_real() != 0.0)
@@ -1992,6 +2055,8 @@ Value getwalletinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getwalletinfo", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
Object obj;
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index c8dd54a747..b0d5faaf77 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -78,7 +78,7 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i
// Regardless of the verification result, the tx did not error.
set_error(err, bitcoinconsensus_ERR_OK);
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, SignatureChecker(tx, nIn), NULL);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 9d9c266435..0320577797 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -46,6 +46,7 @@ enum
{
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
+ bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
};
/// Returns 1 if the input nIn of the serialized transaction pointed to by
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 0cee1a0116..84a7432fdb 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -93,76 +93,76 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
* in which case a single 0 byte is necessary and even required).
*
* See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
+ *
+ * This function is consensus-critical since BIP66.
*/
-bool static IsDERSignature(const valtype &vchSig) {
+bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {
+ // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
+ // * total-length: 1-byte length descriptor of everything that follows,
+ // excluding the sighash byte.
+ // * R-length: 1-byte length descriptor of the R value that follows.
+ // * R: arbitrary-length big-endian encoded R value. It must use the shortest
+ // possible encoding for a positive integers (which means no null bytes at
+ // the start, except a single one when the next byte has its highest bit set).
+ // * S-length: 1-byte length descriptor of the S value that follows.
+ // * S: arbitrary-length big-endian encoded S value. The same rules apply.
+ // * sighash: 1-byte value indicating what data is hashed (not part of the DER
+ // signature)
- if (vchSig.size() < 9) {
- // Non-canonical signature: too short
- return false;
- }
- if (vchSig.size() > 73) {
- // Non-canonical signature: too long
- return false;
- }
- if (vchSig[0] != 0x30) {
- // Non-canonical signature: wrong type
- return false;
- }
- if (vchSig[1] != vchSig.size()-3) {
- // Non-canonical signature: wrong length marker
- return false;
- }
- unsigned int nLenR = vchSig[3];
- if (5 + nLenR >= vchSig.size()) {
- // Non-canonical signature: S length misplaced
- return false;
- }
- unsigned int nLenS = vchSig[5+nLenR];
- if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) {
- // Non-canonical signature: R+S length mismatch
- return false;
- }
+ // Minimum and maximum size constraints.
+ if (sig.size() < 9) return false;
+ if (sig.size() > 73) return false;
- const unsigned char *R = &vchSig[4];
- if (R[-2] != 0x02) {
- // Non-canonical signature: R value type mismatch
- return false;
- }
- if (nLenR == 0) {
- // Non-canonical signature: R length is zero
- return false;
- }
- if (R[0] & 0x80) {
- // Non-canonical signature: R value negative
- return false;
- }
- if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) {
- // Non-canonical signature: R value excessively padded
- return false;
- }
+ // A signature is of type 0x30 (compound).
+ if (sig[0] != 0x30) return false;
+
+ // Make sure the length covers the entire signature.
+ if (sig[1] != sig.size() - 3) return false;
+
+ // Extract the length of the R element.
+ unsigned int lenR = sig[3];
+
+ // Make sure the length of the S element is still inside the signature.
+ if (5 + lenR >= sig.size()) return false;
+
+ // Extract the length of the S element.
+ unsigned int lenS = sig[5 + lenR];
+
+ // Verify that the length of the signature matches the sum of the length
+ // of the elements.
+ if ((size_t)(lenR + lenS + 7) != sig.size()) return false;
+
+ // Check whether the R element is an integer.
+ if (sig[2] != 0x02) return false;
+
+ // Zero-length integers are not allowed for R.
+ if (lenR == 0) return false;
+
+ // Negative numbers are not allowed for R.
+ if (sig[4] & 0x80) return false;
+
+ // Null bytes at the start of R are not allowed, unless R would
+ // otherwise be interpreted as a negative number.
+ if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false;
+
+ // Check whether the S element is an integer.
+ if (sig[lenR + 4] != 0x02) return false;
+
+ // Zero-length integers are not allowed for S.
+ if (lenS == 0) return false;
+
+ // Negative numbers are not allowed for S.
+ if (sig[lenR + 6] & 0x80) return false;
+
+ // Null bytes at the start of S are not allowed, unless S would otherwise be
+ // interpreted as a negative number.
+ if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false;
- const unsigned char *S = &vchSig[6+nLenR];
- if (S[-2] != 0x02) {
- // Non-canonical signature: S value type mismatch
- return false;
- }
- if (nLenS == 0) {
- // Non-canonical signature: S length is zero
- return false;
- }
- if (S[0] & 0x80) {
- // Non-canonical signature: S value negative
- return false;
- }
- if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) {
- // Non-canonical signature: S value excessively padded
- return false;
- }
return true;
}
bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
- if (!IsDERSignature(vchSig)) {
+ if (!IsValidSignatureEncoding(vchSig)) {
return set_error(serror, SCRIPT_ERR_SIG_DER);
}
unsigned int nLenR = vchSig[3];
@@ -194,7 +194,7 @@ bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, Sc
if (vchSig.size() == 0) {
return true;
}
- if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) {
+ if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsValidSignatureEncoding(vchSig)) {
return set_error(serror, SCRIPT_ERR_SIG_DER);
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {
// serror is set
@@ -1058,12 +1058,12 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
return ss.GetHash();
}
-bool SignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
+bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
return pubkey.Verify(sighash, vchSig);
}
-bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
@@ -1076,7 +1076,7 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec
int nHashType = vchSig.back();
vchSig.pop_back();
- uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
+ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 8bf379ed89..fc64438f68 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -7,6 +7,7 @@
#define BITCOIN_SCRIPT_INTERPRETER_H
#include "script_error.h"
+#include "primitives/transaction.h"
#include <vector>
#include <stdint.h>
@@ -90,20 +91,29 @@ public:
virtual ~BaseSignatureChecker() {}
};
-class SignatureChecker : public BaseSignatureChecker
+class TransactionSignatureChecker : public BaseSignatureChecker
{
private:
- const CTransaction& txTo;
+ const CTransaction* txTo;
unsigned int nIn;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- SignatureChecker(const CTransaction& txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
};
+class MutableTransactionSignatureChecker : public TransactionSignatureChecker
+{
+private:
+ const CTransaction txTo;
+
+public:
+ MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {}
+};
+
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 75ecdb563d..099b4ad0e3 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -74,14 +74,14 @@ public:
}
-bool CachingSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
+bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
static CSignatureCache signatureCache;
if (signatureCache.Get(sighash, vchSig, pubkey))
return true;
- if (!SignatureChecker::VerifySignature(vchSig, pubkey, sighash))
+ if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))
return false;
if (store)
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 3bd11caff5..b299038daa 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -12,13 +12,13 @@
class CPubKey;
-class CachingSignatureChecker : public SignatureChecker
+class CachingTransactionSignatureChecker : public TransactionSignatureChecker
{
private:
bool store;
public:
- CachingSignatureChecker(const CTransaction& txToIn, unsigned int nInIn, bool storeIn=true) : SignatureChecker(txToIn, nInIn), store(storeIn) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index adddd4ec78..14119f7e2c 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -123,7 +123,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl
}
// Test solution
- return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(txTo, nIn));
+ return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&txTo, nIn));
}
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
@@ -174,7 +174,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction&
if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey
- if (SignatureChecker(txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
+ if (TransactionSignatureChecker(&txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
{
sigs[pubkey] = sig;
break;
diff --git a/src/script/standard.h b/src/script/standard.h
index ac80193773..a8b0acc981 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -25,7 +25,7 @@ public:
CScriptID(const uint160& in) : uint160(in) {}
};
-static const unsigned int MAX_OP_RETURN_RELAY = 40; //! bytes
+static const unsigned int MAX_OP_RETURN_RELAY = 80; //! bytes
extern unsigned nMaxDatacarrierBytes;
/**
@@ -45,6 +45,7 @@ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
* blocks and we must accept those blocks.
*/
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
+ SCRIPT_VERIFY_DERSIG |
SCRIPT_VERIFY_STRICTENC |
SCRIPT_VERIFY_MINIMALDATA |
SCRIPT_VERIFY_NULLDUMMY |
diff --git a/src/sync.h b/src/sync.h
index 7891e41560..27e80e813b 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -142,6 +142,17 @@ public:
Enter(pszName, pszFile, nLine);
}
+ CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false)
+ {
+ if (!pmutexIn) return;
+
+ lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
+ if (fTry)
+ TryEnter(pszName, pszFile, nLine);
+ else
+ Enter(pszName, pszFile, nLine);
+ }
+
~CMutexLock()
{
if (lock.owns_lock())
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 9a8fe1ee88..a67c157aff 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -510,6 +510,16 @@
"2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid."
],
+["Increase DERSIG test coverage"],
+["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Overly long signature is incorrectly encoded for DERSIG"],
+["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "DERSIG", "Missing S is incorrectly encoded for DERSIG"],
+["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "S with invalid S length is incorrectly encoded for DERSIG"],
+["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer R is incorrectly encoded for DERSIG"],
+["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Non-integer S is incorrectly encoded for DERSIG"],
+["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Zero-length R is incorrectly encoded for DERSIG"],
+["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "DERSIG", "Zero-length S is incorrectly encoded for DERSIG"],
+["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "DERSIG", "Negative S is incorrectly encoded for DERSIG"],
+
["Automatically generated test cases"],
[
"0x47 0x3044022053205076a7bb12d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
@@ -590,6 +600,102 @@
"P2PK NOT with too much R padding"
],
[
+ "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "DERSIG",
+ "BIP66 example 1, with DERSIG"
+],
+[
+ "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "",
+ "BIP66 example 2, without DERSIG"
+],
+[
+ "0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "DERSIG",
+ "BIP66 example 2, with DERSIG"
+],
+[
+ "0",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "BIP66 example 3, without DERSIG"
+],
+[
+ "0",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "DERSIG",
+ "BIP66 example 3, with DERSIG"
+],
+[
+ "1",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "BIP66 example 5, without DERSIG"
+],
+[
+ "1",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "DERSIG",
+ "BIP66 example 5, with DERSIG"
+],
+[
+ "1",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "DERSIG",
+ "BIP66 example 6, with DERSIG"
+],
+[
+ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x304402200b3d0b0375bb15c14620afa4aa10ae90a0d6a046ce217bc20fe0bc1ced68c1b802204b550acab90ae6d3478057c9ad24f9df743815b799b6449dd7e7f6d3bc6e274c01",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
+ "DERSIG",
+ "BIP66 example 7, with DERSIG"
+],
+[
+ "0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
+ "",
+ "BIP66 example 8, without DERSIG"
+],
+[
+ "0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
+ "DERSIG",
+ "BIP66 example 8, with DERSIG"
+],
+[
+ "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
+ "",
+ "BIP66 example 9, without DERSIG"
+],
+[
+ "0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
+ "DERSIG",
+ "BIP66 example 9, with DERSIG"
+],
+[
+ "0 0 0x47 0x30440220afa76a8f60622f813b05711f051c6c3407e32d1b1b70b0576c1f01b54e4c05c702200d58e9df044fd1845cabfbeef6e624ba0401daf7d7e084736f9ff601c3783bf501",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
+ "DERSIG",
+ "BIP66 example 10, with DERSIG"
+],
+[
+ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
+ "",
+ "BIP66 example 11, without DERSIG"
+],
+[
+ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
+ "DERSIG",
+ "BIP66 example 11, with DERSIG"
+],
+[
"0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
"LOW_S",
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index a187401cd4..fb81fcb1f5 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -688,6 +688,16 @@
"2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature."
],
+["Increase test coverage for DERSIG"],
+["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "Overly long signature is correctly encoded"],
+["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000", "0 CHECKSIG NOT", "", "Missing S is correctly encoded"],
+["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701", "0 CHECKSIG NOT", "", "S with invalid S length is correctly encoded"],
+["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Non-integer R is correctly encoded"],
+["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Non-integer S is correctly encoded"],
+["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Zero-length R is correctly encoded"],
+["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "Zero-length S is correctly encoded for DERSIG"],
+["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "Negative S is correctly encoded"],
+
["Automatically generated test cases"],
[
"0x47 0x3044022053205076a7bb13d2db3162a2d97d8197631f829b065948b7019b15482af819a902204328dcc02c994ca086b1226d0d5f1674d23cfae0d846143df812b81cab3391e801",
@@ -756,6 +766,54 @@
"P2PK NOT with bad sig with too much R padding but no DERSIG"
],
[
+ "0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG",
+ "",
+ "BIP66 example 1, without DERSIG"
+],
+[
+ "0",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "",
+ "BIP66 example 4, without DERSIG"
+],
+[
+ "0",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "DERSIG",
+ "BIP66 example 4, with DERSIG"
+],
+[
+ "1",
+ "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT",
+ "",
+ "BIP66 example 6, without DERSIG"
+],
+[
+ "0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x304402200b3d0b0375bb15c14620afa4aa10ae90a0d6a046ce217bc20fe0bc1ced68c1b802204b550acab90ae6d3478057c9ad24f9df743815b799b6449dd7e7f6d3bc6e274c01",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG",
+ "",
+ "BIP66 example 7, without DERSIG"
+],
+[
+ "0 0 0x47 0x30440220afa76a8f60622f813b05711f051c6c3407e32d1b1b70b0576c1f01b54e4c05c702200d58e9df044fd1845cabfbeef6e624ba0401daf7d7e084736f9ff601c3783bf501",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
+ "",
+ "BIP66 example 10, without DERSIG"
+],
+[
+ "0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
+ "",
+ "BIP66 example 12, without DERSIG"
+],
+[
+ "0 0x47 0x30440220f00a77260d34ec2f0c59621dc710f58169d0ca06df1a88cd4b1f1b97bd46991b02201ee220c7e04f26aed03f94aa97fb09ca5627163bf4ba07e6979972ec737db22601 0",
+ "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT",
+ "DERSIG",
+ "BIP66 example 12, with DERSIG"
+],
+[
"0x49 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef05101",
"0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
"",
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 9501169943..2168a5fef1 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -82,20 +82,20 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys.assign(1,key[0]);
keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK(VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err));
+ BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++)
{
keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err), strprintf("a&b 1: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 1: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.assign(1,key[1]);
keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err), strprintf("a&b 2: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 2: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@@ -106,18 +106,18 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
s = sign_multisig(a_or_b, keys, txTo[1], 0);
if (i == 0 || i == 1)
{
- BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err), strprintf("a|b: %d", i));
+ BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else
{
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err), strprintf("a|b: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
}
s.clear();
s << OP_0 << OP_1;
- BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err));
+ BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
@@ -129,12 +129,12 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
s = sign_multisig(escrow, keys, txTo[2], 0);
if (i < j && i < 3 && j < 3)
{
- BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j));
+ BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else
{
- BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
}
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 77e70022df..94f2ce1a29 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -43,7 +43,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1;
- return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, SignatureChecker(txTo, 0), &err);
+ return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
}
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 4db8942fa1..6092afd782 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -93,7 +93,7 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bo
ScriptError err;
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey));
CMutableTransaction tx2 = tx;
- BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(tx, 0), &err) == expect, message);
+ BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0), &err) == expect, message);
BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
#if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
@@ -406,6 +406,79 @@ BOOST_AUTO_TEST_CASE(script_build)
"P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
+ good.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"));
+ bad.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"));
+ bad.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"));
+ bad.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"));
+ bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
+ "BIP66 example 3, without DERSIG", 0
+ ).Num(0));
+ bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
+ "BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG
+ ).Num(0));
+ good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
+ "BIP66 example 4, without DERSIG", 0
+ ).Num(0));
+ good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
+ "BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG
+ ).Num(0));
+ bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
+ "BIP66 example 5, without DERSIG", 0
+ ).Num(1));
+ bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
+ "BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG
+ ).Num(1));
+ good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
+ "BIP66 example 6, without DERSIG", 0
+ ).Num(1));
+ bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
+ "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG
+ ).Num(1));
+ good.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));
+ bad.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));
+ bad.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));
+ bad.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));
+ bad.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"));
+ bad.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"));
+ good.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"));
+ bad.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"));
+ bad.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));
+ bad.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));
+ good.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));
+ good.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));
+
good.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));
@@ -682,18 +755,18 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
- BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
+ BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
txTo12.vout[0].nValue = 2;
- BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
+ BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
- BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
- BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@@ -715,54 +788,54 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &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, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &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, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &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, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &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, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &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, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &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, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &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, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &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, SignatureChecker(txTo23, 0), &err));
+ BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
}
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 96134cd72e..52adfea992 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- verify_flags, SignatureChecker(tx, i), &err),
+ verify_flags, TransactionSignatureChecker(&tx, i), &err),
strTest);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
@@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- verify_flags, SignatureChecker(tx, i), &err);
+ verify_flags, TransactionSignatureChecker(&tx, i), &err);
}
BOOST_CHECK_MESSAGE(!fValid, strTest);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
@@ -347,12 +347,12 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
t.vout[0].scriptPubKey = CScript() << OP_1;
BOOST_CHECK(!IsStandardTx(t, reason));
- // 40-byte TX_NULL_DATA (standard)
- t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
+ // 80-byte TX_NULL_DATA (standard)
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
BOOST_CHECK(IsStandardTx(t, reason));
- // 41-byte TX_NULL_DATA (non-standard)
- t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
+ // 81-byte TX_NULL_DATA (non-standard)
+ t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
BOOST_CHECK(!IsStandardTx(t, reason));
// TX_NULL_DATA w/o PUSHDATA
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 1c5778abed..d829ec228d 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -282,21 +282,21 @@ BOOST_AUTO_TEST_CASE(strprintf_numbers)
{
int64_t s64t = -9223372036854775807LL; /* signed 64 bit test value */
uint64_t u64t = 18446744073709551615ULL; /* unsigned 64 bit test value */
- BOOST_CHECK(strprintf("%s %d %s", B, s64t, E) == B" -9223372036854775807 "E);
- BOOST_CHECK(strprintf("%s %u %s", B, u64t, E) == B" 18446744073709551615 "E);
- BOOST_CHECK(strprintf("%s %x %s", B, u64t, E) == B" ffffffffffffffff "E);
+ BOOST_CHECK(strprintf("%s %d %s", B, s64t, E) == B" -9223372036854775807 " E);
+ BOOST_CHECK(strprintf("%s %u %s", B, u64t, E) == B" 18446744073709551615 " E);
+ BOOST_CHECK(strprintf("%s %x %s", B, u64t, E) == B" ffffffffffffffff " E);
size_t st = 12345678; /* unsigned size_t test value */
ssize_t sst = -12345678; /* signed size_t test value */
- BOOST_CHECK(strprintf("%s %d %s", B, sst, E) == B" -12345678 "E);
- BOOST_CHECK(strprintf("%s %u %s", B, st, E) == B" 12345678 "E);
- BOOST_CHECK(strprintf("%s %x %s", B, st, E) == B" bc614e "E);
+ BOOST_CHECK(strprintf("%s %d %s", B, sst, E) == B" -12345678 " E);
+ BOOST_CHECK(strprintf("%s %u %s", B, st, E) == B" 12345678 " E);
+ BOOST_CHECK(strprintf("%s %x %s", B, st, E) == B" bc614e " E);
ptrdiff_t pt = 87654321; /* positive ptrdiff_t test value */
ptrdiff_t spt = -87654321; /* negative ptrdiff_t test value */
- BOOST_CHECK(strprintf("%s %d %s", B, spt, E) == B" -87654321 "E);
- BOOST_CHECK(strprintf("%s %u %s", B, pt, E) == B" 87654321 "E);
- BOOST_CHECK(strprintf("%s %x %s", B, pt, E) == B" 5397fb1 "E);
+ BOOST_CHECK(strprintf("%s %d %s", B, spt, E) == B" -87654321 " E);
+ BOOST_CHECK(strprintf("%s %u %s", B, pt, E) == B" 87654321 " E);
+ BOOST_CHECK(strprintf("%s %x %s", B, pt, E) == B" 5397fb1 " E);
}
#undef B
#undef E
diff --git a/src/wallet.cpp b/src/wallet.cpp
index d66a4465c5..b51c4d4b14 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -1015,6 +1015,193 @@ set<uint256> CWalletTx::GetConflicts() const
return result;
}
+CAmount CWalletTx::GetDebit(const isminefilter& filter) const
+{
+ if (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;
+
+ int64_t 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 = GetHash();
+ for (unsigned int i = 0; i < vout.size(); i++)
+ {
+ if (!pwallet->IsSpent(hashTx, i))
+ {
+ const CTxOut &txout = 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 < vout.size(); i++)
+ {
+ if (!pwallet->IsSpent(GetHash(), i))
+ {
+ const CTxOut &txout = 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::IsTrusted() const
+{
+ // Quick answer in most cases
+ if (!IsFinalTx(*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;
+
+ // Trusted if all inputs are from us and are in the mempool:
+ BOOST_FOREACH(const CTxIn& txin, 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->vout[txin.prevout.n];
+ if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
+ return false;
+ }
+ return true;
+}
+
void CWallet::ResendWalletTransactions()
{
// Do this infrequently and randomly to avoid giving away
@@ -1445,10 +1632,14 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend,
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
CAmount nCredit = pcoin.first->vout[pcoin.second].nValue;
- //The priority after the next block (depth+1) is used instead of the current,
+ //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.
- dPriority += (double)nCredit * (pcoin.first->GetDepthInMainChain()+1);
+ //But mempool inputs might still be in the mempool, so their age stays 0
+ int age = pcoin.first->GetDepthInMainChain();
+ if (age != 0)
+ age += 1;
+ dPriority += (double)nCredit * age;
}
CAmount nChange = nValueIn - nValue - nFeeRet;
@@ -2365,9 +2556,9 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee)
+bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee);
}
diff --git a/src/wallet.h b/src/wallet.h
index aaff00b716..6ed87d1e68 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -103,6 +103,329 @@ public:
StringMap destdata;
};
+
+typedef std::map<std::string, std::string> mapValue_t;
+
+
+static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
+{
+ if (!mapValue.count("n"))
+ {
+ nOrderPos = -1; // TODO: calculate elsewhere
+ return;
+ }
+ nOrderPos = atoi64(mapValue["n"].c_str());
+}
+
+
+static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
+{
+ if (nOrderPos == -1)
+ return;
+ mapValue["n"] = i64tostr(nOrderPos);
+}
+
+struct COutputEntry
+{
+ CTxDestination destination;
+ CAmount amount;
+ int vout;
+};
+
+/** A transaction with a merkle branch linking it to the block chain. */
+class CMerkleTx : public CTransaction
+{
+private:
+ int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
+
+public:
+ uint256 hashBlock;
+ std::vector<uint256> vMerkleBranch;
+ int nIndex;
+
+ // memory only
+ mutable bool fMerkleVerified;
+
+
+ CMerkleTx()
+ {
+ Init();
+ }
+
+ CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
+ {
+ Init();
+ }
+
+ void Init()
+ {
+ hashBlock = uint256();
+ nIndex = -1;
+ fMerkleVerified = false;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(*(CTransaction*)this);
+ nVersion = this->nVersion;
+ READWRITE(hashBlock);
+ READWRITE(vMerkleBranch);
+ READWRITE(nIndex);
+ }
+
+ int SetMerkleBranch(const CBlock& block);
+
+
+ /**
+ * Return depth of transaction in blockchain:
+ * -1 : not in blockchain, and not in memory pool (conflicted transaction)
+ * 0 : in memory pool, waiting to be included in a block
+ * >=1 : this many blocks deep in the main chain
+ */
+ int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;
+ int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
+ bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
+ int GetBlocksToMaturity() const;
+ bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
+};
+
+/**
+ * A transaction with a bunch of additional info that only the owner cares about.
+ * It includes any unrecorded transactions needed to link it back to the block chain.
+ */
+class CWalletTx : public CMerkleTx
+{
+private:
+ const CWallet* pwallet;
+
+public:
+ mapValue_t mapValue;
+ std::vector<std::pair<std::string, std::string> > vOrderForm;
+ unsigned int fTimeReceivedIsTxTime;
+ unsigned int nTimeReceived; //! time received by this node
+ unsigned int nTimeSmart;
+ char fFromMe;
+ std::string strFromAccount;
+ int64_t nOrderPos; //! position in ordered transaction list
+
+ // memory only
+ mutable bool fDebitCached;
+ mutable bool fCreditCached;
+ mutable bool fImmatureCreditCached;
+ mutable bool fAvailableCreditCached;
+ mutable bool fWatchDebitCached;
+ mutable bool fWatchCreditCached;
+ mutable bool fImmatureWatchCreditCached;
+ mutable bool fAvailableWatchCreditCached;
+ mutable bool fChangeCached;
+ mutable CAmount nDebitCached;
+ mutable CAmount nCreditCached;
+ mutable CAmount nImmatureCreditCached;
+ mutable CAmount nAvailableCreditCached;
+ mutable CAmount nWatchDebitCached;
+ mutable CAmount nWatchCreditCached;
+ mutable CAmount nImmatureWatchCreditCached;
+ mutable CAmount nAvailableWatchCreditCached;
+ mutable CAmount nChangeCached;
+
+ CWalletTx()
+ {
+ Init(NULL);
+ }
+
+ CWalletTx(const CWallet* pwalletIn)
+ {
+ Init(pwalletIn);
+ }
+
+ CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
+ {
+ Init(pwalletIn);
+ }
+
+ CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
+ {
+ Init(pwalletIn);
+ }
+
+ void Init(const CWallet* pwalletIn)
+ {
+ pwallet = pwalletIn;
+ mapValue.clear();
+ vOrderForm.clear();
+ fTimeReceivedIsTxTime = false;
+ nTimeReceived = 0;
+ nTimeSmart = 0;
+ fFromMe = false;
+ strFromAccount.clear();
+ fDebitCached = false;
+ fCreditCached = false;
+ fImmatureCreditCached = false;
+ fAvailableCreditCached = false;
+ fWatchDebitCached = false;
+ fWatchCreditCached = false;
+ fImmatureWatchCreditCached = false;
+ fAvailableWatchCreditCached = false;
+ fChangeCached = false;
+ nDebitCached = 0;
+ nCreditCached = 0;
+ nImmatureCreditCached = 0;
+ nAvailableCreditCached = 0;
+ nWatchDebitCached = 0;
+ nWatchCreditCached = 0;
+ nAvailableWatchCreditCached = 0;
+ nImmatureWatchCreditCached = 0;
+ nChangeCached = 0;
+ nOrderPos = -1;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ if (ser_action.ForRead())
+ Init(NULL);
+ char fSpent = false;
+
+ if (!ser_action.ForRead())
+ {
+ mapValue["fromaccount"] = strFromAccount;
+
+ WriteOrderPos(nOrderPos, mapValue);
+
+ if (nTimeSmart)
+ mapValue["timesmart"] = strprintf("%u", nTimeSmart);
+ }
+
+ READWRITE(*(CMerkleTx*)this);
+ std::vector<CMerkleTx> vUnused; //! Used to be vtxPrev
+ READWRITE(vUnused);
+ READWRITE(mapValue);
+ READWRITE(vOrderForm);
+ READWRITE(fTimeReceivedIsTxTime);
+ READWRITE(nTimeReceived);
+ READWRITE(fFromMe);
+ READWRITE(fSpent);
+
+ if (ser_action.ForRead())
+ {
+ strFromAccount = mapValue["fromaccount"];
+
+ ReadOrderPos(nOrderPos, mapValue);
+
+ nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
+ }
+
+ mapValue.erase("fromaccount");
+ mapValue.erase("version");
+ mapValue.erase("spent");
+ mapValue.erase("n");
+ mapValue.erase("timesmart");
+ }
+
+ //! make sure balances are recalculated
+ void MarkDirty()
+ {
+ fCreditCached = false;
+ fAvailableCreditCached = false;
+ fWatchDebitCached = false;
+ fWatchCreditCached = false;
+ fAvailableWatchCreditCached = false;
+ fImmatureWatchCreditCached = false;
+ fDebitCached = false;
+ fChangeCached = false;
+ }
+
+ void BindWallet(CWallet *pwalletIn)
+ {
+ pwallet = pwalletIn;
+ MarkDirty();
+ }
+
+ //! filter decides which addresses will count towards the debit
+ CAmount GetDebit(const isminefilter& filter) const;
+ CAmount GetCredit(const isminefilter& filter) const;
+ CAmount GetImmatureCredit(bool fUseCache=true) const;
+ CAmount GetAvailableCredit(bool fUseCache=true) const;
+ CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const;
+ CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const;
+ CAmount GetChange() const;
+
+ void GetAmounts(std::list<COutputEntry>& listReceived,
+ std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
+
+ void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
+ CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
+
+ bool IsFromMe(const isminefilter& filter) const
+ {
+ return (GetDebit(filter) > 0);
+ }
+
+ bool IsTrusted() const;
+
+ bool WriteToDisk(CWalletDB *pwalletdb);
+
+ int64_t GetTxTime() const;
+ int GetRequestCount() const;
+
+ void RelayWalletTransaction();
+
+ std::set<uint256> GetConflicts() const;
+};
+
+
+
+
+class COutput
+{
+public:
+ const CWalletTx *tx;
+ int i;
+ int nDepth;
+ bool fSpendable;
+
+ COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn)
+ {
+ tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn;
+ }
+
+ std::string ToString() const;
+};
+
+
+
+
+/** Private key that includes an expiration date in case it never gets used. */
+class CWalletKey
+{
+public:
+ CPrivKey vchPrivKey;
+ int64_t nTimeCreated;
+ int64_t nTimeExpires;
+ std::string strComment;
+ //! todo: add something to note what created it (user, getnewaddress, change)
+ //! maybe should have a map<string, string> property map
+
+ CWalletKey(int64_t nExpires=0);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(vchPrivKey);
+ READWRITE(nTimeCreated);
+ READWRITE(nTimeExpires);
+ READWRITE(LIMITED_STRING(strComment, 65536));
+ }
+};
+
+
+
/**
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
@@ -464,508 +787,6 @@ public:
};
-typedef std::map<std::string, std::string> mapValue_t;
-
-
-static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
-{
- if (!mapValue.count("n"))
- {
- nOrderPos = -1; // TODO: calculate elsewhere
- return;
- }
- nOrderPos = atoi64(mapValue["n"].c_str());
-}
-
-
-static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
-{
- if (nOrderPos == -1)
- return;
- mapValue["n"] = i64tostr(nOrderPos);
-}
-
-struct COutputEntry
-{
- CTxDestination destination;
- CAmount amount;
- int vout;
-};
-
-/** A transaction with a merkle branch linking it to the block chain. */
-class CMerkleTx : public CTransaction
-{
-private:
- int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
-
-public:
- uint256 hashBlock;
- std::vector<uint256> vMerkleBranch;
- int nIndex;
-
- // memory only
- mutable bool fMerkleVerified;
-
-
- CMerkleTx()
- {
- Init();
- }
-
- CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
- {
- Init();
- }
-
- void Init()
- {
- hashBlock = uint256();
- nIndex = -1;
- fMerkleVerified = false;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(*(CTransaction*)this);
- nVersion = this->nVersion;
- READWRITE(hashBlock);
- READWRITE(vMerkleBranch);
- READWRITE(nIndex);
- }
-
- int SetMerkleBranch(const CBlock& block);
-
-
- /**
- * Return depth of transaction in blockchain:
- * -1 : not in blockchain, and not in memory pool (conflicted transaction)
- * 0 : in memory pool, waiting to be included in a block
- * >=1 : this many blocks deep in the main chain
- */
- int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;
- int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
- bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
- int GetBlocksToMaturity() const;
- bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectInsaneFee=true);
-};
-
-/**
- * A transaction with a bunch of additional info that only the owner cares about.
- * It includes any unrecorded transactions needed to link it back to the block chain.
- */
-class CWalletTx : public CMerkleTx
-{
-private:
- const CWallet* pwallet;
-
-public:
- mapValue_t mapValue;
- std::vector<std::pair<std::string, std::string> > vOrderForm;
- unsigned int fTimeReceivedIsTxTime;
- unsigned int nTimeReceived; //! time received by this node
- unsigned int nTimeSmart;
- char fFromMe;
- std::string strFromAccount;
- int64_t nOrderPos; //! position in ordered transaction list
-
- // memory only
- mutable bool fDebitCached;
- mutable bool fCreditCached;
- mutable bool fImmatureCreditCached;
- mutable bool fAvailableCreditCached;
- mutable bool fWatchDebitCached;
- mutable bool fWatchCreditCached;
- mutable bool fImmatureWatchCreditCached;
- mutable bool fAvailableWatchCreditCached;
- mutable bool fChangeCached;
- mutable CAmount nDebitCached;
- mutable CAmount nCreditCached;
- mutable CAmount nImmatureCreditCached;
- mutable CAmount nAvailableCreditCached;
- mutable CAmount nWatchDebitCached;
- mutable CAmount nWatchCreditCached;
- mutable CAmount nImmatureWatchCreditCached;
- mutable CAmount nAvailableWatchCreditCached;
- mutable CAmount nChangeCached;
-
- CWalletTx()
- {
- Init(NULL);
- }
-
- CWalletTx(const CWallet* pwalletIn)
- {
- Init(pwalletIn);
- }
-
- CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
- {
- Init(pwalletIn);
- }
-
- CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
- {
- Init(pwalletIn);
- }
-
- void Init(const CWallet* pwalletIn)
- {
- pwallet = pwalletIn;
- mapValue.clear();
- vOrderForm.clear();
- fTimeReceivedIsTxTime = false;
- nTimeReceived = 0;
- nTimeSmart = 0;
- fFromMe = false;
- strFromAccount.clear();
- fDebitCached = false;
- fCreditCached = false;
- fImmatureCreditCached = false;
- fAvailableCreditCached = false;
- fWatchDebitCached = false;
- fWatchCreditCached = false;
- fImmatureWatchCreditCached = false;
- fAvailableWatchCreditCached = false;
- fChangeCached = false;
- nDebitCached = 0;
- nCreditCached = 0;
- nImmatureCreditCached = 0;
- nAvailableCreditCached = 0;
- nWatchDebitCached = 0;
- nWatchCreditCached = 0;
- nAvailableWatchCreditCached = 0;
- nImmatureWatchCreditCached = 0;
- nChangeCached = 0;
- nOrderPos = -1;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (ser_action.ForRead())
- Init(NULL);
- char fSpent = false;
-
- if (!ser_action.ForRead())
- {
- mapValue["fromaccount"] = strFromAccount;
-
- WriteOrderPos(nOrderPos, mapValue);
-
- if (nTimeSmart)
- mapValue["timesmart"] = strprintf("%u", nTimeSmart);
- }
-
- READWRITE(*(CMerkleTx*)this);
- std::vector<CMerkleTx> vUnused; //! Used to be vtxPrev
- READWRITE(vUnused);
- READWRITE(mapValue);
- READWRITE(vOrderForm);
- READWRITE(fTimeReceivedIsTxTime);
- READWRITE(nTimeReceived);
- READWRITE(fFromMe);
- READWRITE(fSpent);
-
- if (ser_action.ForRead())
- {
- strFromAccount = mapValue["fromaccount"];
-
- ReadOrderPos(nOrderPos, mapValue);
-
- nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
- }
-
- mapValue.erase("fromaccount");
- mapValue.erase("version");
- mapValue.erase("spent");
- mapValue.erase("n");
- mapValue.erase("timesmart");
- }
-
- //! make sure balances are recalculated
- void MarkDirty()
- {
- fCreditCached = false;
- fAvailableCreditCached = false;
- fWatchDebitCached = false;
- fWatchCreditCached = false;
- fAvailableWatchCreditCached = false;
- fImmatureWatchCreditCached = false;
- fDebitCached = false;
- fChangeCached = false;
- }
-
- void BindWallet(CWallet *pwalletIn)
- {
- pwallet = pwalletIn;
- MarkDirty();
- }
-
- //! filter decides which addresses will count towards the debit
- CAmount GetDebit(const isminefilter& filter) const
- {
- if (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 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;
-
- int64_t 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 GetImmatureCredit(bool fUseCache=true) const
- {
- if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
- {
- if (fUseCache && fImmatureCreditCached)
- return nImmatureCreditCached;
- nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
- fImmatureCreditCached = true;
- return nImmatureCreditCached;
- }
-
- return 0;
- }
-
- CAmount GetAvailableCredit(bool fUseCache=true) 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 = GetHash();
- for (unsigned int i = 0; i < vout.size(); i++)
- {
- if (!pwallet->IsSpent(hashTx, i))
- {
- const CTxOut &txout = 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 GetImmatureWatchOnlyCredit(const bool& fUseCache=true) 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 GetAvailableWatchOnlyCredit(const bool& fUseCache=true) 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 < vout.size(); i++)
- {
- if (!pwallet->IsSpent(GetHash(), i))
- {
- const CTxOut &txout = 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 GetChange() const
- {
- if (fChangeCached)
- return nChangeCached;
- nChangeCached = pwallet->GetChange(*this);
- fChangeCached = true;
- return nChangeCached;
- }
-
- void GetAmounts(std::list<COutputEntry>& listReceived,
- std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
-
- void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
- CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
-
- bool IsFromMe(const isminefilter& filter) const
- {
- return (GetDebit(filter) > 0);
- }
-
- bool IsTrusted() const
- {
- // Quick answer in most cases
- if (!IsFinalTx(*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;
-
- // Trusted if all inputs are from us and are in the mempool:
- BOOST_FOREACH(const CTxIn& txin, 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->vout[txin.prevout.n];
- if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE)
- return false;
- }
- return true;
- }
-
- bool WriteToDisk(CWalletDB *pwalletdb);
-
- int64_t GetTxTime() const;
- int GetRequestCount() const;
-
- void RelayWalletTransaction();
-
- std::set<uint256> GetConflicts() const;
-};
-
-
-
-
-class COutput
-{
-public:
- const CWalletTx *tx;
- int i;
- int nDepth;
- bool fSpendable;
-
- COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn)
- {
- tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn;
- }
-
- std::string ToString() const;
-};
-
-
-
-
-/** Private key that includes an expiration date in case it never gets used. */
-class CWalletKey
-{
-public:
- CPrivKey vchPrivKey;
- int64_t nTimeCreated;
- int64_t nTimeExpires;
- std::string strComment;
- //! todo: add something to note what created it (user, getnewaddress, change)
- //! maybe should have a map<string, string> property map
-
- CWalletKey(int64_t nExpires=0);
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- READWRITE(vchPrivKey);
- READWRITE(nTimeCreated);
- READWRITE(nTimeExpires);
- READWRITE(LIMITED_STRING(strComment, 65536));
- }
-};
-
-
-
-
-
-
/**
* Account information.
* Stored in wallet with key "acc"+string account name.