Merge branch 'subcent-change' of https://github.com/tcatm/bitcoin
authorGavin Andresen <gavinandresen@gmail.com>
Sun, 13 Mar 2011 21:15:28 +0000 (17:15 -0400)
committerGavin Andresen <gavinandresen@gmail.com>
Sun, 13 Mar 2011 21:15:28 +0000 (17:15 -0400)
1  2 
main.cpp

diff --combined main.cpp
+++ b/main.cpp
@@@ -287,7 -287,7 +287,7 @@@ void EraseOrphanTx(uint256 hash
  
  //////////////////////////////////////////////////////////////////////////////
  //
 -// CTransaction
 +// CTransaction and CTxIndex
  //
  
  bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet)
@@@ -678,11 -678,7 +678,11 @@@ bool CTransaction::AcceptToMemoryPool(C
  
      // 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
@@@ -1038,22 -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;
 +}
 +
  
  
  
@@@ -3347,7 -3327,18 +3347,7 @@@ CBlock* CreateNewBlock(CReserveKey& res
                  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;
  
                  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
@@@ -3759,16 -3750,16 +3759,16 @@@ bool SelectCoinsMinConf(int64 nTargetVa
              int64 n = pcoin->GetCredit();
              if (n <= 0)
                  continue;
-             if (n < nTargetValue)
-             {
-                 vValue.push_back(make_pair(n, pcoin));
-                 nTotalLower += n;
-             }
-             else if (n == nTargetValue)
+             if (n == nTargetValue)
              {
                  setCoinsRet.insert(pcoin);
                  return true;
              }
+             else if (n < nTargetValue + CENT)
+             {
+                 vValue.push_back(make_pair(n, pcoin));
+                 nTotalLower += n;
+             }
              else if (n < nLowestLarger)
              {
                  nLowestLarger = n;
          }
      }
  
-     if (nTotalLower < nTargetValue)
+     if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
+     {
+         for (int i = 0; i < vValue.size(); ++i)
+             setCoinsRet.insert(vValue[i].second);
+         return true;
+     }
+     if (nTotalLower < nTargetValue + (pcoinLowestLarger ? CENT : 0))
      {
          if (pcoinLowestLarger == NULL)
              return false;
          return true;
      }
  
+     if (nTotalLower >= nTargetValue + CENT)
+         nTargetValue += CENT;
      // Solve subset sum by stochastic approximation
      sort(vValue.rbegin(), vValue.rend());
      vector<char> vfIncluded;
@@@ -3850,18 -3851,8 +3860,18 @@@ bool SelectCoins(int64 nTargetValue, se
  
  
  
 -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
                  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;
                      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;
  
                      // 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++)
                  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);
      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)
  {