diff options
Diffstat (limited to 'main.cpp')
| -rw-r--r-- | main.cpp | 92 |
1 files changed, 60 insertions, 32 deletions
@@ -287,7 +287,7 @@ void EraseOrphanTx(uint256 hash) ////////////////////////////////////////////////////////////////////////////// // -// CTransaction +// CTransaction and CTxIndex // bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet) @@ -678,7 +678,11 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi // Safety limits unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK); - if (GetSigOpCount() > 2 || nSize < 100) + // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service + // attacks disallow transactions with more than one SigOp per 34 bytes. + // 34 bytes because a TxOut is: + // 20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length + if (GetSigOpCount() > nSize / 34 || nSize < 100) return error("AcceptToMemoryPool() : nonstandard transaction"); // Rather not work on nonstandard transactions @@ -1034,6 +1038,22 @@ void ResendWalletTransactions() } } +int CTxIndex::GetDepthInMainChain() const +{ + // Read block header + CBlock block; + if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false)) + return 0; + // Find the block in the index + map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.GetHash()); + if (mi == mapBlockIndex.end()) + return 0; + CBlockIndex* pindex = (*mi).second; + if (!pindex || !pindex->IsInMainChain()) + return 0; + return 1 + nBestHeight - pindex->nHeight; +} + @@ -3327,18 +3347,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; // Read block header - int nConf = 0; - CBlock block; - if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) - { - map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(block.GetHash()); - if (it != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*it).second; - if (pindex->IsInMainChain()) - nConf = 1 + nBestHeight - pindex->nHeight; - } - } + int nConf = txindex.GetDepthInMainChain(); dPriority += (double)nValueIn * nConf; @@ -3383,7 +3392,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) continue; // Transaction fee required depends on block size - bool fAllowFree = (nBlockSize + nTxSize < 4000 || dPriority > COIN * 144 / 250); + bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority)); int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree); // Connecting shouldn't fail due to dependency on other memory pool transactions @@ -3851,8 +3860,18 @@ bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet) -bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) { + int64 nValue = 0; + foreach (const PAIRTYPE(CScript, int64)& s, vecSend) + { + if (nValue < 0) + return false; + nValue += s.second; + } + if (vecSend.empty() || nValue < 0) + return false; + CRITICAL_BLOCK(cs_main) { // txdb must be opened before the mapWallet lock @@ -3865,10 +3884,12 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR wtxNew.vin.clear(); wtxNew.vout.clear(); wtxNew.fFromMe = true; - if (nValue < 0) - return false; - int64 nValueOut = nValue; + int64 nTotalValue = nValue + nFeeRet; + double dPriority = 0; + // vouts to the payees + foreach (const PAIRTYPE(CScript, int64)& s, vecSend) + wtxNew.vout.push_back(CTxOut(s.second, s.first)); // Choose coins to use set<CWalletTx*> setCoins; @@ -3876,12 +3897,11 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR return false; int64 nValueIn = 0; foreach(CWalletTx* pcoin, setCoins) - nValueIn += pcoin->GetCredit(); - - // Fill a vout to the payee - bool fChangeFirst = GetRand(2); - if (!fChangeFirst) - wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey)); + { + int64 nCredit = pcoin->GetCredit(); + nValueIn += nCredit; + dPriority += (double)nCredit * pcoin->GetDepthInMainChain(); + } // Fill a vout back to self with any change int64 nChange = nValueIn - nTotalValue; @@ -3900,19 +3920,18 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR // Fill a vout to ourself, using same address type as the payment CScript scriptChange; - if (scriptPubKey.GetBitcoinAddressHash160() != 0) + if (vecSend[0].first.GetBitcoinAddressHash160() != 0) scriptChange.SetBitcoinAddress(vchPubKey); else scriptChange << vchPubKey << OP_CHECKSIG; - wtxNew.vout.push_back(CTxOut(nChange, scriptChange)); + + // Insert change txn at random position: + vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()); + wtxNew.vout.insert(position, CTxOut(nChange, scriptChange)); } else reservekey.ReturnKey(); - // Fill a vout to the payee - if (fChangeFirst) - wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey)); - // Fill vin foreach(CWalletTx* pcoin, setCoins) for (int nOut = 0; nOut < pcoin->vout.size(); nOut++) @@ -3931,10 +3950,12 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK); if (nBytes >= MAX_BLOCK_SIZE_GEN/5) return false; + dPriority /= nBytes; // Check that enough fee is included int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); - int64 nMinFee = wtxNew.GetMinFee(); + bool fAllowFree = CTransaction::AllowFree(dPriority); + int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree); if (nFeeRet < max(nPayFee, nMinFee)) { nFeeRet = max(nPayFee, nMinFee); @@ -3952,6 +3973,13 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR return true; } +bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +{ + vector< pair<CScript, int64> > vecSend; + vecSend.push_back(make_pair(scriptPubKey, nValue)); + return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet); +} + // Call after CreateTransaction unless you want to abort bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) { |