aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am14
-rw-r--r--src/addrman.h2
-rw-r--r--src/base58.h2
-rw-r--r--src/bitcoin-tx.cpp8
-rw-r--r--src/bloom.cpp3
-rw-r--r--src/coins.cpp38
-rw-r--r--src/coins.h8
-rw-r--r--src/core.h3
-rw-r--r--src/core_read.cpp2
-rw-r--r--src/core_write.cpp3
-rw-r--r--src/crypter.cpp2
-rw-r--r--src/keystore.cpp2
-rw-r--r--src/main.cpp57
-rw-r--r--src/main.h3
-rw-r--r--src/miner.cpp7
-rw-r--r--src/net.cpp2
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/qt/coincontroldialog.cpp4
-rw-r--r--src/qt/transactiondesc.cpp2
-rw-r--r--src/qt/walletmodel.cpp20
-rw-r--r--src/qt/walletmodel.h1
-rw-r--r--src/rpcmisc.cpp4
-rw-r--r--src/rpcrawtransaction.cpp15
-rw-r--r--src/script/compressor.cpp127
-rw-r--r--src/script/compressor.h84
-rw-r--r--src/script/interpreter.cpp (renamed from src/script.cpp)1041
-rw-r--r--src/script/interpreter.h45
-rw-r--r--src/script/script.cpp295
-rw-r--r--src/script/script.h (renamed from src/script.h)482
-rw-r--r--src/script/sign.cpp260
-rw-r--r--src/script/sign.h23
-rw-r--r--src/script/standard.cpp254
-rw-r--r--src/script/standard.h56
-rw-r--r--src/scriptutils.cpp127
-rw-r--r--src/scriptutils.h29
-rw-r--r--src/test/DoS_tests.cpp2
-rw-r--r--src/test/base58_tests.cpp2
-rw-r--r--src/test/canonical_tests.cpp4
-rw-r--r--src/test/key_tests.cpp2
-rw-r--r--src/test/multisig_tests.cpp5
-rw-r--r--src/test/script_P2SH_tests.cpp6
-rw-r--r--src/test/script_tests.cpp5
-rw-r--r--src/test/scriptnum_tests.cpp2
-rw-r--r--src/test/sighash_tests.cpp3
-rw-r--r--src/test/sigopcount_tests.cpp2
-rw-r--r--src/test/transaction_tests.cpp2
-rw-r--r--src/txmempool.cpp6
-rw-r--r--src/wallet.cpp4
-rw-r--r--src/wallet.h1
-rw-r--r--src/walletdb.cpp9
50 files changed, 1612 insertions, 1470 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 35fca6570f..9b7e99861d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -98,7 +98,12 @@ BITCOIN_CORE_H = \
rpcclient.h \
rpcprotocol.h \
rpcserver.h \
- script.h \
+ script/interpreter.h \
+ script/compressor.h \
+ script/script.h \
+ script/sign.h \
+ script/standard.h \
+ scriptutils.h \
serialize.h \
sync.h \
threadsafety.h \
@@ -206,7 +211,12 @@ libbitcoin_common_a_SOURCES = \
keystore.cpp \
netbase.cpp \
protocol.cpp \
- script.cpp \
+ script/interpreter.cpp \
+ script/compressor.cpp \
+ script/script.cpp \
+ script/sign.cpp \
+ script/standard.cpp \
+ scriptutils.cpp \
$(BITCOIN_CORE_H)
# util: shared between all executables.
diff --git a/src/addrman.h b/src/addrman.h
index 90507cb458..5fd698f18a 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -424,7 +424,7 @@ public:
Check();
}
if (fRet)
- LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort().c_str(), source.ToString(), nTried, nNew);
+ LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew);
return fRet;
}
diff --git a/src/base58.h b/src/base58.h
index 70681f589a..216aca3648 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -16,7 +16,7 @@
#include "chainparams.h"
#include "key.h"
-#include "script.h"
+#include "script/script.h"
#include <string>
#include <vector>
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 5f547bba83..91525b51c9 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -8,6 +8,8 @@
#include "core.h"
#include "main.h" // for MAX_BLOCK_SIZE
#include "keystore.h"
+#include "script/script.h"
+#include "script/sign.h"
#include "ui_interface.h" // for _(...)
#include "univalue/univalue.h"
#include "core_io.h"
@@ -418,12 +420,12 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
- CCoins coins;
- if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n)) {
+ const CCoins* coins = view.AccessCoins(txin.prevout.hash);
+ if (!coins || !coins->IsAvailable(txin.prevout.n)) {
fComplete = false;
continue;
}
- const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
+ const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
txin.scriptSig.clear();
// Only sign SIGHASH_SINGLE if there's a corresponding output:
diff --git a/src/bloom.cpp b/src/bloom.cpp
index e34041336f..cef74a3a54 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -5,7 +5,8 @@
#include "bloom.h"
#include "core.h"
-#include "script.h"
+#include "script/script.h"
+#include "script/standard.h"
#include <math.h>
#include <stdlib.h>
diff --git a/src/coins.cpp b/src/coins.cpp
index 7bfb84ef3e..34485db2bd 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -110,9 +110,13 @@ CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
return it->second;
}
-const CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) const {
- /* Avoid redundant implementation with the const-cast. */
- return const_cast<CCoinsViewCache*>(this)->GetCoins(txid);
+const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
+ CCoinsMap::const_iterator it = FetchCoins(txid);
+ if (it == cacheCoins.end()) {
+ return NULL;
+ } else {
+ return &it->second;
+ }
}
bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) {
@@ -162,9 +166,9 @@ unsigned int CCoinsViewCache::GetCacheSize() const {
const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const
{
- const CCoins &coins = GetCoins(input.prevout.hash);
- assert(coins.IsAvailable(input.prevout.n));
- return coins.vout[input.prevout.n];
+ const CCoins* coins = AccessCoins(input.prevout.hash);
+ assert(coins && coins->IsAvailable(input.prevout.n));
+ return coins->vout[input.prevout.n];
}
int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) const
@@ -182,19 +186,12 @@ int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) const
bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{
if (!tx.IsCoinBase()) {
- // first check whether information about the prevout hash is available
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
- if (!HaveCoins(prevout.hash))
- return false;
- }
-
- // then check whether the actual outputs are available
- for (unsigned int i = 0; i < tx.vin.size(); i++) {
- const COutPoint &prevout = tx.vin[i].prevout;
- const CCoins &coins = GetCoins(prevout.hash);
- if (!coins.IsAvailable(prevout.n))
+ const CCoins* coins = AccessCoins(prevout.hash);
+ if (!coins || !coins->IsAvailable(prevout.n)) {
return false;
+ }
}
}
return true;
@@ -207,10 +204,11 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
double dResult = 0.0;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
- const CCoins &coins = GetCoins(txin.prevout.hash);
- if (!coins.IsAvailable(txin.prevout.n)) continue;
- if (coins.nHeight < nHeight) {
- dResult += coins.vout[txin.prevout.n].nValue * (nHeight-coins.nHeight);
+ const CCoins* coins = AccessCoins(txin.prevout.hash);
+ assert(coins);
+ if (!coins->IsAvailable(txin.prevout.n)) continue;
+ if (coins->nHeight < nHeight) {
+ dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
}
}
return tx.ComputePriority(dResult);
diff --git a/src/coins.h b/src/coins.h
index d338e3172e..c25393f1e0 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -344,11 +344,13 @@ public:
bool SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+ // Return a pointer to CCoins in the cache, or NULL if not found. This is
+ // more efficient than GetCoins. Modifications to other cache entries are
+ // allowed while accessing the returned pointer.
+ const CCoins* AccessCoins(const uint256 &txid) const;
+
// Return a modifiable reference to a CCoins. Check HaveCoins first.
- // Many methods explicitly require a CCoinsViewCache because of this method, to reduce
- // copying.
CCoins &GetCoins(const uint256 &txid);
- const CCoins &GetCoins(const uint256 &txid) const;
// Push the modifications applied to this cache to its base.
// Failure to call this method before destruction will cause the changes to be forgotten.
diff --git a/src/core.h b/src/core.h
index cde8d8b3fe..030eb17734 100644
--- a/src/core.h
+++ b/src/core.h
@@ -6,7 +6,8 @@
#ifndef BITCOIN_CORE_H
#define BITCOIN_CORE_H
-#include "script.h"
+#include "script/compressor.h"
+#include "script/script.h"
#include "serialize.h"
#include "uint256.h"
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 57f1397f18..efcecb106f 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -5,7 +5,7 @@
#include "core_io.h"
#include "core.h"
#include "serialize.h"
-#include "script.h"
+#include "script/script.h"
#include "util.h"
#include <boost/assign/list_of.hpp>
diff --git a/src/core_write.cpp b/src/core_write.cpp
index e66e75515c..62712b1ba0 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -4,7 +4,8 @@
#include "core_io.h"
#include "univalue/univalue.h"
-#include "script.h"
+#include "script/script.h"
+#include "script/standard.h"
#include "core.h"
#include "serialize.h"
#include "util.h"
diff --git a/src/crypter.cpp b/src/crypter.cpp
index 8aa2bb0517..3df13021df 100644
--- a/src/crypter.cpp
+++ b/src/crypter.cpp
@@ -4,7 +4,7 @@
#include "crypter.h"
-#include "script.h"
+#include "script/script.h"
#include "util.h"
#include <string>
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 72ae9b0a30..98bc0e9e28 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -7,7 +7,7 @@
#include "crypter.h"
#include "key.h"
-#include "script.h"
+#include "script/script.h"
#include "util.h"
#include <boost/foreach.hpp>
diff --git a/src/main.cpp b/src/main.cpp
index a3b31b719d..bbe5bd87fb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -492,16 +492,17 @@ bool AddOrphanTx(const CTransaction& tx)
void static EraseOrphanTx(uint256 hash)
{
- if (!mapOrphanTransactions.count(hash))
+ map<uint256, CTransaction>::iterator it = mapOrphanTransactions.find(hash);
+ if (it == mapOrphanTransactions.end())
return;
- const CTransaction& tx = mapOrphanTransactions[hash];
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ BOOST_FOREACH(const CTxIn& txin, it->second.vin)
{
- mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
- if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
- mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
+ map<uint256, set<uint256> >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash);
+ itPrev->second.erase(hash);
+ if (itPrev->second.empty())
+ mapOrphanTransactionsByPrev.erase(itPrev);
}
- mapOrphanTransactions.erase(hash);
+ mapOrphanTransactions.erase(it);
}
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
@@ -1017,9 +1018,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
int nHeight = -1;
{
CCoinsViewCache &view = *pcoinsTip;
- CCoins coins;
- if (view.GetCoins(hash, coins))
- nHeight = coins.nHeight;
+ const CCoins* coins = view.AccessCoins(hash);
+ if (coins)
+ nHeight = coins->nHeight;
}
if (nHeight > 0)
pindexSlow = chainActive[nHeight];
@@ -1371,19 +1372,20 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
const COutPoint &prevout = tx.vin[i].prevout;
- const CCoins &coins = inputs.GetCoins(prevout.hash);
+ const CCoins *coins = inputs.AccessCoins(prevout.hash);
+ assert(coins);
// If prev is coinbase, check that it's matured
- if (coins.IsCoinBase()) {
- if (nSpendHeight - coins.nHeight < COINBASE_MATURITY)
+ if (coins->IsCoinBase()) {
+ if (nSpendHeight - coins->nHeight < COINBASE_MATURITY)
return state.Invalid(
- error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight),
+ error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
}
// Check for negative or overflow input values
- nValueIn += coins.vout[prevout.n].nValue;
- if (!MoneyRange(coins.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
+ nValueIn += coins->vout[prevout.n].nValue;
+ if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return state.DoS(100, error("CheckInputs() : txin values out of range"),
REJECT_INVALID, "bad-txns-inputvalues-outofrange");
@@ -1413,10 +1415,11 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
if (fScriptChecks) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
- const CCoins &coins = inputs.GetCoins(prevout.hash);
+ const CCoins* coins = inputs.AccessCoins(prevout.hash);
+ assert(coins);
// Verify signature
- CScriptCheck check(coins, tx, i, flags, 0);
+ CScriptCheck check(*coins, tx, i, flags, 0);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -1428,7 +1431,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
- CScriptCheck check(coins, tx, i,
+ CScriptCheck check(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, 0);
if (check())
return state.Invalid(false, REJECT_NONSTANDARD, "non-mandatory-script-verify-flag");
@@ -1614,8 +1617,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) {
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
- const uint256& hash = tx.GetHash();
- if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
+ const CCoins* coins = view.AccessCoins(tx.GetHash());
+ if (coins && !coins->IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30");
}
@@ -3769,9 +3772,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Recursively process any orphan transactions that depended on this one
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
{
- uint256 hashPrev = vWorkQueue[i];
- for (set<uint256>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();
- mi != mapOrphanTransactionsByPrev[hashPrev].end();
+ map<uint256, set<uint256> >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]);
+ if (itByPrev == mapOrphanTransactionsByPrev.end())
+ continue;
+ for (set<uint256>::iterator mi = itByPrev->second.begin();
+ mi != itByPrev->second.end();
++mi)
{
const uint256& orphanHash = *mi;
@@ -4392,7 +4397,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (!pto->fDisconnect && state.nBlocksInFlight &&
state.nLastBlockReceive < state.nLastBlockProcess - BLOCK_DOWNLOAD_TIMEOUT*1000000 &&
state.vBlocksInFlight.front().nTime < state.nLastBlockProcess - 2*BLOCK_DOWNLOAD_TIMEOUT*1000000) {
- LogPrintf("Peer %s is stalling block download, disconnecting\n", state.name.c_str());
+ LogPrintf("Peer %s is stalling block download, disconnecting\n", state.name);
pto->fDisconnect = true;
}
@@ -4502,7 +4507,7 @@ bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock
}
std::string CBlockFileInfo::ToString() const {
- return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str());
+ return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
}
diff --git a/src/main.h b/src/main.h
index 8c0a743e24..30cccab2f1 100644
--- a/src/main.h
+++ b/src/main.h
@@ -15,7 +15,8 @@
#include "core.h"
#include "net.h"
#include "pow.h"
-#include "script.h"
+#include "script/script.h"
+#include "script/standard.h"
#include "sync.h"
#include "txmempool.h"
#include "uint256.h"
diff --git a/src/miner.cpp b/src/miner.cpp
index 96dc80a26d..d05ddbeb1f 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -167,12 +167,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
continue;
}
- const CCoins &coins = view.GetCoins(txin.prevout.hash);
+ const CCoins* coins = view.AccessCoins(txin.prevout.hash);
+ assert(coins);
- int64_t nValueIn = coins.vout[txin.prevout.n].nValue;
+ int64_t nValueIn = coins->vout[txin.prevout.n].nValue;
nTotalIn += nValueIn;
- int nConf = pindexPrev->nHeight - coins.nHeight + 1;
+ int nConf = pindexPrev->nHeight - coins->nHeight + 1;
dPriority += (double)nValueIn * nConf;
}
diff --git a/src/net.cpp b/src/net.cpp
index 2546826f9a..633a3a34e7 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2114,7 +2114,7 @@ void CNode::AskFor(const CInv& inv)
nRequestTime = it->second;
else
nRequestTime = 0;
- LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str(), id);
+ LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000), id);
// Make sure not to reuse time indexes to keep things in the same order
int64_t nNow = GetTimeMicros() - 1000000;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index d5821d4465..954c11f77d 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -259,7 +259,7 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
strSocks5 += strDest;
strSocks5 += static_cast<char>((port >> 8) & 0xFF);
strSocks5 += static_cast<char>((port >> 0) & 0xFF);
- ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL);
+ ret = send(hSocket, strSocks5.data(), strSocks5.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)strSocks5.size())
{
CloseSocket(hSocket);
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 7b30f8de09..d10463fd8f 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -705,7 +705,7 @@ void CoinControlDialog::updateView()
QString sAddress = "";
if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, outputAddress))
{
- sAddress = CBitcoinAddress(outputAddress).ToString().c_str();
+ sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString());
// if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
if (!treeMode || (!(sAddress == sWalletAddress)))
@@ -752,7 +752,7 @@ void CoinControlDialog::updateView()
// transaction hash
uint256 txhash = out.tx->GetHash();
- itemOutput->setText(COLUMN_TXHASH, txhash.GetHex().c_str());
+ itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex()));
// vout index
itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i));
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 8258e719a3..727b8dc66d 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -11,7 +11,7 @@
#include "db.h"
#include "main.h"
#include "paymentserver.h"
-#include "script.h"
+#include "script/script.h"
#include "transactionrecord.h"
#include "timedata.h"
#include "ui_interface.h"
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 92c22f5692..8d2c2e96d8 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -36,6 +36,7 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
{
fProcessingQueuedTransactions = false;
fHaveWatchOnly = wallet->HaveWatchOnly();
+ fForceCheckBalanceChanged = false;
addressTableModel = new AddressTableModel(wallet, this);
transactionTableModel = new TransactionTableModel(wallet, this);
@@ -121,8 +122,10 @@ void WalletModel::pollBalanceChanged()
if(!lockWallet)
return;
- if(chainActive.Height() != cachedNumBlocks)
+ if(fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks)
{
+ fForceCheckBalanceChanged = false;
+
// Balance and number of transactions might have changed
cachedNumBlocks = chainActive.Height();
@@ -167,7 +170,7 @@ void WalletModel::updateTransaction(const QString &hash, int status)
transactionTableModel->updateTransaction(hash, status);
// Balance and number of transactions might have changed
- checkBalanceChanged();
+ fForceCheckBalanceChanged = true;
}
void WalletModel::updateAddressBook(const QString &address, const QString &label,
@@ -344,6 +347,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
}
emit coinsSent(wallet, rcp, transaction_array);
}
+ checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
return SendCoinsReturn(OK);
}
@@ -473,11 +477,6 @@ static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet,
static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress)
{
- // emits signal "showProgress"
- QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection,
- Q_ARG(QString, QString::fromStdString(title)),
- Q_ARG(int, nProgress));
-
if (nProgress == 0)
fQueueNotifications = true;
@@ -495,6 +494,11 @@ static void ShowProgress(WalletModel *walletmodel, const std::string &title, int
}
std::vector<std::pair<uint256, ChangeType> >().swap(vQueueNotifications); // clear
}
+
+ // emits signal "showProgress"
+ QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection,
+ Q_ARG(QString, QString::fromStdString(title)),
+ Q_ARG(int, nProgress));
}
static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly)
@@ -618,7 +622,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
CTxDestination address;
if(!out.fSpendable || !ExtractDestination(cout.tx->vout[cout.i].scriptPubKey, address))
continue;
- mapCoins[CBitcoinAddress(address).ToString().c_str()].push_back(out);
+ mapCoins[QString::fromStdString(CBitcoinAddress(address).ToString())].push_back(out);
}
}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 00a011d937..111ae2178c 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -199,6 +199,7 @@ private:
CWallet *wallet;
bool fProcessingQueuedTransactions;
bool fHaveWatchOnly;
+ bool fForceCheckBalanceChanged;
// Wallet has an options model for wallet-specific options
// (transaction fee, for example)
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index bd992397b8..917c840536 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -74,8 +74,8 @@ Value getinfo(const Array& params, bool fHelp)
GetProxy(NET_IPV4, proxy);
Object obj;
- obj.push_back(Pair("version", (int)CLIENT_VERSION));
- obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
+ obj.push_back(Pair("version", CLIENT_VERSION));
+ obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index a73641834d..c5c99870fc 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -11,6 +11,9 @@
#include "main.h"
#include "net.h"
#include "rpcserver.h"
+#include "script/script.h"
+#include "script/standard.h"
+#include "script/sign.h"
#include "uint256.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
@@ -565,7 +568,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
const uint256& prevHash = txin.prevout.hash;
CCoins coins;
- view.GetCoins(prevHash, coins); // this is certainly allowed to fail
+ view.AccessCoins(prevHash); // this is certainly allowed to fail
}
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
@@ -669,12 +672,12 @@ Value signrawtransaction(const Array& params, bool fHelp)
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
- CCoins coins;
- if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n)) {
+ const CCoins* coins = view.AccessCoins(txin.prevout.hash);
+ if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) {
fComplete = false;
continue;
}
- const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
+ const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
txin.scriptSig.clear();
// Only sign SIGHASH_SINGLE if there's a corresponding output:
@@ -732,9 +735,9 @@ Value sendrawtransaction(const Array& params, bool fHelp)
fOverrideFees = params[1].get_bool();
CCoinsViewCache &view = *pcoinsTip;
- CCoins existingCoins;
+ const CCoins* existingCoins = view.AccessCoins(hashTx);
bool fHaveMempool = mempool.exists(hashTx);
- bool fHaveChain = view.GetCoins(hashTx, existingCoins) && existingCoins.nHeight < 1000000000;
+ bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
CValidationState state;
diff --git a/src/script/compressor.cpp b/src/script/compressor.cpp
new file mode 100644
index 0000000000..2f8df602bf
--- /dev/null
+++ b/src/script/compressor.cpp
@@ -0,0 +1,127 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "compressor.h"
+
+bool CScriptCompressor::IsToKeyID(CKeyID &hash) const
+{
+ if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160
+ && script[2] == 20 && script[23] == OP_EQUALVERIFY
+ && script[24] == OP_CHECKSIG) {
+ memcpy(&hash, &script[3], 20);
+ return true;
+ }
+ return false;
+}
+
+bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
+{
+ if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20
+ && script[22] == OP_EQUAL) {
+ memcpy(&hash, &script[2], 20);
+ return true;
+ }
+ return false;
+}
+
+bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
+{
+ if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
+ && (script[1] == 0x02 || script[1] == 0x03)) {
+ pubkey.Set(&script[1], &script[34]);
+ return true;
+ }
+ if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
+ && script[1] == 0x04) {
+ pubkey.Set(&script[1], &script[66]);
+ return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
+ }
+ return false;
+}
+
+bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
+{
+ CKeyID keyID;
+ if (IsToKeyID(keyID)) {
+ out.resize(21);
+ out[0] = 0x00;
+ memcpy(&out[1], &keyID, 20);
+ return true;
+ }
+ CScriptID scriptID;
+ if (IsToScriptID(scriptID)) {
+ out.resize(21);
+ out[0] = 0x01;
+ memcpy(&out[1], &scriptID, 20);
+ return true;
+ }
+ CPubKey pubkey;
+ if (IsToPubKey(pubkey)) {
+ out.resize(33);
+ memcpy(&out[1], &pubkey[1], 32);
+ if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
+ out[0] = pubkey[0];
+ return true;
+ } else if (pubkey[0] == 0x04) {
+ out[0] = 0x04 | (pubkey[64] & 0x01);
+ return true;
+ }
+ }
+ return false;
+}
+
+unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const
+{
+ if (nSize == 0 || nSize == 1)
+ return 20;
+ if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)
+ return 32;
+ return 0;
+}
+
+bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in)
+{
+ switch(nSize) {
+ case 0x00:
+ script.resize(25);
+ script[0] = OP_DUP;
+ script[1] = OP_HASH160;
+ script[2] = 20;
+ memcpy(&script[3], &in[0], 20);
+ script[23] = OP_EQUALVERIFY;
+ script[24] = OP_CHECKSIG;
+ return true;
+ case 0x01:
+ script.resize(23);
+ script[0] = OP_HASH160;
+ script[1] = 20;
+ memcpy(&script[2], &in[0], 20);
+ script[22] = OP_EQUAL;
+ return true;
+ case 0x02:
+ case 0x03:
+ script.resize(35);
+ script[0] = 33;
+ script[1] = nSize;
+ memcpy(&script[2], &in[0], 32);
+ script[34] = OP_CHECKSIG;
+ return true;
+ case 0x04:
+ case 0x05:
+ unsigned char vch[33] = {};
+ vch[0] = nSize - 2;
+ memcpy(&vch[1], &in[0], 32);
+ CPubKey pubkey(&vch[0], &vch[33]);
+ if (!pubkey.Decompress())
+ return false;
+ assert(pubkey.size() == 65);
+ script.resize(67);
+ script[0] = 65;
+ memcpy(&script[1], pubkey.begin(), 65);
+ script[66] = OP_CHECKSIG;
+ return true;
+ }
+ return false;
+}
diff --git a/src/script/compressor.h b/src/script/compressor.h
new file mode 100644
index 0000000000..f0a3754f02
--- /dev/null
+++ b/src/script/compressor.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_SCRIPT_COMPRESSOR
+#define H_BITCOIN_SCRIPT_COMPRESSOR
+
+#include "script/script.h"
+
+/** Compact serializer for scripts.
+ *
+ * It detects common cases and encodes them much more efficiently.
+ * 3 special cases are defined:
+ * * Pay to pubkey hash (encoded as 21 bytes)
+ * * Pay to script hash (encoded as 21 bytes)
+ * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes)
+ *
+ * Other scripts up to 121 bytes require 1 byte + script length. Above
+ * that, scripts up to 16505 bytes require 2 bytes + script length.
+ */
+class CScriptCompressor
+{
+private:
+ // make this static for now (there are only 6 special scripts defined)
+ // this can potentially be extended together with a new nVersion for
+ // transactions, in which case this value becomes dependent on nVersion
+ // and nHeight of the enclosing transaction.
+ static const unsigned int nSpecialScripts = 6;
+
+ CScript &script;
+protected:
+ // These check for scripts for which a special case with a shorter encoding is defined.
+ // They are implemented separately from the CScript test, as these test for exact byte
+ // sequence correspondences, and are more strict. For example, IsToPubKey also verifies
+ // whether the public key is valid (as invalid ones cannot be represented in compressed
+ // form).
+ bool IsToKeyID(CKeyID &hash) const;
+ bool IsToScriptID(CScriptID &hash) const;
+ bool IsToPubKey(CPubKey &pubkey) const;
+
+ bool Compress(std::vector<unsigned char> &out) const;
+ unsigned int GetSpecialSize(unsigned int nSize) const;
+ bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);
+public:
+ CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
+
+ unsigned int GetSerializeSize(int nType, int nVersion) const {
+ std::vector<unsigned char> compr;
+ if (Compress(compr))
+ return compr.size();
+ unsigned int nSize = script.size() + nSpecialScripts;
+ return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion);
+ }
+
+ template<typename Stream>
+ void Serialize(Stream &s, int nType, int nVersion) const {
+ std::vector<unsigned char> compr;
+ if (Compress(compr)) {
+ s << CFlatData(compr);
+ return;
+ }
+ unsigned int nSize = script.size() + nSpecialScripts;
+ s << VARINT(nSize);
+ s << CFlatData(script);
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream &s, int nType, int nVersion) {
+ unsigned int nSize = 0;
+ s >> VARINT(nSize);
+ if (nSize < nSpecialScripts) {
+ std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
+ s >> REF(CFlatData(vch));
+ Decompress(nSize, vch);
+ return;
+ }
+ nSize -= nSpecialScripts;
+ script.resize(nSize);
+ s >> REF(CFlatData(script));
+ }
+};
+
+#endif
diff --git a/src/script.cpp b/src/script/interpreter.cpp
index 06a0a5decf..4f4fdb6b7f 100644
--- a/src/script.cpp
+++ b/src/script/interpreter.cpp
@@ -3,27 +3,21 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script.h"
+#include "interpreter.h"
+#include "core.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha2.h"
-#include "core.h"
-#include "hash.h"
-#include "key.h"
-#include "keystore.h"
#include "random.h"
-#include "sync.h"
+#include "script/script.h"
#include "uint256.h"
#include "util.h"
-#include <boost/foreach.hpp>
#include <boost/thread.hpp>
-#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
using namespace std;
-using namespace boost;
typedef vector<unsigned char> valtype;
static const valtype vchFalse(0);
@@ -34,8 +28,6 @@ static const CScriptNum bnOne(1);
static const CScriptNum bnFalse(0);
static const CScriptNum bnTrue(1);
-bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
-
bool CastToBool(const valtype& vch)
{
for (unsigned int i = 0; i < vch.size(); i++)
@@ -51,8 +43,6 @@ bool CastToBool(const valtype& vch)
return false;
}
-
-
//
// Script is a stack machine (like Forth) that evaluates a predicate
// returning a bool indicating valid or not. There are no loops.
@@ -66,165 +56,6 @@ static inline void popstack(vector<valtype>& stack)
stack.pop_back();
}
-
-const char* GetTxnOutputType(txnouttype t)
-{
- switch (t)
- {
- case TX_NONSTANDARD: return "nonstandard";
- case TX_PUBKEY: return "pubkey";
- case TX_PUBKEYHASH: return "pubkeyhash";
- case TX_SCRIPTHASH: return "scripthash";
- case TX_MULTISIG: return "multisig";
- case TX_NULL_DATA: return "nulldata";
- }
- return NULL;
-}
-
-
-const char* GetOpName(opcodetype opcode)
-{
- switch (opcode)
- {
- // push value
- case OP_0 : return "0";
- case OP_PUSHDATA1 : return "OP_PUSHDATA1";
- case OP_PUSHDATA2 : return "OP_PUSHDATA2";
- case OP_PUSHDATA4 : return "OP_PUSHDATA4";
- case OP_1NEGATE : return "-1";
- case OP_RESERVED : return "OP_RESERVED";
- case OP_1 : return "1";
- case OP_2 : return "2";
- case OP_3 : return "3";
- case OP_4 : return "4";
- case OP_5 : return "5";
- case OP_6 : return "6";
- case OP_7 : return "7";
- case OP_8 : return "8";
- case OP_9 : return "9";
- case OP_10 : return "10";
- case OP_11 : return "11";
- case OP_12 : return "12";
- case OP_13 : return "13";
- case OP_14 : return "14";
- case OP_15 : return "15";
- case OP_16 : return "16";
-
- // control
- case OP_NOP : return "OP_NOP";
- case OP_VER : return "OP_VER";
- case OP_IF : return "OP_IF";
- case OP_NOTIF : return "OP_NOTIF";
- case OP_VERIF : return "OP_VERIF";
- case OP_VERNOTIF : return "OP_VERNOTIF";
- case OP_ELSE : return "OP_ELSE";
- case OP_ENDIF : return "OP_ENDIF";
- case OP_VERIFY : return "OP_VERIFY";
- case OP_RETURN : return "OP_RETURN";
-
- // stack ops
- case OP_TOALTSTACK : return "OP_TOALTSTACK";
- case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
- case OP_2DROP : return "OP_2DROP";
- case OP_2DUP : return "OP_2DUP";
- case OP_3DUP : return "OP_3DUP";
- case OP_2OVER : return "OP_2OVER";
- case OP_2ROT : return "OP_2ROT";
- case OP_2SWAP : return "OP_2SWAP";
- case OP_IFDUP : return "OP_IFDUP";
- case OP_DEPTH : return "OP_DEPTH";
- case OP_DROP : return "OP_DROP";
- case OP_DUP : return "OP_DUP";
- case OP_NIP : return "OP_NIP";
- case OP_OVER : return "OP_OVER";
- case OP_PICK : return "OP_PICK";
- case OP_ROLL : return "OP_ROLL";
- case OP_ROT : return "OP_ROT";
- case OP_SWAP : return "OP_SWAP";
- case OP_TUCK : return "OP_TUCK";
-
- // splice ops
- case OP_CAT : return "OP_CAT";
- case OP_SUBSTR : return "OP_SUBSTR";
- case OP_LEFT : return "OP_LEFT";
- case OP_RIGHT : return "OP_RIGHT";
- case OP_SIZE : return "OP_SIZE";
-
- // bit logic
- case OP_INVERT : return "OP_INVERT";
- case OP_AND : return "OP_AND";
- case OP_OR : return "OP_OR";
- case OP_XOR : return "OP_XOR";
- case OP_EQUAL : return "OP_EQUAL";
- case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
- case OP_RESERVED1 : return "OP_RESERVED1";
- case OP_RESERVED2 : return "OP_RESERVED2";
-
- // numeric
- case OP_1ADD : return "OP_1ADD";
- case OP_1SUB : return "OP_1SUB";
- case OP_2MUL : return "OP_2MUL";
- case OP_2DIV : return "OP_2DIV";
- case OP_NEGATE : return "OP_NEGATE";
- case OP_ABS : return "OP_ABS";
- case OP_NOT : return "OP_NOT";
- case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
- case OP_ADD : return "OP_ADD";
- case OP_SUB : return "OP_SUB";
- case OP_MUL : return "OP_MUL";
- case OP_DIV : return "OP_DIV";
- case OP_MOD : return "OP_MOD";
- case OP_LSHIFT : return "OP_LSHIFT";
- case OP_RSHIFT : return "OP_RSHIFT";
- case OP_BOOLAND : return "OP_BOOLAND";
- case OP_BOOLOR : return "OP_BOOLOR";
- case OP_NUMEQUAL : return "OP_NUMEQUAL";
- case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
- case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
- case OP_LESSTHAN : return "OP_LESSTHAN";
- case OP_GREATERTHAN : return "OP_GREATERTHAN";
- case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
- case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
- case OP_MIN : return "OP_MIN";
- case OP_MAX : return "OP_MAX";
- case OP_WITHIN : return "OP_WITHIN";
-
- // crypto
- case OP_RIPEMD160 : return "OP_RIPEMD160";
- case OP_SHA1 : return "OP_SHA1";
- case OP_SHA256 : return "OP_SHA256";
- case OP_HASH160 : return "OP_HASH160";
- case OP_HASH256 : return "OP_HASH256";
- case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
- case OP_CHECKSIG : return "OP_CHECKSIG";
- case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
- case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
- case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
-
- // expanson
- case OP_NOP1 : return "OP_NOP1";
- case OP_NOP2 : return "OP_NOP2";
- case OP_NOP3 : return "OP_NOP3";
- case OP_NOP4 : return "OP_NOP4";
- case OP_NOP5 : return "OP_NOP5";
- case OP_NOP6 : return "OP_NOP6";
- case OP_NOP7 : return "OP_NOP7";
- case OP_NOP8 : return "OP_NOP8";
- case OP_NOP9 : return "OP_NOP9";
- case OP_NOP10 : return "OP_NOP10";
-
- case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
-
- // Note:
- // The template matching params OP_SMALLDATA/etc are defined in opcodetype enum
- // as kind of implementation hack, they are *NOT* real opcodes. If found in real
- // Script, just let the default: case deal with them.
-
- default:
- return "OP_UNKNOWN";
- }
-}
-
bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
if (!(flags & SCRIPT_VERIFY_STRICTENC))
return true;
@@ -238,7 +69,7 @@ bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
if (vchPubKey.size() != 33)
return error("Non-canonical public key: invalid length for compressed key");
} else {
- return error("Non-canonical public key: compressed nor uncompressed");
+ return error("Non-canonical public key: neither compressed nor uncompressed");
}
return true;
}
@@ -962,19 +793,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
return false;
}
-
if (!vfExec.empty())
return false;
return true;
}
-
-
-
-
-
-
namespace {
/** Wrapper that serializes like CTransaction, but with the modifications
@@ -1151,8 +975,7 @@ public:
}
};
-bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode,
- const CTransaction& txTo, unsigned int nIn, int nHashType, int flags)
+bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags)
{
static CSignatureCache signatureCache;
@@ -1183,426 +1006,6 @@ bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char> &vchPubK
return true;
}
-
-
-
-
-
-
-
-
-//
-// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
-//
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
-{
- // Templates
- static multimap<txnouttype, CScript> mTemplates;
- if (mTemplates.empty())
- {
- // Standard tx, sender provides pubkey, receiver adds signature
- mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
-
- // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
- mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
-
- // Sender provides N pubkeys, receivers provides M signatures
- mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
-
- // Empty, provably prunable, data-carrying output
- if (GetBoolArg("-datacarrier", true))
- mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
- mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
- }
-
- // Shortcut for pay-to-script-hash, which are more constrained than the other types:
- // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
- if (scriptPubKey.IsPayToScriptHash())
- {
- typeRet = TX_SCRIPTHASH;
- vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
- vSolutionsRet.push_back(hashBytes);
- return true;
- }
-
- // Scan templates
- const CScript& script1 = scriptPubKey;
- BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
- {
- const CScript& script2 = tplate.second;
- vSolutionsRet.clear();
-
- opcodetype opcode1, opcode2;
- vector<unsigned char> vch1, vch2;
-
- // Compare
- CScript::const_iterator pc1 = script1.begin();
- CScript::const_iterator pc2 = script2.begin();
- while (true)
- {
- if (pc1 == script1.end() && pc2 == script2.end())
- {
- // Found a match
- typeRet = tplate.first;
- if (typeRet == TX_MULTISIG)
- {
- // Additional checks for TX_MULTISIG:
- unsigned char m = vSolutionsRet.front()[0];
- unsigned char n = vSolutionsRet.back()[0];
- if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
- return false;
- }
- return true;
- }
- if (!script1.GetOp(pc1, opcode1, vch1))
- break;
- if (!script2.GetOp(pc2, opcode2, vch2))
- break;
-
- // Template matching opcodes:
- if (opcode2 == OP_PUBKEYS)
- {
- while (vch1.size() >= 33 && vch1.size() <= 65)
- {
- vSolutionsRet.push_back(vch1);
- if (!script1.GetOp(pc1, opcode1, vch1))
- break;
- }
- if (!script2.GetOp(pc2, opcode2, vch2))
- break;
- // Normal situation is to fall through
- // to other if/else statements
- }
-
- if (opcode2 == OP_PUBKEY)
- {
- if (vch1.size() < 33 || vch1.size() > 65)
- break;
- vSolutionsRet.push_back(vch1);
- }
- else if (opcode2 == OP_PUBKEYHASH)
- {
- if (vch1.size() != sizeof(uint160))
- break;
- vSolutionsRet.push_back(vch1);
- }
- else if (opcode2 == OP_SMALLINTEGER)
- { // Single-byte small integer pushed onto vSolutions
- if (opcode1 == OP_0 ||
- (opcode1 >= OP_1 && opcode1 <= OP_16))
- {
- char n = (char)CScript::DecodeOP_N(opcode1);
- vSolutionsRet.push_back(valtype(1, n));
- }
- else
- break;
- }
- else if (opcode2 == OP_SMALLDATA)
- {
- // small pushdata, <= MAX_OP_RETURN_RELAY bytes
- if (vch1.size() > MAX_OP_RETURN_RELAY)
- break;
- }
- else if (opcode1 != opcode2 || vch1 != vch2)
- {
- // Others must match exactly
- break;
- }
- }
- }
-
- vSolutionsRet.clear();
- typeRet = TX_NONSTANDARD;
- return false;
-}
-
-
-bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
-{
- CKey key;
- if (!keystore.GetKey(address, key))
- return false;
-
- vector<unsigned char> vchSig;
- if (!key.Sign(hash, vchSig))
- return false;
- vchSig.push_back((unsigned char)nHashType);
- scriptSigRet << vchSig;
-
- return true;
-}
-
-bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
-{
- int nSigned = 0;
- int nRequired = multisigdata.front()[0];
- for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
- {
- const valtype& pubkey = multisigdata[i];
- CKeyID keyID = CPubKey(pubkey).GetID();
- if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
- ++nSigned;
- }
- return nSigned==nRequired;
-}
-
-//
-// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
-// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
-// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
-// Returns false if scriptPubKey could not be completely satisfied.
-//
-bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
- CScript& scriptSigRet, txnouttype& whichTypeRet)
-{
- scriptSigRet.clear();
-
- vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
- return false;
-
- CKeyID keyID;
- switch (whichTypeRet)
- {
- case TX_NONSTANDARD:
- case TX_NULL_DATA:
- return false;
- case TX_PUBKEY:
- keyID = CPubKey(vSolutions[0]).GetID();
- return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
- case TX_PUBKEYHASH:
- keyID = CKeyID(uint160(vSolutions[0]));
- if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
- return false;
- else
- {
- CPubKey vch;
- keystore.GetPubKey(keyID, vch);
- scriptSigRet << vch;
- }
- return true;
- case TX_SCRIPTHASH:
- return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
-
- case TX_MULTISIG:
- scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
- return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
- }
- return false;
-}
-
-int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
-{
- switch (t)
- {
- case TX_NONSTANDARD:
- case TX_NULL_DATA:
- return -1;
- case TX_PUBKEY:
- return 1;
- case TX_PUBKEYHASH:
- return 2;
- case TX_MULTISIG:
- if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
- return -1;
- return vSolutions[0][0] + 1;
- case TX_SCRIPTHASH:
- return 1; // doesn't include args needed by the script
- }
- return -1;
-}
-
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
-{
- vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
-
- if (whichType == TX_MULTISIG)
- {
- unsigned char m = vSolutions.front()[0];
- unsigned char n = vSolutions.back()[0];
- // Support up to x-of-3 multisig txns as standard
- if (n < 1 || n > 3)
- return false;
- if (m < 1 || m > n)
- return false;
- }
-
- return whichType != TX_NONSTANDARD;
-}
-
-
-unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
-{
- unsigned int nResult = 0;
- BOOST_FOREACH(const valtype& pubkey, pubkeys)
- {
- CKeyID keyID = CPubKey(pubkey).GetID();
- if (keystore.HaveKey(keyID))
- ++nResult;
- }
- return nResult;
-}
-
-isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
-{
- CScript script;
- script.SetDestination(dest);
- return IsMine(keystore, script);
-}
-
-isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
-{
- vector<valtype> vSolutions;
- txnouttype whichType;
- if (!Solver(scriptPubKey, whichType, vSolutions)) {
- if (keystore.HaveWatchOnly(scriptPubKey))
- return ISMINE_WATCH_ONLY;
- return ISMINE_NO;
- }
-
- CKeyID keyID;
- switch (whichType)
- {
- case TX_NONSTANDARD:
- case TX_NULL_DATA:
- break;
- case TX_PUBKEY:
- keyID = CPubKey(vSolutions[0]).GetID();
- if (keystore.HaveKey(keyID))
- return ISMINE_SPENDABLE;
- break;
- case TX_PUBKEYHASH:
- keyID = CKeyID(uint160(vSolutions[0]));
- if (keystore.HaveKey(keyID))
- return ISMINE_SPENDABLE;
- break;
- case TX_SCRIPTHASH:
- {
- CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
- CScript subscript;
- if (keystore.GetCScript(scriptID, subscript)) {
- isminetype ret = IsMine(keystore, subscript);
- if (ret == ISMINE_SPENDABLE)
- return ret;
- }
- break;
- }
- case TX_MULTISIG:
- {
- // Only consider transactions "mine" if we own ALL the
- // keys involved. multi-signature transactions that are
- // partially owned (somebody else has a key that can spend
- // them) enable spend-out-from-under-you attacks, especially
- // in shared-wallet situations.
- vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
- if (HaveKeys(keys, keystore) == keys.size())
- return ISMINE_SPENDABLE;
- break;
- }
- }
-
- if (keystore.HaveWatchOnly(scriptPubKey))
- return ISMINE_WATCH_ONLY;
- return ISMINE_NO;
-}
-
-bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
-{
- vector<valtype> vSolutions;
- txnouttype whichType;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
-
- if (whichType == TX_PUBKEY)
- {
- addressRet = CPubKey(vSolutions[0]).GetID();
- return true;
- }
- else if (whichType == TX_PUBKEYHASH)
- {
- addressRet = CKeyID(uint160(vSolutions[0]));
- return true;
- }
- else if (whichType == TX_SCRIPTHASH)
- {
- addressRet = CScriptID(uint160(vSolutions[0]));
- return true;
- }
- // Multisig txns have more than one address...
- return false;
-}
-
-bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
-{
- addressRet.clear();
- typeRet = TX_NONSTANDARD;
- vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, typeRet, vSolutions))
- return false;
- if (typeRet == TX_NULL_DATA){
- // This is data, not addresses
- return false;
- }
-
- if (typeRet == TX_MULTISIG)
- {
- nRequiredRet = vSolutions.front()[0];
- for (unsigned int i = 1; i < vSolutions.size()-1; i++)
- {
- CTxDestination address = CPubKey(vSolutions[i]).GetID();
- addressRet.push_back(address);
- }
- }
- else
- {
- nRequiredRet = 1;
- CTxDestination address;
- if (!ExtractDestination(scriptPubKey, address))
- return false;
- addressRet.push_back(address);
- }
-
- return true;
-}
-
-class CAffectedKeysVisitor : public boost::static_visitor<void> {
-private:
- const CKeyStore &keystore;
- std::vector<CKeyID> &vKeys;
-
-public:
- CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
-
- void Process(const CScript &script) {
- txnouttype type;
- std::vector<CTxDestination> vDest;
- int nRequired;
- if (ExtractDestinations(script, type, vDest, nRequired)) {
- BOOST_FOREACH(const CTxDestination &dest, vDest)
- boost::apply_visitor(*this, dest);
- }
- }
-
- void operator()(const CKeyID &keyId) {
- if (keystore.HaveKey(keyId))
- vKeys.push_back(keyId);
- }
-
- void operator()(const CScriptID &scriptId) {
- CScript script;
- if (keystore.GetCScript(scriptId, script))
- Process(script);
- }
-
- void operator()(const CNoDestination &none) {}
-};
-
-void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) {
- CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey);
-}
-
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
unsigned int flags, int nHashType)
{
@@ -1643,437 +1046,3 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
return true;
}
-
-
-bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
-{
- assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
-
- // Leave out the signature from the hash, since a signature can't sign itself.
- // The checksig op will also drop the signatures from its hash.
- uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
-
- txnouttype whichType;
- if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
- return false;
-
- if (whichType == TX_SCRIPTHASH)
- {
- // Solver returns the subscript that need to be evaluated;
- // the final scriptSig is the signatures from that
- // and then the serialized subscript:
- CScript subscript = txin.scriptSig;
-
- // Recompute txn hash using subscript in place of scriptPubKey:
- uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
-
- txnouttype subType;
- bool fSolved =
- Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
- // Append serialized subscript whether or not it is completely signed:
- txin.scriptSig << static_cast<valtype>(subscript);
- if (!fSolved) return false;
- }
-
- // Test solution
- return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
-}
-
-bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
-{
- assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
- assert(txin.prevout.n < txFrom.vout.size());
- const CTxOut& txout = txFrom.vout[txin.prevout.n];
-
- return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
-}
-
-static CScript PushAll(const vector<valtype>& values)
-{
- CScript result;
- BOOST_FOREACH(const valtype& v, values)
- result << v;
- return result;
-}
-
-static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
- const vector<valtype>& vSolutions,
- vector<valtype>& sigs1, vector<valtype>& sigs2)
-{
- // Combine all the signatures we've got:
- set<valtype> allsigs;
- BOOST_FOREACH(const valtype& v, sigs1)
- {
- if (!v.empty())
- allsigs.insert(v);
- }
- BOOST_FOREACH(const valtype& v, sigs2)
- {
- if (!v.empty())
- allsigs.insert(v);
- }
-
- // Build a map of pubkey -> signature by matching sigs to pubkeys:
- assert(vSolutions.size() > 1);
- unsigned int nSigsRequired = vSolutions.front()[0];
- unsigned int nPubKeys = vSolutions.size()-2;
- map<valtype, valtype> sigs;
- BOOST_FOREACH(const valtype& sig, allsigs)
- {
- for (unsigned int i = 0; i < nPubKeys; i++)
- {
- const valtype& pubkey = vSolutions[i+1];
- if (sigs.count(pubkey))
- continue; // Already got a sig for this pubkey
-
- if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0))
- {
- sigs[pubkey] = sig;
- break;
- }
- }
- }
- // Now build a merged CScript:
- unsigned int nSigsHave = 0;
- CScript result; result << OP_0; // pop-one-too-many workaround
- for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
- {
- if (sigs.count(vSolutions[i+1]))
- {
- result << sigs[vSolutions[i+1]];
- ++nSigsHave;
- }
- }
- // Fill any missing with OP_0:
- for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
- result << OP_0;
-
- return result;
-}
-
-static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- const txnouttype txType, const vector<valtype>& vSolutions,
- vector<valtype>& sigs1, vector<valtype>& sigs2)
-{
- switch (txType)
- {
- case TX_NONSTANDARD:
- case TX_NULL_DATA:
- // Don't know anything about this, assume bigger one is correct:
- if (sigs1.size() >= sigs2.size())
- return PushAll(sigs1);
- return PushAll(sigs2);
- case TX_PUBKEY:
- case TX_PUBKEYHASH:
- // Signatures are bigger than placeholders or empty scripts:
- if (sigs1.empty() || sigs1[0].empty())
- return PushAll(sigs2);
- return PushAll(sigs1);
- case TX_SCRIPTHASH:
- if (sigs1.empty() || sigs1.back().empty())
- return PushAll(sigs2);
- else if (sigs2.empty() || sigs2.back().empty())
- return PushAll(sigs1);
- else
- {
- // Recur to combine:
- valtype spk = sigs1.back();
- CScript pubKey2(spk.begin(), spk.end());
-
- txnouttype txType2;
- vector<vector<unsigned char> > vSolutions2;
- Solver(pubKey2, txType2, vSolutions2);
- sigs1.pop_back();
- sigs2.pop_back();
- CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
- result << spk;
- return result;
- }
- case TX_MULTISIG:
- return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
- }
-
- return CScript();
-}
-
-CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- const CScript& scriptSig1, const CScript& scriptSig2)
-{
- txnouttype txType;
- vector<vector<unsigned char> > vSolutions;
- Solver(scriptPubKey, txType, vSolutions);
-
- vector<valtype> stack1;
- EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
- vector<valtype> stack2;
- EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
-
- return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
-}
-
-unsigned int CScript::GetSigOpCount(bool fAccurate) const
-{
- unsigned int n = 0;
- const_iterator pc = begin();
- opcodetype lastOpcode = OP_INVALIDOPCODE;
- while (pc < end())
- {
- opcodetype opcode;
- if (!GetOp(pc, opcode))
- break;
- if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
- n++;
- else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
- {
- if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
- n += DecodeOP_N(lastOpcode);
- else
- n += 20;
- }
- lastOpcode = opcode;
- }
- return n;
-}
-
-unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
-{
- if (!IsPayToScriptHash())
- return GetSigOpCount(true);
-
- // This is a pay-to-script-hash scriptPubKey;
- // get the last item that the scriptSig
- // pushes onto the stack:
- const_iterator pc = scriptSig.begin();
- vector<unsigned char> data;
- while (pc < scriptSig.end())
- {
- opcodetype opcode;
- if (!scriptSig.GetOp(pc, opcode, data))
- return 0;
- if (opcode > OP_16)
- return 0;
- }
-
- /// ... and return its opcount:
- CScript subscript(data.begin(), data.end());
- return subscript.GetSigOpCount(true);
-}
-
-bool CScript::IsPayToScriptHash() const
-{
- // Extra-fast test for pay-to-script-hash CScripts:
- return (this->size() == 23 &&
- this->at(0) == OP_HASH160 &&
- this->at(1) == 0x14 &&
- this->at(22) == OP_EQUAL);
-}
-
-bool CScript::IsPushOnly() const
-{
- const_iterator pc = begin();
- while (pc < end())
- {
- // Note how a script with an invalid PUSHDATA returns False.
- opcodetype opcode;
- if (!GetOp(pc, opcode))
- return false;
-
- // Note that IsPushOnly() *does* consider OP_RESERVED to be a
- // push-type opcode, however execution of OP_RESERVED fails, so
- // it's not relevant to P2SH as the scriptSig would fail prior to
- // the P2SH special validation code being executed.
- if (opcode > OP_16)
- return false;
- }
- return true;
-}
-
-bool CScript::HasCanonicalPushes() const
-{
- const_iterator pc = begin();
- while (pc < end())
- {
- opcodetype opcode;
- std::vector<unsigned char> data;
- if (!GetOp(pc, opcode, data))
- return false;
- if (opcode > OP_16)
- continue;
- if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16))
- // Could have used an OP_n code, rather than a 1-byte push.
- return false;
- if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1)
- // Could have used a normal n-byte push, rather than OP_PUSHDATA1.
- return false;
- if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF)
- // Could have used an OP_PUSHDATA1.
- return false;
- if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF)
- // Could have used an OP_PUSHDATA2.
- return false;
- }
- return true;
-}
-
-class CScriptVisitor : public boost::static_visitor<bool>
-{
-private:
- CScript *script;
-public:
- CScriptVisitor(CScript *scriptin) { script = scriptin; }
-
- bool operator()(const CNoDestination &dest) const {
- script->clear();
- return false;
- }
-
- bool operator()(const CKeyID &keyID) const {
- script->clear();
- *script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG;
- return true;
- }
-
- bool operator()(const CScriptID &scriptID) const {
- script->clear();
- *script << OP_HASH160 << scriptID << OP_EQUAL;
- return true;
- }
-};
-
-void CScript::SetDestination(const CTxDestination& dest)
-{
- boost::apply_visitor(CScriptVisitor(this), dest);
-}
-
-void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
-{
- this->clear();
-
- *this << EncodeOP_N(nRequired);
- BOOST_FOREACH(const CPubKey& key, keys)
- *this << key;
- *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
-}
-
-bool CScriptCompressor::IsToKeyID(CKeyID &hash) const
-{
- if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160
- && script[2] == 20 && script[23] == OP_EQUALVERIFY
- && script[24] == OP_CHECKSIG) {
- memcpy(&hash, &script[3], 20);
- return true;
- }
- return false;
-}
-
-bool CScriptCompressor::IsToScriptID(CScriptID &hash) const
-{
- if (script.size() == 23 && script[0] == OP_HASH160 && script[1] == 20
- && script[22] == OP_EQUAL) {
- memcpy(&hash, &script[2], 20);
- return true;
- }
- return false;
-}
-
-bool CScriptCompressor::IsToPubKey(CPubKey &pubkey) const
-{
- if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG
- && (script[1] == 0x02 || script[1] == 0x03)) {
- pubkey.Set(&script[1], &script[34]);
- return true;
- }
- if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG
- && script[1] == 0x04) {
- pubkey.Set(&script[1], &script[66]);
- return pubkey.IsFullyValid(); // if not fully valid, a case that would not be compressible
- }
- return false;
-}
-
-bool CScriptCompressor::Compress(std::vector<unsigned char> &out) const
-{
- CKeyID keyID;
- if (IsToKeyID(keyID)) {
- out.resize(21);
- out[0] = 0x00;
- memcpy(&out[1], &keyID, 20);
- return true;
- }
- CScriptID scriptID;
- if (IsToScriptID(scriptID)) {
- out.resize(21);
- out[0] = 0x01;
- memcpy(&out[1], &scriptID, 20);
- return true;
- }
- CPubKey pubkey;
- if (IsToPubKey(pubkey)) {
- out.resize(33);
- memcpy(&out[1], &pubkey[1], 32);
- if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
- out[0] = pubkey[0];
- return true;
- } else if (pubkey[0] == 0x04) {
- out[0] = 0x04 | (pubkey[64] & 0x01);
- return true;
- }
- }
- return false;
-}
-
-unsigned int CScriptCompressor::GetSpecialSize(unsigned int nSize) const
-{
- if (nSize == 0 || nSize == 1)
- return 20;
- if (nSize == 2 || nSize == 3 || nSize == 4 || nSize == 5)
- return 32;
- return 0;
-}
-
-bool CScriptCompressor::Decompress(unsigned int nSize, const std::vector<unsigned char> &in)
-{
- switch(nSize) {
- case 0x00:
- script.resize(25);
- script[0] = OP_DUP;
- script[1] = OP_HASH160;
- script[2] = 20;
- memcpy(&script[3], &in[0], 20);
- script[23] = OP_EQUALVERIFY;
- script[24] = OP_CHECKSIG;
- return true;
- case 0x01:
- script.resize(23);
- script[0] = OP_HASH160;
- script[1] = 20;
- memcpy(&script[2], &in[0], 20);
- script[22] = OP_EQUAL;
- return true;
- case 0x02:
- case 0x03:
- script.resize(35);
- script[0] = 33;
- script[1] = nSize;
- memcpy(&script[2], &in[0], 32);
- script[34] = OP_CHECKSIG;
- return true;
- case 0x04:
- case 0x05:
- unsigned char vch[33] = {};
- vch[0] = nSize - 2;
- memcpy(&vch[1], &in[0], 32);
- CPubKey pubkey(&vch[0], &vch[33]);
- if (!pubkey.Decompress())
- return false;
- assert(pubkey.size() == 65);
- script.resize(67);
- script[0] = 65;
- memcpy(&script[1], pubkey.begin(), 65);
- script[66] = OP_CHECKSIG;
- return true;
- }
- return false;
-}
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
new file mode 100644
index 0000000000..0c6f8b9d13
--- /dev/null
+++ b/src/script/interpreter.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_SCRIPT_INTERPRETER
+#define H_BITCOIN_SCRIPT_INTERPRETER
+
+#include <vector>
+#include <stdint.h>
+#include <string>
+
+class uint256;
+class CScript;
+class CTransaction;
+
+/** Signature hash types/flags */
+enum
+{
+ SIGHASH_ALL = 1,
+ SIGHASH_NONE = 2,
+ SIGHASH_SINGLE = 3,
+ SIGHASH_ANYONECANPAY = 0x80,
+};
+
+/** Script verification flags */
+enum
+{
+ SCRIPT_VERIFY_NONE = 0,
+ SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
+ SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
+ SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC)
+ SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
+ SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
+};
+
+bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
+bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags);
+
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+bool CheckSig(std::vector<unsigned char> vchSig, const std::vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, int flags);
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
+
+#endif
diff --git a/src/script/script.cpp b/src/script/script.cpp
new file mode 100644
index 0000000000..60d1beac95
--- /dev/null
+++ b/src/script/script.cpp
@@ -0,0 +1,295 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "script.h"
+
+#include <boost/foreach.hpp>
+
+using namespace std;
+
+const char* GetOpName(opcodetype opcode)
+{
+ switch (opcode)
+ {
+ // push value
+ case OP_0 : return "0";
+ case OP_PUSHDATA1 : return "OP_PUSHDATA1";
+ case OP_PUSHDATA2 : return "OP_PUSHDATA2";
+ case OP_PUSHDATA4 : return "OP_PUSHDATA4";
+ case OP_1NEGATE : return "-1";
+ case OP_RESERVED : return "OP_RESERVED";
+ case OP_1 : return "1";
+ case OP_2 : return "2";
+ case OP_3 : return "3";
+ case OP_4 : return "4";
+ case OP_5 : return "5";
+ case OP_6 : return "6";
+ case OP_7 : return "7";
+ case OP_8 : return "8";
+ case OP_9 : return "9";
+ case OP_10 : return "10";
+ case OP_11 : return "11";
+ case OP_12 : return "12";
+ case OP_13 : return "13";
+ case OP_14 : return "14";
+ case OP_15 : return "15";
+ case OP_16 : return "16";
+
+ // control
+ case OP_NOP : return "OP_NOP";
+ case OP_VER : return "OP_VER";
+ case OP_IF : return "OP_IF";
+ case OP_NOTIF : return "OP_NOTIF";
+ case OP_VERIF : return "OP_VERIF";
+ case OP_VERNOTIF : return "OP_VERNOTIF";
+ case OP_ELSE : return "OP_ELSE";
+ case OP_ENDIF : return "OP_ENDIF";
+ case OP_VERIFY : return "OP_VERIFY";
+ case OP_RETURN : return "OP_RETURN";
+
+ // stack ops
+ case OP_TOALTSTACK : return "OP_TOALTSTACK";
+ case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
+ case OP_2DROP : return "OP_2DROP";
+ case OP_2DUP : return "OP_2DUP";
+ case OP_3DUP : return "OP_3DUP";
+ case OP_2OVER : return "OP_2OVER";
+ case OP_2ROT : return "OP_2ROT";
+ case OP_2SWAP : return "OP_2SWAP";
+ case OP_IFDUP : return "OP_IFDUP";
+ case OP_DEPTH : return "OP_DEPTH";
+ case OP_DROP : return "OP_DROP";
+ case OP_DUP : return "OP_DUP";
+ case OP_NIP : return "OP_NIP";
+ case OP_OVER : return "OP_OVER";
+ case OP_PICK : return "OP_PICK";
+ case OP_ROLL : return "OP_ROLL";
+ case OP_ROT : return "OP_ROT";
+ case OP_SWAP : return "OP_SWAP";
+ case OP_TUCK : return "OP_TUCK";
+
+ // splice ops
+ case OP_CAT : return "OP_CAT";
+ case OP_SUBSTR : return "OP_SUBSTR";
+ case OP_LEFT : return "OP_LEFT";
+ case OP_RIGHT : return "OP_RIGHT";
+ case OP_SIZE : return "OP_SIZE";
+
+ // bit logic
+ case OP_INVERT : return "OP_INVERT";
+ case OP_AND : return "OP_AND";
+ case OP_OR : return "OP_OR";
+ case OP_XOR : return "OP_XOR";
+ case OP_EQUAL : return "OP_EQUAL";
+ case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
+ case OP_RESERVED1 : return "OP_RESERVED1";
+ case OP_RESERVED2 : return "OP_RESERVED2";
+
+ // numeric
+ case OP_1ADD : return "OP_1ADD";
+ case OP_1SUB : return "OP_1SUB";
+ case OP_2MUL : return "OP_2MUL";
+ case OP_2DIV : return "OP_2DIV";
+ case OP_NEGATE : return "OP_NEGATE";
+ case OP_ABS : return "OP_ABS";
+ case OP_NOT : return "OP_NOT";
+ case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
+ case OP_ADD : return "OP_ADD";
+ case OP_SUB : return "OP_SUB";
+ case OP_MUL : return "OP_MUL";
+ case OP_DIV : return "OP_DIV";
+ case OP_MOD : return "OP_MOD";
+ case OP_LSHIFT : return "OP_LSHIFT";
+ case OP_RSHIFT : return "OP_RSHIFT";
+ case OP_BOOLAND : return "OP_BOOLAND";
+ case OP_BOOLOR : return "OP_BOOLOR";
+ case OP_NUMEQUAL : return "OP_NUMEQUAL";
+ case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
+ case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
+ case OP_LESSTHAN : return "OP_LESSTHAN";
+ case OP_GREATERTHAN : return "OP_GREATERTHAN";
+ case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
+ case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
+ case OP_MIN : return "OP_MIN";
+ case OP_MAX : return "OP_MAX";
+ case OP_WITHIN : return "OP_WITHIN";
+
+ // crypto
+ case OP_RIPEMD160 : return "OP_RIPEMD160";
+ case OP_SHA1 : return "OP_SHA1";
+ case OP_SHA256 : return "OP_SHA256";
+ case OP_HASH160 : return "OP_HASH160";
+ case OP_HASH256 : return "OP_HASH256";
+ case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
+ case OP_CHECKSIG : return "OP_CHECKSIG";
+ case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
+ case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
+ case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
+
+ // expanson
+ case OP_NOP1 : return "OP_NOP1";
+ case OP_NOP2 : return "OP_NOP2";
+ case OP_NOP3 : return "OP_NOP3";
+ case OP_NOP4 : return "OP_NOP4";
+ case OP_NOP5 : return "OP_NOP5";
+ case OP_NOP6 : return "OP_NOP6";
+ case OP_NOP7 : return "OP_NOP7";
+ case OP_NOP8 : return "OP_NOP8";
+ case OP_NOP9 : return "OP_NOP9";
+ case OP_NOP10 : return "OP_NOP10";
+
+ case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
+
+ // Note:
+ // The template matching params OP_SMALLDATA/etc are defined in opcodetype enum
+ // as kind of implementation hack, they are *NOT* real opcodes. If found in real
+ // Script, just let the default: case deal with them.
+
+ default:
+ return "OP_UNKNOWN";
+ }
+}
+
+unsigned int CScript::GetSigOpCount(bool fAccurate) const
+{
+ unsigned int n = 0;
+ const_iterator pc = begin();
+ opcodetype lastOpcode = OP_INVALIDOPCODE;
+ while (pc < end())
+ {
+ opcodetype opcode;
+ if (!GetOp(pc, opcode))
+ break;
+ if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
+ n++;
+ else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
+ {
+ if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
+ n += DecodeOP_N(lastOpcode);
+ else
+ n += 20;
+ }
+ lastOpcode = opcode;
+ }
+ return n;
+}
+
+unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
+{
+ if (!IsPayToScriptHash())
+ return GetSigOpCount(true);
+
+ // This is a pay-to-script-hash scriptPubKey;
+ // get the last item that the scriptSig
+ // pushes onto the stack:
+ const_iterator pc = scriptSig.begin();
+ vector<unsigned char> data;
+ while (pc < scriptSig.end())
+ {
+ opcodetype opcode;
+ if (!scriptSig.GetOp(pc, opcode, data))
+ return 0;
+ if (opcode > OP_16)
+ return 0;
+ }
+
+ /// ... and return its opcount:
+ CScript subscript(data.begin(), data.end());
+ return subscript.GetSigOpCount(true);
+}
+
+bool CScript::IsPayToScriptHash() const
+{
+ // Extra-fast test for pay-to-script-hash CScripts:
+ return (this->size() == 23 &&
+ this->at(0) == OP_HASH160 &&
+ this->at(1) == 0x14 &&
+ this->at(22) == OP_EQUAL);
+}
+
+bool CScript::IsPushOnly() const
+{
+ const_iterator pc = begin();
+ while (pc < end())
+ {
+ opcodetype opcode;
+ if (!GetOp(pc, opcode))
+ return false;
+ // Note that IsPushOnly() *does* consider OP_RESERVED to be a
+ // push-type opcode, however execution of OP_RESERVED fails, so
+ // it's not relevant to P2SH as the scriptSig would fail prior to
+ // the P2SH special validation code being executed.
+ if (opcode > OP_16)
+ return false;
+ }
+ return true;
+}
+
+bool CScript::HasCanonicalPushes() const
+{
+ const_iterator pc = begin();
+ while (pc < end())
+ {
+ opcodetype opcode;
+ std::vector<unsigned char> data;
+ if (!GetOp(pc, opcode, data))
+ return false;
+ if (opcode > OP_16)
+ continue;
+ if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16))
+ // Could have used an OP_n code, rather than a 1-byte push.
+ return false;
+ if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1)
+ // Could have used a normal n-byte push, rather than OP_PUSHDATA1.
+ return false;
+ if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF)
+ // Could have used an OP_PUSHDATA1.
+ return false;
+ if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF)
+ // Could have used an OP_PUSHDATA2.
+ return false;
+ }
+ return true;
+}
+
+class CScriptVisitor : public boost::static_visitor<bool>
+{
+private:
+ CScript *script;
+public:
+ CScriptVisitor(CScript *scriptin) { script = scriptin; }
+
+ bool operator()(const CNoDestination &dest) const {
+ script->clear();
+ return false;
+ }
+
+ bool operator()(const CKeyID &keyID) const {
+ script->clear();
+ *script << OP_DUP << OP_HASH160 << keyID << OP_EQUALVERIFY << OP_CHECKSIG;
+ return true;
+ }
+
+ bool operator()(const CScriptID &scriptID) const {
+ script->clear();
+ *script << OP_HASH160 << scriptID << OP_EQUAL;
+ return true;
+ }
+};
+
+void CScript::SetDestination(const CTxDestination& dest)
+{
+ boost::apply_visitor(CScriptVisitor(this), dest);
+}
+
+void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
+{
+ this->clear();
+
+ *this << EncodeOP_N(nRequired);
+ BOOST_FOREACH(const CPubKey& key, keys)
+ *this << key;
+ *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
+}
diff --git a/src/script.h b/src/script/script.h
index d17cfe3fa4..21847c09bd 100644
--- a/src/script.h
+++ b/src/script/script.h
@@ -7,22 +7,162 @@
#define H_BITCOIN_SCRIPT
#include "key.h"
-#include "utilstrencodings.h"
#include "tinyformat.h"
+#include "utilstrencodings.h"
#include <stdexcept>
-#include <stdint.h>
-#include <string>
-#include <vector>
#include <boost/variant.hpp>
-class CKeyStore;
-class CTransaction;
-struct CMutableTransaction;
-
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
-static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
+
+/** Script opcodes */
+enum opcodetype
+{
+ // push value
+ OP_0 = 0x00,
+ OP_FALSE = OP_0,
+ OP_PUSHDATA1 = 0x4c,
+ OP_PUSHDATA2 = 0x4d,
+ OP_PUSHDATA4 = 0x4e,
+ OP_1NEGATE = 0x4f,
+ OP_RESERVED = 0x50,
+ OP_1 = 0x51,
+ OP_TRUE=OP_1,
+ OP_2 = 0x52,
+ OP_3 = 0x53,
+ OP_4 = 0x54,
+ OP_5 = 0x55,
+ OP_6 = 0x56,
+ OP_7 = 0x57,
+ OP_8 = 0x58,
+ OP_9 = 0x59,
+ OP_10 = 0x5a,
+ OP_11 = 0x5b,
+ OP_12 = 0x5c,
+ OP_13 = 0x5d,
+ OP_14 = 0x5e,
+ OP_15 = 0x5f,
+ OP_16 = 0x60,
+
+ // control
+ OP_NOP = 0x61,
+ OP_VER = 0x62,
+ OP_IF = 0x63,
+ OP_NOTIF = 0x64,
+ OP_VERIF = 0x65,
+ OP_VERNOTIF = 0x66,
+ OP_ELSE = 0x67,
+ OP_ENDIF = 0x68,
+ OP_VERIFY = 0x69,
+ OP_RETURN = 0x6a,
+
+ // stack ops
+ OP_TOALTSTACK = 0x6b,
+ OP_FROMALTSTACK = 0x6c,
+ OP_2DROP = 0x6d,
+ OP_2DUP = 0x6e,
+ OP_3DUP = 0x6f,
+ OP_2OVER = 0x70,
+ OP_2ROT = 0x71,
+ OP_2SWAP = 0x72,
+ OP_IFDUP = 0x73,
+ OP_DEPTH = 0x74,
+ OP_DROP = 0x75,
+ OP_DUP = 0x76,
+ OP_NIP = 0x77,
+ OP_OVER = 0x78,
+ OP_PICK = 0x79,
+ OP_ROLL = 0x7a,
+ OP_ROT = 0x7b,
+ OP_SWAP = 0x7c,
+ OP_TUCK = 0x7d,
+
+ // splice ops
+ OP_CAT = 0x7e,
+ OP_SUBSTR = 0x7f,
+ OP_LEFT = 0x80,
+ OP_RIGHT = 0x81,
+ OP_SIZE = 0x82,
+
+ // bit logic
+ OP_INVERT = 0x83,
+ OP_AND = 0x84,
+ OP_OR = 0x85,
+ OP_XOR = 0x86,
+ OP_EQUAL = 0x87,
+ OP_EQUALVERIFY = 0x88,
+ OP_RESERVED1 = 0x89,
+ OP_RESERVED2 = 0x8a,
+
+ // numeric
+ OP_1ADD = 0x8b,
+ OP_1SUB = 0x8c,
+ OP_2MUL = 0x8d,
+ OP_2DIV = 0x8e,
+ OP_NEGATE = 0x8f,
+ OP_ABS = 0x90,
+ OP_NOT = 0x91,
+ OP_0NOTEQUAL = 0x92,
+
+ OP_ADD = 0x93,
+ OP_SUB = 0x94,
+ OP_MUL = 0x95,
+ OP_DIV = 0x96,
+ OP_MOD = 0x97,
+ OP_LSHIFT = 0x98,
+ OP_RSHIFT = 0x99,
+
+ OP_BOOLAND = 0x9a,
+ OP_BOOLOR = 0x9b,
+ OP_NUMEQUAL = 0x9c,
+ OP_NUMEQUALVERIFY = 0x9d,
+ OP_NUMNOTEQUAL = 0x9e,
+ OP_LESSTHAN = 0x9f,
+ OP_GREATERTHAN = 0xa0,
+ OP_LESSTHANOREQUAL = 0xa1,
+ OP_GREATERTHANOREQUAL = 0xa2,
+ OP_MIN = 0xa3,
+ OP_MAX = 0xa4,
+
+ OP_WITHIN = 0xa5,
+
+ // crypto
+ OP_RIPEMD160 = 0xa6,
+ OP_SHA1 = 0xa7,
+ OP_SHA256 = 0xa8,
+ OP_HASH160 = 0xa9,
+ OP_HASH256 = 0xaa,
+ OP_CODESEPARATOR = 0xab,
+ OP_CHECKSIG = 0xac,
+ OP_CHECKSIGVERIFY = 0xad,
+ OP_CHECKMULTISIG = 0xae,
+ OP_CHECKMULTISIGVERIFY = 0xaf,
+
+ // expansion
+ OP_NOP1 = 0xb0,
+ OP_NOP2 = 0xb1,
+ OP_NOP3 = 0xb2,
+ OP_NOP4 = 0xb3,
+ OP_NOP5 = 0xb4,
+ OP_NOP6 = 0xb5,
+ OP_NOP7 = 0xb6,
+ OP_NOP8 = 0xb7,
+ OP_NOP9 = 0xb8,
+ OP_NOP10 = 0xb9,
+
+
+ // template matching params
+ OP_SMALLDATA = 0xf9,
+ OP_SMALLINTEGER = 0xfa,
+ OP_PUBKEYS = 0xfb,
+ OP_PUBKEYHASH = 0xfd,
+ OP_PUBKEY = 0xfe,
+
+ OP_INVALIDOPCODE = 0xff,
+};
+
+const char* GetOpName(opcodetype opcode);
class scriptnum_error : public std::runtime_error
{
@@ -131,7 +271,6 @@ public:
absvalue >>= 8;
}
-
// - If the most significant byte is >= 0x80 and the value is positive, push a
// new zero-byte to make the significant byte < 0x80 again.
@@ -173,66 +312,13 @@ private:
int64_t m_value;
};
-/** Signature hash types/flags */
-enum
-{
- SIGHASH_ALL = 1,
- SIGHASH_NONE = 2,
- SIGHASH_SINGLE = 3,
- SIGHASH_ANYONECANPAY = 0x80,
-};
-
-/** Script verification flags */
-enum
-{
- SCRIPT_VERIFY_NONE = 0,
- SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
- SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
- SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC)
- SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
- SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
-};
-
-/** IsMine() return codes */
-enum isminetype
-{
- ISMINE_NO = 0,
- ISMINE_WATCH_ONLY = 1,
- ISMINE_SPENDABLE = 2,
- ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
-};
-/** used for bitflags of isminetype */
-typedef uint8_t isminefilter;
-
-// Mandatory script verification flags that all new blocks must comply with for
-// them to be valid. (but old blocks may not comply with) Currently just P2SH,
-// but in the future other flags may be added, such as a soft-fork to enforce
-// strict DER encoding.
-//
-// Failing one of these tests may trigger a DoS ban - see CheckInputs() for
-// details.
-static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
-
-// Standard script verification flags that standard transactions will comply
-// with. However scripts violating these flags may still be present in valid
-// blocks and we must accept those blocks.
-static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
- SCRIPT_VERIFY_STRICTENC |
- SCRIPT_VERIFY_NULLDUMMY;
-
-// For convenience, standard but not mandatory verify flags.
-static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
-
-enum txnouttype
+inline std::string ValueString(const std::vector<unsigned char>& vch)
{
- TX_NONSTANDARD,
- // 'standard' transaction types:
- TX_PUBKEY,
- TX_PUBKEYHASH,
- TX_SCRIPTHASH,
- TX_MULTISIG,
- TX_NULL_DATA,
-};
+ if (vch.size() <= 4)
+ return strprintf("%d", CScriptNum(vch).getint());
+ else
+ return HexStr(vch);
+}
class CNoDestination {
public:
@@ -248,167 +334,6 @@ public:
*/
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
-const char* GetTxnOutputType(txnouttype t);
-
-/** Script opcodes */
-enum opcodetype
-{
- // push value
- OP_0 = 0x00,
- OP_FALSE = OP_0,
- OP_PUSHDATA1 = 0x4c,
- OP_PUSHDATA2 = 0x4d,
- OP_PUSHDATA4 = 0x4e,
- OP_1NEGATE = 0x4f,
- OP_RESERVED = 0x50,
- OP_1 = 0x51,
- OP_TRUE=OP_1,
- OP_2 = 0x52,
- OP_3 = 0x53,
- OP_4 = 0x54,
- OP_5 = 0x55,
- OP_6 = 0x56,
- OP_7 = 0x57,
- OP_8 = 0x58,
- OP_9 = 0x59,
- OP_10 = 0x5a,
- OP_11 = 0x5b,
- OP_12 = 0x5c,
- OP_13 = 0x5d,
- OP_14 = 0x5e,
- OP_15 = 0x5f,
- OP_16 = 0x60,
-
- // control
- OP_NOP = 0x61,
- OP_VER = 0x62,
- OP_IF = 0x63,
- OP_NOTIF = 0x64,
- OP_VERIF = 0x65,
- OP_VERNOTIF = 0x66,
- OP_ELSE = 0x67,
- OP_ENDIF = 0x68,
- OP_VERIFY = 0x69,
- OP_RETURN = 0x6a,
-
- // stack ops
- OP_TOALTSTACK = 0x6b,
- OP_FROMALTSTACK = 0x6c,
- OP_2DROP = 0x6d,
- OP_2DUP = 0x6e,
- OP_3DUP = 0x6f,
- OP_2OVER = 0x70,
- OP_2ROT = 0x71,
- OP_2SWAP = 0x72,
- OP_IFDUP = 0x73,
- OP_DEPTH = 0x74,
- OP_DROP = 0x75,
- OP_DUP = 0x76,
- OP_NIP = 0x77,
- OP_OVER = 0x78,
- OP_PICK = 0x79,
- OP_ROLL = 0x7a,
- OP_ROT = 0x7b,
- OP_SWAP = 0x7c,
- OP_TUCK = 0x7d,
-
- // splice ops
- OP_CAT = 0x7e,
- OP_SUBSTR = 0x7f,
- OP_LEFT = 0x80,
- OP_RIGHT = 0x81,
- OP_SIZE = 0x82,
-
- // bit logic
- OP_INVERT = 0x83,
- OP_AND = 0x84,
- OP_OR = 0x85,
- OP_XOR = 0x86,
- OP_EQUAL = 0x87,
- OP_EQUALVERIFY = 0x88,
- OP_RESERVED1 = 0x89,
- OP_RESERVED2 = 0x8a,
-
- // numeric
- OP_1ADD = 0x8b,
- OP_1SUB = 0x8c,
- OP_2MUL = 0x8d,
- OP_2DIV = 0x8e,
- OP_NEGATE = 0x8f,
- OP_ABS = 0x90,
- OP_NOT = 0x91,
- OP_0NOTEQUAL = 0x92,
-
- OP_ADD = 0x93,
- OP_SUB = 0x94,
- OP_MUL = 0x95,
- OP_DIV = 0x96,
- OP_MOD = 0x97,
- OP_LSHIFT = 0x98,
- OP_RSHIFT = 0x99,
-
- OP_BOOLAND = 0x9a,
- OP_BOOLOR = 0x9b,
- OP_NUMEQUAL = 0x9c,
- OP_NUMEQUALVERIFY = 0x9d,
- OP_NUMNOTEQUAL = 0x9e,
- OP_LESSTHAN = 0x9f,
- OP_GREATERTHAN = 0xa0,
- OP_LESSTHANOREQUAL = 0xa1,
- OP_GREATERTHANOREQUAL = 0xa2,
- OP_MIN = 0xa3,
- OP_MAX = 0xa4,
-
- OP_WITHIN = 0xa5,
-
- // crypto
- OP_RIPEMD160 = 0xa6,
- OP_SHA1 = 0xa7,
- OP_SHA256 = 0xa8,
- OP_HASH160 = 0xa9,
- OP_HASH256 = 0xaa,
- OP_CODESEPARATOR = 0xab,
- OP_CHECKSIG = 0xac,
- OP_CHECKSIGVERIFY = 0xad,
- OP_CHECKMULTISIG = 0xae,
- OP_CHECKMULTISIGVERIFY = 0xaf,
-
- // expansion
- OP_NOP1 = 0xb0,
- OP_NOP2 = 0xb1,
- OP_NOP3 = 0xb2,
- OP_NOP4 = 0xb3,
- OP_NOP5 = 0xb4,
- OP_NOP6 = 0xb5,
- OP_NOP7 = 0xb6,
- OP_NOP8 = 0xb7,
- OP_NOP9 = 0xb8,
- OP_NOP10 = 0xb9,
-
-
-
- // template matching params
- OP_SMALLDATA = 0xf9,
- OP_SMALLINTEGER = 0xfa,
- OP_PUBKEYS = 0xfb,
- OP_PUBKEYHASH = 0xfd,
- OP_PUBKEY = 0xfe,
-
- OP_INVALIDOPCODE = 0xff,
-};
-
-const char* GetOpName(opcodetype opcode);
-
-
-
-inline std::string ValueString(const std::vector<unsigned char>& vch)
-{
- if (vch.size() <= 4)
- return strprintf("%d", CScriptNum(vch).getint());
- else
- return HexStr(vch);
-}
-
/** Serialized script, used inside transaction inputs and outputs */
class CScript : public std::vector<unsigned char>
{
@@ -446,7 +371,6 @@ public:
return ret;
}
-
CScript(int64_t b) { operator<<(b); }
explicit CScript(opcodetype b) { operator<<(b); }
@@ -718,98 +642,4 @@ public:
}
};
-/** Compact serializer for scripts.
- *
- * It detects common cases and encodes them much more efficiently.
- * 3 special cases are defined:
- * * Pay to pubkey hash (encoded as 21 bytes)
- * * Pay to script hash (encoded as 21 bytes)
- * * Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes)
- *
- * Other scripts up to 121 bytes require 1 byte + script length. Above
- * that, scripts up to 16505 bytes require 2 bytes + script length.
- */
-class CScriptCompressor
-{
-private:
- // make this static for now (there are only 6 special scripts defined)
- // this can potentially be extended together with a new nVersion for
- // transactions, in which case this value becomes dependent on nVersion
- // and nHeight of the enclosing transaction.
- static const unsigned int nSpecialScripts = 6;
-
- CScript &script;
-protected:
- // These check for scripts for which a special case with a shorter encoding is defined.
- // They are implemented separately from the CScript test, as these test for exact byte
- // sequence correspondences, and are more strict. For example, IsToPubKey also verifies
- // whether the public key is valid (as invalid ones cannot be represented in compressed
- // form).
- bool IsToKeyID(CKeyID &hash) const;
- bool IsToScriptID(CScriptID &hash) const;
- bool IsToPubKey(CPubKey &pubkey) const;
-
- bool Compress(std::vector<unsigned char> &out) const;
- unsigned int GetSpecialSize(unsigned int nSize) const;
- bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);
-public:
- CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
-
- unsigned int GetSerializeSize(int nType, int nVersion) const {
- std::vector<unsigned char> compr;
- if (Compress(compr))
- return compr.size();
- unsigned int nSize = script.size() + nSpecialScripts;
- return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion);
- }
-
- template<typename Stream>
- void Serialize(Stream &s, int nType, int nVersion) const {
- std::vector<unsigned char> compr;
- if (Compress(compr)) {
- s << CFlatData(compr);
- return;
- }
- unsigned int nSize = script.size() + nSpecialScripts;
- s << VARINT(nSize);
- s << CFlatData(script);
- }
-
- template<typename Stream>
- void Unserialize(Stream &s, int nType, int nVersion) {
- unsigned int nSize = 0;
- s >> VARINT(nSize);
- if (nSize < nSpecialScripts) {
- std::vector<unsigned char> vch(GetSpecialSize(nSize), 0x00);
- s >> REF(CFlatData(vch));
- Decompress(nSize, vch);
- return;
- }
- nSize -= nSpecialScripts;
- script.resize(nSize);
- s >> REF(CFlatData(script));
- }
-};
-
-bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
-bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags);
-
-bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
-int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
-isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
-void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
-bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
-bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
-bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
-bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
-bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
-
-// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
-// combine them intelligently and return the result.
-CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
-
-#endif // H_BITCOIN_SCRIPT
+#endif
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
new file mode 100644
index 0000000000..958177de3d
--- /dev/null
+++ b/src/script/sign.cpp
@@ -0,0 +1,260 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "script/sign.h"
+
+#include "core.h"
+#include "key.h"
+#include "keystore.h"
+#include "script/standard.h"
+#include "uint256.h"
+
+#include <boost/foreach.hpp>
+
+using namespace std;
+
+typedef vector<unsigned char> valtype;
+
+bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+{
+ CKey key;
+ if (!keystore.GetKey(address, key))
+ return false;
+
+ vector<unsigned char> vchSig;
+ if (!key.Sign(hash, vchSig))
+ return false;
+ vchSig.push_back((unsigned char)nHashType);
+ scriptSigRet << vchSig;
+
+ return true;
+}
+
+bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+{
+ int nSigned = 0;
+ int nRequired = multisigdata.front()[0];
+ for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
+ {
+ const valtype& pubkey = multisigdata[i];
+ CKeyID keyID = CPubKey(pubkey).GetID();
+ if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
+ ++nSigned;
+ }
+ return nSigned==nRequired;
+}
+
+//
+// Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
+// Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
+// unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
+// Returns false if scriptPubKey could not be completely satisfied.
+//
+bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
+ CScript& scriptSigRet, txnouttype& whichTypeRet)
+{
+ scriptSigRet.clear();
+
+ vector<valtype> vSolutions;
+ if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
+ return false;
+
+ CKeyID keyID;
+ switch (whichTypeRet)
+ {
+ case TX_NONSTANDARD:
+ case TX_NULL_DATA:
+ return false;
+ case TX_PUBKEY:
+ keyID = CPubKey(vSolutions[0]).GetID();
+ return Sign1(keyID, keystore, hash, nHashType, scriptSigRet);
+ case TX_PUBKEYHASH:
+ keyID = CKeyID(uint160(vSolutions[0]));
+ if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
+ return false;
+ else
+ {
+ CPubKey vch;
+ keystore.GetPubKey(keyID, vch);
+ scriptSigRet << vch;
+ }
+ return true;
+ case TX_SCRIPTHASH:
+ return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
+
+ case TX_MULTISIG:
+ scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
+ return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
+ }
+ return false;
+}
+
+bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ assert(nIn < txTo.vin.size());
+ CTxIn& txin = txTo.vin[nIn];
+
+ // Leave out the signature from the hash, since a signature can't sign itself.
+ // The checksig op will also drop the signatures from its hash.
+ uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
+
+ txnouttype whichType;
+ if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
+ return false;
+
+ if (whichType == TX_SCRIPTHASH)
+ {
+ // Solver returns the subscript that need to be evaluated;
+ // the final scriptSig is the signatures from that
+ // and then the serialized subscript:
+ CScript subscript = txin.scriptSig;
+
+ // Recompute txn hash using subscript in place of scriptPubKey:
+ uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
+
+ txnouttype subType;
+ bool fSolved =
+ Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
+ // Append serialized subscript whether or not it is completely signed:
+ txin.scriptSig << static_cast<valtype>(subscript);
+ if (!fSolved) return false;
+ }
+
+ // Test solution
+ return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS, 0);
+}
+
+bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ assert(nIn < txTo.vin.size());
+ CTxIn& txin = txTo.vin[nIn];
+ assert(txin.prevout.n < txFrom.vout.size());
+ const CTxOut& txout = txFrom.vout[txin.prevout.n];
+
+ return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
+}
+
+static CScript PushAll(const vector<valtype>& values)
+{
+ CScript result;
+ BOOST_FOREACH(const valtype& v, values)
+ result << v;
+ return result;
+}
+
+static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& txTo, unsigned int nIn,
+ const vector<valtype>& vSolutions,
+ vector<valtype>& sigs1, vector<valtype>& sigs2)
+{
+ // Combine all the signatures we've got:
+ set<valtype> allsigs;
+ BOOST_FOREACH(const valtype& v, sigs1)
+ {
+ if (!v.empty())
+ allsigs.insert(v);
+ }
+ BOOST_FOREACH(const valtype& v, sigs2)
+ {
+ if (!v.empty())
+ allsigs.insert(v);
+ }
+
+ // Build a map of pubkey -> signature by matching sigs to pubkeys:
+ assert(vSolutions.size() > 1);
+ unsigned int nSigsRequired = vSolutions.front()[0];
+ unsigned int nPubKeys = vSolutions.size()-2;
+ map<valtype, valtype> sigs;
+ BOOST_FOREACH(const valtype& sig, allsigs)
+ {
+ for (unsigned int i = 0; i < nPubKeys; i++)
+ {
+ const valtype& pubkey = vSolutions[i+1];
+ if (sigs.count(pubkey))
+ continue; // Already got a sig for this pubkey
+
+ if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0, 0))
+ {
+ sigs[pubkey] = sig;
+ break;
+ }
+ }
+ }
+ // Now build a merged CScript:
+ unsigned int nSigsHave = 0;
+ CScript result; result << OP_0; // pop-one-too-many workaround
+ for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
+ {
+ if (sigs.count(vSolutions[i+1]))
+ {
+ result << sigs[vSolutions[i+1]];
+ ++nSigsHave;
+ }
+ }
+ // Fill any missing with OP_0:
+ for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
+ result << OP_0;
+
+ return result;
+}
+
+static CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+ const txnouttype txType, const vector<valtype>& vSolutions,
+ vector<valtype>& sigs1, vector<valtype>& sigs2)
+{
+ switch (txType)
+ {
+ case TX_NONSTANDARD:
+ case TX_NULL_DATA:
+ // Don't know anything about this, assume bigger one is correct:
+ if (sigs1.size() >= sigs2.size())
+ return PushAll(sigs1);
+ return PushAll(sigs2);
+ case TX_PUBKEY:
+ case TX_PUBKEYHASH:
+ // Signatures are bigger than placeholders or empty scripts:
+ if (sigs1.empty() || sigs1[0].empty())
+ return PushAll(sigs2);
+ return PushAll(sigs1);
+ case TX_SCRIPTHASH:
+ if (sigs1.empty() || sigs1.back().empty())
+ return PushAll(sigs2);
+ else if (sigs2.empty() || sigs2.back().empty())
+ return PushAll(sigs1);
+ else
+ {
+ // Recur to combine:
+ valtype spk = sigs1.back();
+ CScript pubKey2(spk.begin(), spk.end());
+
+ txnouttype txType2;
+ vector<vector<unsigned char> > vSolutions2;
+ Solver(pubKey2, txType2, vSolutions2);
+ sigs1.pop_back();
+ sigs2.pop_back();
+ CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
+ result << spk;
+ return result;
+ }
+ case TX_MULTISIG:
+ return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
+ }
+
+ return CScript();
+}
+
+CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+ const CScript& scriptSig1, const CScript& scriptSig2)
+{
+ txnouttype txType;
+ vector<vector<unsigned char> > vSolutions;
+ Solver(scriptPubKey, txType, vSolutions);
+
+ vector<valtype> stack1;
+ EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
+ vector<valtype> stack2;
+ EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
+
+ return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
+}
diff --git a/src/script/sign.h b/src/script/sign.h
new file mode 100644
index 0000000000..51723b53af
--- /dev/null
+++ b/src/script/sign.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_SCRIPT_SIGN
+#define H_BITCOIN_SCRIPT_SIGN
+
+#include "script/interpreter.h"
+
+class CKeyStore;
+class CScript;
+class CTransaction;
+struct CMutableTransaction;
+
+bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
+bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
+
+// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
+// combine them intelligently and return the result.
+CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
+
+#endif
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
new file mode 100644
index 0000000000..684edff4d2
--- /dev/null
+++ b/src/script/standard.cpp
@@ -0,0 +1,254 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "script/standard.h"
+
+#include "script/script.h"
+#include "util.h"
+
+#include <boost/foreach.hpp>
+
+using namespace std;
+
+typedef vector<unsigned char> valtype;
+
+const char* GetTxnOutputType(txnouttype t)
+{
+ switch (t)
+ {
+ case TX_NONSTANDARD: return "nonstandard";
+ case TX_PUBKEY: return "pubkey";
+ case TX_PUBKEYHASH: return "pubkeyhash";
+ case TX_SCRIPTHASH: return "scripthash";
+ case TX_MULTISIG: return "multisig";
+ case TX_NULL_DATA: return "nulldata";
+ }
+ return NULL;
+}
+
+//
+// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
+//
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
+{
+ // Templates
+ static multimap<txnouttype, CScript> mTemplates;
+ if (mTemplates.empty())
+ {
+ // Standard tx, sender provides pubkey, receiver adds signature
+ mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
+
+ // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
+ mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
+
+ // Sender provides N pubkeys, receivers provides M signatures
+ mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+
+ // Empty, provably prunable, data-carrying output
+ if (GetBoolArg("-datacarrier", true))
+ mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
+ mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
+ }
+
+ // Shortcut for pay-to-script-hash, which are more constrained than the other types:
+ // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
+ if (scriptPubKey.IsPayToScriptHash())
+ {
+ typeRet = TX_SCRIPTHASH;
+ vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
+ vSolutionsRet.push_back(hashBytes);
+ return true;
+ }
+
+ // Scan templates
+ const CScript& script1 = scriptPubKey;
+ BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
+ {
+ const CScript& script2 = tplate.second;
+ vSolutionsRet.clear();
+
+ opcodetype opcode1, opcode2;
+ vector<unsigned char> vch1, vch2;
+
+ // Compare
+ CScript::const_iterator pc1 = script1.begin();
+ CScript::const_iterator pc2 = script2.begin();
+ while (true)
+ {
+ if (pc1 == script1.end() && pc2 == script2.end())
+ {
+ // Found a match
+ typeRet = tplate.first;
+ if (typeRet == TX_MULTISIG)
+ {
+ // Additional checks for TX_MULTISIG:
+ unsigned char m = vSolutionsRet.front()[0];
+ unsigned char n = vSolutionsRet.back()[0];
+ if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
+ return false;
+ }
+ return true;
+ }
+ if (!script1.GetOp(pc1, opcode1, vch1))
+ break;
+ if (!script2.GetOp(pc2, opcode2, vch2))
+ break;
+
+ // Template matching opcodes:
+ if (opcode2 == OP_PUBKEYS)
+ {
+ while (vch1.size() >= 33 && vch1.size() <= 65)
+ {
+ vSolutionsRet.push_back(vch1);
+ if (!script1.GetOp(pc1, opcode1, vch1))
+ break;
+ }
+ if (!script2.GetOp(pc2, opcode2, vch2))
+ break;
+ // Normal situation is to fall through
+ // to other if/else statements
+ }
+
+ if (opcode2 == OP_PUBKEY)
+ {
+ if (vch1.size() < 33 || vch1.size() > 65)
+ break;
+ vSolutionsRet.push_back(vch1);
+ }
+ else if (opcode2 == OP_PUBKEYHASH)
+ {
+ if (vch1.size() != sizeof(uint160))
+ break;
+ vSolutionsRet.push_back(vch1);
+ }
+ else if (opcode2 == OP_SMALLINTEGER)
+ { // Single-byte small integer pushed onto vSolutions
+ if (opcode1 == OP_0 ||
+ (opcode1 >= OP_1 && opcode1 <= OP_16))
+ {
+ char n = (char)CScript::DecodeOP_N(opcode1);
+ vSolutionsRet.push_back(valtype(1, n));
+ }
+ else
+ break;
+ }
+ else if (opcode2 == OP_SMALLDATA)
+ {
+ // small pushdata, <= MAX_OP_RETURN_RELAY bytes
+ if (vch1.size() > MAX_OP_RETURN_RELAY)
+ break;
+ }
+ else if (opcode1 != opcode2 || vch1 != vch2)
+ {
+ // Others must match exactly
+ break;
+ }
+ }
+ }
+
+ vSolutionsRet.clear();
+ typeRet = TX_NONSTANDARD;
+ return false;
+}
+
+int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
+{
+ switch (t)
+ {
+ case TX_NONSTANDARD:
+ case TX_NULL_DATA:
+ return -1;
+ case TX_PUBKEY:
+ return 1;
+ case TX_PUBKEYHASH:
+ return 2;
+ case TX_MULTISIG:
+ if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
+ return -1;
+ return vSolutions[0][0] + 1;
+ case TX_SCRIPTHASH:
+ return 1; // doesn't include args needed by the script
+ }
+ return -1;
+}
+
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
+{
+ vector<valtype> vSolutions;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
+ return false;
+
+ if (whichType == TX_MULTISIG)
+ {
+ unsigned char m = vSolutions.front()[0];
+ unsigned char n = vSolutions.back()[0];
+ // Support up to x-of-3 multisig txns as standard
+ if (n < 1 || n > 3)
+ return false;
+ if (m < 1 || m > n)
+ return false;
+ }
+
+ return whichType != TX_NONSTANDARD;
+}
+
+bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
+{
+ vector<valtype> vSolutions;
+ txnouttype whichType;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
+ return false;
+
+ if (whichType == TX_PUBKEY)
+ {
+ addressRet = CPubKey(vSolutions[0]).GetID();
+ return true;
+ }
+ else if (whichType == TX_PUBKEYHASH)
+ {
+ addressRet = CKeyID(uint160(vSolutions[0]));
+ return true;
+ }
+ else if (whichType == TX_SCRIPTHASH)
+ {
+ addressRet = CScriptID(uint160(vSolutions[0]));
+ return true;
+ }
+ // Multisig txns have more than one address...
+ return false;
+}
+
+bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
+{
+ addressRet.clear();
+ typeRet = TX_NONSTANDARD;
+ vector<valtype> vSolutions;
+ if (!Solver(scriptPubKey, typeRet, vSolutions))
+ return false;
+ if (typeRet == TX_NULL_DATA){
+ // This is data, not addresses
+ return false;
+ }
+
+ if (typeRet == TX_MULTISIG)
+ {
+ nRequiredRet = vSolutions.front()[0];
+ for (unsigned int i = 1; i < vSolutions.size()-1; i++)
+ {
+ CTxDestination address = CPubKey(vSolutions[i]).GetID();
+ addressRet.push_back(address);
+ }
+ }
+ else
+ {
+ nRequiredRet = 1;
+ CTxDestination address;
+ if (!ExtractDestination(scriptPubKey, address))
+ return false;
+ addressRet.push_back(address);
+ }
+
+ return true;
+}
diff --git a/src/script/standard.h b/src/script/standard.h
new file mode 100644
index 0000000000..18092e879e
--- /dev/null
+++ b/src/script/standard.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_SCRIPT_STANDARD
+#define H_BITCOIN_SCRIPT_STANDARD
+
+#include "script/script.h"
+#include "script/interpreter.h"
+
+#include <stdint.h>
+
+class CScript;
+
+static const unsigned int MAX_OP_RETURN_RELAY = 40; // bytes
+
+// Mandatory script verification flags that all new blocks must comply with for
+// them to be valid. (but old blocks may not comply with) Currently just P2SH,
+// but in the future other flags may be added, such as a soft-fork to enforce
+// strict DER encoding.
+//
+// Failing one of these tests may trigger a DoS ban - see CheckInputs() for
+// details.
+static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
+
+// Standard script verification flags that standard transactions will comply
+// with. However scripts violating these flags may still be present in valid
+// blocks and we must accept those blocks.
+static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
+ SCRIPT_VERIFY_STRICTENC |
+ SCRIPT_VERIFY_NULLDUMMY;
+
+// For convenience, standard but not mandatory verify flags.
+static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
+
+enum txnouttype
+{
+ TX_NONSTANDARD,
+ // 'standard' transaction types:
+ TX_PUBKEY,
+ TX_PUBKEYHASH,
+ TX_SCRIPTHASH,
+ TX_MULTISIG,
+ TX_NULL_DATA,
+};
+
+const char* GetTxnOutputType(txnouttype t);
+
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
+bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
+bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
+
+#endif
diff --git a/src/scriptutils.cpp b/src/scriptutils.cpp
new file mode 100644
index 0000000000..a636eeedab
--- /dev/null
+++ b/src/scriptutils.cpp
@@ -0,0 +1,127 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "scriptutils.h"
+
+#include "key.h"
+#include "keystore.h"
+#include "script/standard.h"
+
+#include <boost/foreach.hpp>
+
+using namespace std;
+
+typedef vector<unsigned char> valtype;
+
+unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
+{
+ unsigned int nResult = 0;
+ BOOST_FOREACH(const valtype& pubkey, pubkeys)
+ {
+ CKeyID keyID = CPubKey(pubkey).GetID();
+ if (keystore.HaveKey(keyID))
+ ++nResult;
+ }
+ return nResult;
+}
+
+isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
+{
+ CScript script;
+ script.SetDestination(dest);
+ return IsMine(keystore, script);
+}
+
+isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
+{
+ vector<valtype> vSolutions;
+ txnouttype whichType;
+ if (!Solver(scriptPubKey, whichType, vSolutions)) {
+ if (keystore.HaveWatchOnly(scriptPubKey))
+ return ISMINE_WATCH_ONLY;
+ return ISMINE_NO;
+ }
+
+ CKeyID keyID;
+ switch (whichType)
+ {
+ case TX_NONSTANDARD:
+ case TX_NULL_DATA:
+ break;
+ case TX_PUBKEY:
+ keyID = CPubKey(vSolutions[0]).GetID();
+ if (keystore.HaveKey(keyID))
+ return ISMINE_SPENDABLE;
+ break;
+ case TX_PUBKEYHASH:
+ keyID = CKeyID(uint160(vSolutions[0]));
+ if (keystore.HaveKey(keyID))
+ return ISMINE_SPENDABLE;
+ break;
+ case TX_SCRIPTHASH:
+ {
+ CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
+ CScript subscript;
+ if (keystore.GetCScript(scriptID, subscript)) {
+ isminetype ret = IsMine(keystore, subscript);
+ if (ret == ISMINE_SPENDABLE)
+ return ret;
+ }
+ break;
+ }
+ case TX_MULTISIG:
+ {
+ // Only consider transactions "mine" if we own ALL the
+ // keys involved. multi-signature transactions that are
+ // partially owned (somebody else has a key that can spend
+ // them) enable spend-out-from-under-you attacks, especially
+ // in shared-wallet situations.
+ vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
+ if (HaveKeys(keys, keystore) == keys.size())
+ return ISMINE_SPENDABLE;
+ break;
+ }
+ }
+
+ if (keystore.HaveWatchOnly(scriptPubKey))
+ return ISMINE_WATCH_ONLY;
+ return ISMINE_NO;
+}
+
+class CAffectedKeysVisitor : public boost::static_visitor<void> {
+private:
+ const CKeyStore &keystore;
+ std::vector<CKeyID> &vKeys;
+
+public:
+ CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
+
+ void Process(const CScript &script) {
+ txnouttype type;
+ std::vector<CTxDestination> vDest;
+ int nRequired;
+ if (ExtractDestinations(script, type, vDest, nRequired)) {
+ BOOST_FOREACH(const CTxDestination &dest, vDest)
+ boost::apply_visitor(*this, dest);
+ }
+ }
+
+ void operator()(const CKeyID &keyId) {
+ if (keystore.HaveKey(keyId))
+ vKeys.push_back(keyId);
+ }
+
+ void operator()(const CScriptID &scriptId) {
+ CScript script;
+ if (keystore.GetCScript(scriptId, script))
+ Process(script);
+ }
+
+ void operator()(const CNoDestination &none) {}
+};
+
+void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) {
+ CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey);
+}
diff --git a/src/scriptutils.h b/src/scriptutils.h
new file mode 100644
index 0000000000..98080fc456
--- /dev/null
+++ b/src/scriptutils.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2013 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef H_BITCOIN_SCRIPTUTILS
+#define H_BITCOIN_SCRIPTUTILS
+
+#include "key.h"
+#include "script/script.h"
+
+class CKeyStore;
+
+/** IsMine() return codes */
+enum isminetype
+{
+ ISMINE_NO = 0,
+ ISMINE_WATCH_ONLY = 1,
+ ISMINE_SPENDABLE = 2,
+ ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
+};
+/** used for bitflags of isminetype */
+typedef uint8_t isminefilter;
+
+isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
+void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
+
+#endif // H_BITCOIN_SCRIPT
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 8fa38c3605..fa4edff63f 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -12,7 +12,7 @@
#include "main.h"
#include "net.h"
#include "pow.h"
-#include "script.h"
+#include "script/sign.h"
#include "serialize.h"
#include "util.h"
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 0ac3e9a363..fe68e9e974 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -9,7 +9,7 @@
#include "data/base58_keys_valid.json.h"
#include "key.h"
-#include "script.h"
+#include "script/script.h"
#include "uint256.h"
#include "util.h"
diff --git a/src/test/canonical_tests.cpp b/src/test/canonical_tests.cpp
index a9798623ea..a17099de72 100644
--- a/src/test/canonical_tests.cpp
+++ b/src/test/canonical_tests.cpp
@@ -8,9 +8,11 @@
#include "data/sig_noncanonical.json.h"
#include "data/sig_canonical.json.h"
+#include "key.h"
#include "random.h"
-#include "script.h"
+#include "script/interpreter.h"
#include "util.h"
+#include "utilstrencodings.h"
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 864d90128c..203c20731a 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -5,7 +5,7 @@
#include "key.h"
#include "base58.h"
-#include "script.h"
+#include "script/script.h"
#include "uint256.h"
#include "util.h"
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 02c6d095f2..6c5afa130c 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -5,7 +5,10 @@
#include "key.h"
#include "keystore.h"
#include "main.h"
-#include "script.h"
+#include "script/script.h"
+#include "script/interpreter.h"
+#include "script/sign.h"
+#include "scriptutils.h"
#include "uint256.h"
#include <boost/assign/std/vector.hpp>
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 51ff1ffbc9..b7e7487bb2 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script.h"
-
#include "key.h"
#include "keystore.h"
#include "main.h"
-#include "script.h"
+#include "script/script.h"
+#include "script/sign.h"
+#include "scriptutils.h"
#include <vector>
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 77c44501ab..88efc38964 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -2,15 +2,14 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script.h"
-
#include "data/script_invalid.json.h"
#include "data/script_valid.json.h"
#include "key.h"
#include "keystore.h"
#include "main.h"
-#include "script.h"
+#include "script/script.h"
+#include "script/sign.h"
#include "core_io.h"
#include <fstream>
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index cd194cc4d9..ac60fa426f 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "bignum.h"
-#include "script.h"
+#include "script/script.h"
#include <boost/test/unit_test.hpp>
#include <limits.h>
#include <stdint.h>
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index bff151cdda..8abde887ce 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -6,7 +6,8 @@
#include "main.h"
#include "random.h"
#include "serialize.h"
-#include "script.h"
+#include "script/script.h"
+#include "script/interpreter.h"
#include "util.h"
#include "version.h"
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index 722f14a989..2d10c356ac 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "key.h"
-#include "script.h"
+#include "script/script.h"
#include "uint256.h"
#include <vector>
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 03919e7c7d..943568e89d 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -8,7 +8,7 @@
#include "key.h"
#include "keystore.h"
#include "main.h"
-#include "script.h"
+#include "script/script.h"
#include "core_io.h"
#include <map>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 238d5bab16..6bbadc8345 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -509,8 +509,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
const CTransaction& tx2 = it2->second.GetTx();
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
} else {
- const CCoins &coins = pcoins->GetCoins(txin.prevout.hash);
- assert(coins.IsAvailable(txin.prevout.n));
+ const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash);
+ assert(coins && coins->IsAvailable(txin.prevout.n));
}
// Check whether its inputs are marked in mapNextTx.
std::map<COutPoint, CInPoint>::const_iterator it3 = mapNextTx.find(txin.prevout);
@@ -606,7 +606,7 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash,
deltas.first += dPriorityDelta;
deltas.second += nFeeDelta;
}
- LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash.c_str(), dPriorityDelta, nFeeDelta);
+ LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, nFeeDelta);
}
void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta)
diff --git a/src/wallet.cpp b/src/wallet.cpp
index d3ad4869bb..218a137966 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -9,6 +9,8 @@
#include "checkpoints.h"
#include "coincontrol.h"
#include "net.h"
+#include "script/script.h"
+#include "script/sign.h"
#include "timedata.h"
#include "util.h"
#include "utilmoneystr.h"
@@ -42,7 +44,7 @@ struct CompareValueOnly
std::string COutput::ToString() const
{
- return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str());
+ return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue));
}
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
diff --git a/src/wallet.h b/src/wallet.h
index f8e1ebac12..6788986f88 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -11,6 +11,7 @@
#include "key.h"
#include "keystore.h"
#include "main.h"
+#include "scriptutils.h"
#include "ui_interface.h"
#include "walletdb.h"
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 2fa6071658..48045b98c8 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -281,8 +281,12 @@ CWalletDB::ReorderTransactions(CWallet* pwallet)
nOrderPos = nOrderPosNext++;
nOrderPosOffsets.push_back(nOrderPos);
- if (pacentry)
- // Have to write accounting regardless, since we don't keep it in memory
+ if (pwtx)
+ {
+ if (!WriteTx(pwtx->GetHash(), *pwtx))
+ return DB_LOAD_FAIL;
+ }
+ else
if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
return DB_LOAD_FAIL;
}
@@ -311,6 +315,7 @@ CWalletDB::ReorderTransactions(CWallet* pwallet)
return DB_LOAD_FAIL;
}
}
+ WriteOrderPosNext(nOrderPosNext);
return DB_LOAD_OK;
}