aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bitcoinrpc.cpp5
-rw-r--r--src/main.cpp111
-rw-r--r--src/main.h11
-rw-r--r--src/makefile.osx25
-rw-r--r--src/makefile.unix16
-rw-r--r--src/obj-test/.gitignore2
-rw-r--r--src/test/script_P2SH_tests.cpp17
-rw-r--r--src/test/transaction_tests.cpp2
-rw-r--r--src/util.cpp23
9 files changed, 130 insertions, 82 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 5ac58de06d..3063abd1fa 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -1025,9 +1025,12 @@ Value addmultisigaddress(const Array& params, bool fHelp)
if (address.IsScript())
throw runtime_error(
strprintf("%s is a pay-to-script address",ks.c_str()));
- if (!pwalletMain->GetKey(address, pubkeys[i]))
+ std::vector<unsigned char> vchPubKey;
+ if (!pwalletMain->GetPubKey(address, vchPubKey))
throw runtime_error(
strprintf("no full public key for address %s",ks.c_str()));
+ if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
+ throw runtime_error(" Invalid public key: "+ks);
}
// Case 2: hex public key
diff --git a/src/main.cpp b/src/main.cpp
index 891dbed980..1dbd50f4e6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -277,11 +277,8 @@ bool CTransaction::IsStandard() const
//
bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
{
- if (fTestNet)
- return true; // Allow non-standard on testnet
-
if (IsCoinBase())
- return true; // Coinbases are allowed to have any input
+ return true; // Coinbases don't use vin normally
for (int i = 0; i < vin.size(); i++)
{
@@ -492,31 +489,31 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
{
MapPrevTx mapInputs;
map<uint256, CTxIndex> mapUnused;
- if (!FetchInputs(txdb, mapUnused, false, false, mapInputs))
+ bool fInvalid = false;
+ if (!FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
{
+ if (fInvalid)
+ return error("AcceptToMemoryPool() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
if (pfMissingInputs)
*pfMissingInputs = true;
return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
}
// Check for non-standard pay-to-script-hash in inputs
- if (!AreInputsStandard(mapInputs))
+ if (!AreInputsStandard(mapInputs) && !fTestNet)
return error("AcceptToMemoryPool() : nonstandard transaction input");
+ // Note: if you modify this code to accept non-standard transactions, then
+ // you should add code here to check that the transaction does a
+ // reasonable number of ECDSA signature verifications.
+
int64 nFees = GetValueIn(mapInputs)-GetValueOut();
- int nSigOps = GetSigOpCount(mapInputs);
unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
// Don't accept it if it can't get into a block
if (nFees < GetMinFee(1000, true, GMF_RELAY))
return error("AcceptToMemoryPool() : not enough fees");
- // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
- // attacks disallow transactions with more than one SigOp per 65 bytes.
- // 65 bytes because that is the minimum size of an ECDSA signature
- if (nSigOps > nSize / 65 || nSize < 100)
- return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
-
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make other's transactions take longer to confirm.
@@ -546,8 +543,6 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
{
- if (pfMissingInputs)
- *pfMissingInputs = true;
return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
}
@@ -923,8 +918,14 @@ bool CTransaction::DisconnectInputs(CTxDB& txdb)
bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool,
- bool fBlock, bool fMiner, MapPrevTx& inputsRet)
+ bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid)
{
+ // FetchInputs can return false either because we just haven't seen some inputs
+ // (in which case the transaction should be stored as an orphan)
+ // or because the transaction is malformed (in which case the transaction should
+ // be dropped). If tx is definitely invalid, fInvalid will be set to true.
+ fInvalid = false;
+
if (IsCoinBase())
return true; // Coinbase transactions have no inputs to fetch.
@@ -980,7 +981,12 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes
const CTxIndex& txindex = inputsRet[prevout.hash].first;
const CTransaction& txPrev = inputsRet[prevout.hash].second;
if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
+ {
+ // Revisit this if/when transaction replacement is implemented and allows
+ // adding inputs:
+ fInvalid = true;
return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
+ }
}
return true;
@@ -1013,7 +1019,7 @@ int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const
}
-int CTransaction::GetSigOpCount(const MapPrevTx& inputs) const
+int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
{
if (IsCoinBase())
return 0;
@@ -1021,14 +1027,16 @@ int CTransaction::GetSigOpCount(const MapPrevTx& inputs) const
int nSigOps = 0;
for (int i = 0; i < vin.size(); i++)
{
- nSigOps += GetOutputFor(vin[i], inputs).scriptPubKey.GetSigOpCount(vin[i].scriptSig);
+ const CTxOut& prevout = GetOutputFor(vin[i], inputs);
+ if (prevout.scriptPubKey.IsPayToScriptHash())
+ nSigOps += prevout.scriptPubKey.GetSigOpCount(vin[i].scriptSig);
}
return nSigOps;
}
bool CTransaction::ConnectInputs(MapPrevTx inputs,
map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
- const CBlockIndex* pindexBlock, bool fBlock, bool fMiner)
+ const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash)
{
// Take over previous transactions' spent pointers
// fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
@@ -1065,20 +1073,6 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,
if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return DoS(100, error("ConnectInputs() : txin values out of range"));
- bool fStrictPayToScriptHash = true;
- if (fBlock)
- {
- // To avoid being on the short end of a block-chain split,
- // don't do secondary validation of pay-to-script-hash transactions
- // until blocks with timestamps after paytoscripthashtime:
- int64 nEvalSwitchTime = GetArg("paytoscripthashtime", 1329264000); // Feb 15, 2012
- fStrictPayToScriptHash = (pindexBlock->nTime >= nEvalSwitchTime);
- }
- // if !fBlock, then always be strict-- don't accept
- // invalid-under-new-rules pay-to-script-hash transactions into
- // our memory pool (don't relay them, don't include them
- // in blocks we mine).
-
// Skip ECDSA signature verification when connecting blocks (fBlock=true)
// before the last blockchain checkpoint. This is safe because block merkle hashes are
// still computed and checked, and any change will be caught at the next checkpoint.
@@ -1189,6 +1183,12 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
if (!CheckBlock())
return false;
+ // To avoid being on the short end of a block-chain split,
+ // don't do secondary validation of pay-to-script-hash transactions
+ // until blocks with timestamps after paytoscripthashtime:
+ int64 nEvalSwitchTime = GetArg("-paytoscripthashtime", 1329264000); // Feb 15, 2012
+ bool fStrictPayToScriptHash = (pindex->nTime >= nEvalSwitchTime);
+
//// issue here: it doesn't know the version
unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
@@ -1197,26 +1197,33 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
int nSigOps = 0;
BOOST_FOREACH(CTransaction& tx, vtx)
{
+ nSigOps += tx.GetLegacySigOpCount();
+ if (nSigOps > MAX_BLOCK_SIGOPS)
+ return DoS(100, error("ConnectBlock() : too many sigops"));
+
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
nTxPos += ::GetSerializeSize(tx, SER_DISK);
MapPrevTx mapInputs;
if (!tx.IsCoinBase())
{
- if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs))
+ bool fInvalid;
+ if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid))
return false;
- int nTxOps = tx.GetSigOpCount(mapInputs);
- nSigOps += nTxOps;
- if (nSigOps > MAX_BLOCK_SIGOPS)
- return DoS(100, error("ConnectBlock() : too many sigops"));
- // There is a different MAX_BLOCK_SIGOPS check in AcceptBlock();
- // a block must satisfy both to make it into the best-chain
- // (AcceptBlock() is always called before ConnectBlock())
+ if (fStrictPayToScriptHash)
+ {
+ // Add in sigops done by pay-to-script-hash inputs;
+ // this is to prevent a "rogue miner" from creating
+ // an incredibly-expensive-to-validate block.
+ nSigOps += tx.GetP2SHSigOpCount(mapInputs);
+ if (nSigOps > MAX_BLOCK_SIGOPS)
+ return DoS(100, error("ConnectBlock() : too many sigops"));
+ }
nFees += tx.GetValueIn(mapInputs)-tx.GetValueOut();
- if (!tx.ConnectInputs(mapInputs, mapQueuedChanges, posThisTx, pindex, true, false))
+ if (!tx.ConnectInputs(mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fStrictPayToScriptHash))
return false;
}
@@ -1500,9 +1507,6 @@ bool CBlock::CheckBlock() const
if (!tx.CheckTransaction())
return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
- // Pre-pay-to-script-hash (before version 0.6), this is how sigops
- // were counted; there is another check in ConnectBlock when
- // transaction inputs are fetched to count pay-to-script-hash sigops:
int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx)
{
@@ -3036,8 +3040,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
map<uint256, CTxIndex> mapTestPool;
uint64 nBlockSize = 1000;
uint64 nBlockTx = 0;
- int nBlockSigOps1 = 100; // pre-0.6 count of sigOps
- int nBlockSigOps2 = 100; // post-0.6 count of sigOps
+ int nBlockSigOps = 100;
while (!mapPriority.empty())
{
// Take highest priority transaction off priority queue
@@ -3051,8 +3054,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
continue;
// Legacy limits on sigOps:
- int nTxSigOps1 = tx.GetLegacySigOpCount();
- if (nBlockSigOps1 + nTxSigOps1 >= MAX_BLOCK_SIGOPS)
+ int nTxSigOps = tx.GetLegacySigOpCount();
+ if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
// Transaction fee required depends on block size
@@ -3063,15 +3066,16 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
// because we're already processing them in order of dependency
map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
MapPrevTx mapInputs;
- if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs))
+ bool fInvalid;
+ if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid))
continue;
int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
if (nFees < nMinFee)
continue;
- int nTxSigOps2 = tx.GetSigOpCount(mapInputs);
- if (nBlockSigOps2 + nTxSigOps2 >= MAX_BLOCK_SIGOPS)
+ nTxSigOps += tx.GetP2SHSigOpCount(mapInputs);
+ if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, false, true))
@@ -3083,8 +3087,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
pblock->vtx.push_back(tx);
nBlockSize += nTxSize;
++nBlockTx;
- nBlockSigOps1 += nTxSigOps1;
- nBlockSigOps2 += nTxSigOps2;
+ nBlockSigOps += nTxSigOps;
// Add transactions that depend on this one to the priority queue
uint256 hash = tx.GetHash();
diff --git a/src/main.h b/src/main.h
index be5f2f58a5..124b228ec9 100644
--- a/src/main.h
+++ b/src/main.h
@@ -528,14 +528,13 @@ public:
*/
int GetLegacySigOpCount() const;
- /** Count ECDSA signature operations the new (0.6-and-later) way
- This is a better measure of how expensive it is to process this transaction.
+ /** Count ECDSA signature operations in pay-to-script-hash inputs.
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return maximum number of sigops required to validate this transaction's inputs
@see CTransaction::FetchInputs
*/
- int GetSigOpCount(const MapPrevTx& mapInputs) const;
+ int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const;
/** Amount of bitcoins spent by this transaction.
@return sum of all outputs (note: does not include fees)
@@ -684,10 +683,11 @@ public:
@param[in] fBlock True if being called to add a new best-block to the chain
@param[in] fMiner True if being called by CreateNewBlock
@param[out] inputsRet Pointers to this transaction's inputs
+ @param[out] fInvalid returns true if transaction is invalid
@return Returns true if all inputs are in txdb or mapTestPool
*/
bool FetchInputs(CTxDB& txdb, const std::map<uint256, CTxIndex>& mapTestPool,
- bool fBlock, bool fMiner, MapPrevTx& inputsRet);
+ bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid);
/** Sanity check previous transactions, then, if all checks succeed,
mark them as spent by this transaction.
@@ -698,11 +698,12 @@ public:
@param[in] pindexBlock
@param[in] fBlock true if called from ConnectBlock
@param[in] fMiner true if called from CreateNewBlock
+ @param[in] fStrictPayToScriptHash true if fully validating p2sh transactions
@return Returns true if all checks succeed
*/
bool ConnectInputs(MapPrevTx inputs,
std::map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
- const CBlockIndex* pindexBlock, bool fBlock, bool fMiner);
+ const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash=true);
bool ClientConnectInputs();
bool CheckTransaction() const;
bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
diff --git a/src/makefile.osx b/src/makefile.osx
index fd60f6233d..9943271a29 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -23,6 +23,8 @@ USE_UPNP:=1
LIBS= -dead_strip
ifdef STATIC
# Build STATIC if you are redistributing the bitcoind binary
+TESTLIBS += \
+ $(DEPSDIR)/lib/libboost_unit_test_framework-mt.a
LIBS += \
$(DEPSDIR)/lib/db48/libdb_cxx-4.8.a \
$(DEPSDIR)/lib/libboost_system-mt.a \
@@ -30,8 +32,11 @@ LIBS += \
$(DEPSDIR)/lib/libboost_program_options-mt.a \
$(DEPSDIR)/lib/libboost_thread-mt.a \
$(DEPSDIR)/lib/libssl.a \
- $(DEPSDIR)/lib/libcrypto.a
+ $(DEPSDIR)/lib/libcrypto.a \
+ -lz
else
+TESTLIBS += \
+ -lboost_unit_test_framework-mt
LIBS += \
-ldb_cxx-4.8 \
-lboost_system-mt \
@@ -39,7 +44,9 @@ LIBS += \
-lboost_program_options-mt \
-lboost_thread-mt \
-lssl \
- -lcrypto
+ -lcrypto \
+ -lz
+TESTDEFS += -DBOOST_TEST_DYN_LINK
endif
DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DUSE_SSL
@@ -81,7 +88,7 @@ all: bitcoind
# auto-generated dependencies:
-include obj/*.P
--include obj/test/*.P
+-include obj-test/*.P
obj/%.o: %.cpp
$(CXX) -c $(CFLAGS) -MMD -o $@ $<
@@ -93,21 +100,21 @@ obj/%.o: %.cpp
bitcoind: $(OBJS:obj/%=obj/%)
$(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
-TESTOBJS := $(patsubst test/%.cpp,obj/test/%.o,$(wildcard test/*.cpp))
+TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
-obj/test/%.o: test/%.cpp
- $(CXX) -c $(CFLAGS) -MMD -o $@ $<
+obj-test/%.o: test/%.cpp
+ $(CXX) -c $(TESTDEFS) $(CFLAGS) -MMD -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
test_bitcoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- $(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) $(DEPSDIR)/lib/libboost_unit_test_framework-mt.a
+ $(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) $(TESTLIBS)
clean:
-rm -f bitcoind test_bitcoin
-rm -f obj/*.o
- -rm -f obj/test/*.o
+ -rm -f obj-test/*.o
-rm -f obj/*.P
- -rm -f obj/test/*.P
+ -rm -f obj-test/*.P
diff --git a/src/makefile.unix b/src/makefile.unix
index 3c6be3ee41..41452dec81 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -16,6 +16,8 @@ ifdef STATIC
ifeq (${STATIC}, all)
LMODE2 = static
endif
+else
+ TESTDEFS += -DBOOST_TEST_DYN_LINK
endif
# for boost 1.37, add -mt to the boost libraries
@@ -109,7 +111,7 @@ all: bitcoind
# auto-generated dependencies:
-include obj/*.P
--include obj/test/*.P
+-include obj-test/*.P
obj/%.o: %.cpp
$(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
@@ -121,21 +123,21 @@ obj/%.o: %.cpp
bitcoind: $(OBJS:obj/%=obj/%)
$(CXX) $(xCXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
-TESTOBJS := $(patsubst test/%.cpp,obj/test/%.o,$(wildcard test/*.cpp))
+TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
-obj/test/%.o: test/%.cpp
- $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
+obj-test/%.o: test/%.cpp
+ $(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -MMD -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
test_bitcoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LDFLAGS) $(LIBS)
+ $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-B$(LMODE) -lboost_unit_test_framework $(LDFLAGS) $(LIBS)
clean:
-rm -f bitcoind test_bitcoin
-rm -f obj/*.o
- -rm -f obj/test/*.o
+ -rm -f obj-test/*.o
-rm -f obj/*.P
- -rm -f obj/test/*.P
+ -rm -f obj-test/*.P
diff --git a/src/obj-test/.gitignore b/src/obj-test/.gitignore
new file mode 100644
index 0000000000..d6b7ef32c8
--- /dev/null
+++ b/src/obj-test/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index aed3e23319..c782e0c6c1 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
}
CTransaction txFrom;
- txFrom.vout.resize(5);
+ txFrom.vout.resize(6);
// First three are standard:
CScript pay1; pay1.SetBitcoinAddress(key[0].GetPubKey());
@@ -267,12 +267,18 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txFrom.vout[1].scriptPubKey = pay1;
txFrom.vout[2].scriptPubKey = pay1of3;
- // Last two non-standard:
+ // Last three non-standard:
CScript empty;
keystore.AddCScript(empty);
txFrom.vout[3].scriptPubKey = empty;
// Can't use SetPayToScriptHash, it checks for the empty Script. So:
txFrom.vout[4].scriptPubKey << OP_HASH160 << Hash160(empty) << OP_EQUAL;
+ CScript oneOfEleven;
+ oneOfEleven << OP_1;
+ for (int i = 0; i < 11; i++)
+ oneOfEleven << key[0].GetPubKey();
+ oneOfEleven << OP_11 << OP_CHECKMULTISIG;
+ txFrom.vout[5].scriptPubKey.SetPayToScriptHash(oneOfEleven);
mapInputs[txFrom.GetHash()] = make_pair(CTxIndex(), txFrom);
@@ -292,16 +298,21 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
BOOST_CHECK(txTo.AreInputsStandard(mapInputs));
+ BOOST_CHECK_EQUAL(txTo.GetP2SHSigOpCount(mapInputs), 1);
CTransaction txToNonStd;
txToNonStd.vout.resize(1);
txToNonStd.vout[0].scriptPubKey.SetBitcoinAddress(key[1].GetPubKey());
- txToNonStd.vin.resize(1);
+ txToNonStd.vin.resize(2);
txToNonStd.vin[0].prevout.n = 4;
txToNonStd.vin[0].prevout.hash = txFrom.GetHash();
txToNonStd.vin[0].scriptSig << Serialize(empty);
+ txToNonStd.vin[1].prevout.n = 5;
+ txToNonStd.vin[1].prevout.hash = txFrom.GetHash();
+ txToNonStd.vin[1].scriptSig << OP_0 << Serialize(oneOfEleven);
BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs));
+ BOOST_CHECK_EQUAL(txToNonStd.GetP2SHSigOpCount(mapInputs), 11);
txToNonStd.vin[0].scriptSig.clear();
BOOST_CHECK(!txToNonStd.AreInputsStandard(mapInputs));
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 33765ca966..592fe3f81a 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -78,7 +78,6 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vout[0].scriptPubKey << OP_1;
BOOST_CHECK(t1.AreInputsStandard(dummyInputs));
- BOOST_CHECK_EQUAL(t1.GetSigOpCount(dummyInputs), 3);
BOOST_CHECK_EQUAL(t1.GetValueIn(dummyInputs), (50+21+22)*CENT);
}
@@ -103,7 +102,6 @@ BOOST_AUTO_TEST_CASE(test_GetThrow)
t1.vout[0].scriptPubKey << OP_1;
BOOST_CHECK_THROW(t1.AreInputsStandard(missingInputs), runtime_error);
- BOOST_CHECK_THROW(t1.GetSigOpCount(missingInputs), runtime_error);
BOOST_CHECK_THROW(t1.GetValueIn(missingInputs), runtime_error);
}
diff --git a/src/util.cpp b/src/util.cpp
index 67e1bf801a..6a4c2a2ef3 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1153,7 +1153,18 @@ static void pop_lock()
void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
{
push_lock(this, CLockLocation(pszName, pszFile, nLine));
+#ifdef DEBUG_LOCKCONTENTION
+ bool result = mutex.try_lock();
+ if (!result)
+ {
+ printf("LOCKCONTENTION: %s\n", pszName);
+ printf("Locker: %s:%d\n", pszFile, nLine);
+ mutex.lock();
+ printf("Locked\n");
+ }
+#else
mutex.lock();
+#endif
}
void CCriticalSection::Leave()
{
@@ -1170,9 +1181,19 @@ bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nL
#else
-void CCriticalSection::Enter(const char*, const char*, int)
+void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
{
+#ifdef DEBUG_LOCKCONTENTION
+ bool result = mutex.try_lock();
+ if (!result)
+ {
+ printf("LOCKCONTENTION: %s\n", pszName);
+ printf("Locker: %s:%d\n", pszFile, nLine);
+ mutex.lock();
+ }
+#else
mutex.lock();
+#endif
}
void CCriticalSection::Leave()