diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bitcoinrpc.cpp | 5 | ||||
-rw-r--r-- | src/main.cpp | 111 | ||||
-rw-r--r-- | src/main.h | 11 | ||||
-rw-r--r-- | src/makefile.osx | 25 | ||||
-rw-r--r-- | src/makefile.unix | 16 | ||||
-rw-r--r-- | src/obj-test/.gitignore | 2 | ||||
-rw-r--r-- | src/test/script_P2SH_tests.cpp | 17 | ||||
-rw-r--r-- | src/test/transaction_tests.cpp | 2 | ||||
-rw-r--r-- | src/util.cpp | 23 |
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() |