Merge branch '0.4.x' into 0.5.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Fri, 16 Mar 2012 20:44:00 +0000 (16:44 -0400)
committerLuke Dashjr <luke-jr+git@utopios.org>
Fri, 16 Mar 2012 20:44:00 +0000 (16:44 -0400)
Conflicts:
contrib/Bitcoin.app/Contents/Info.plist
doc/README
doc/README_windows.txt
share/setup.nsi
src/serialize.h

1  2 
src/key.h
src/main.cpp

diff --combined src/key.h
+++ b/src/key.h
@@@ -39,7 -39,6 +39,7 @@@
  // see www.keylength.com
  // script supports up to 75 for single byte push
  
 +// Generate a private key from just the secret parameter
  int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
  {
      int ok = 0;
@@@ -76,79 -75,6 +76,79 @@@ err
      return(ok);
  }
  
 +// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
 +// recid selects which key is recovered
 +// if check is nonzero, additional checks are performed
 +int static inline ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
 +{
 +    if (!eckey) return 0;
 +
 +    int ret = 0;
 +    BN_CTX *ctx = NULL;
 +
 +    BIGNUM *x = NULL;
 +    BIGNUM *e = NULL;
 +    BIGNUM *order = NULL;
 +    BIGNUM *sor = NULL;
 +    BIGNUM *eor = NULL;
 +    BIGNUM *field = NULL;
 +    EC_POINT *R = NULL;
 +    EC_POINT *O = NULL;
 +    EC_POINT *Q = NULL;
 +    BIGNUM *rr = NULL;
 +    BIGNUM *zero = NULL;
 +    int n = 0;
 +    int i = recid / 2;
 +
 +    const EC_GROUP *group = EC_KEY_get0_group(eckey);
 +    if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
 +    BN_CTX_start(ctx);
 +    order = BN_CTX_get(ctx);
 +    if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
 +    x = BN_CTX_get(ctx);
 +    if (!BN_copy(x, order)) { ret=-1; goto err; }
 +    if (!BN_mul_word(x, i)) { ret=-1; goto err; }
 +    if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
 +    field = BN_CTX_get(ctx);
 +    if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
 +    if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
 +    if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
 +    if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
 +    if (check)
 +    {
 +        if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
 +        if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
 +        if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
 +    }
 +    if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
 +    n = EC_GROUP_get_degree(group);
 +    e = BN_CTX_get(ctx);
 +    if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
 +    if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
 +    zero = BN_CTX_get(ctx);
 +    if (!BN_zero(zero)) { ret=-1; goto err; }
 +    if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
 +    rr = BN_CTX_get(ctx);
 +    if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
 +    sor = BN_CTX_get(ctx);
 +    if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
 +    eor = BN_CTX_get(ctx);
 +    if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
 +    if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
 +    if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
 +
 +    ret = 1;
 +
 +err:
 +    if (ctx) {
 +        BN_CTX_end(ctx);
 +        BN_CTX_free(ctx);
 +    }
 +    if (R != NULL) EC_POINT_free(R);
 +    if (O != NULL) EC_POINT_free(O);
 +    if (Q != NULL) EC_POINT_free(Q);
 +    return ret;
 +}
  
  class key_error : public std::runtime_error
  {
@@@ -158,9 -84,7 +158,9 @@@ public
  
  
  // secure_allocator is defined in serialize.h
 +// CPrivKey is a serialized private key, with all parameters included (279 bytes)
  typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
 +// CSecret is a serialization of just the secret parameter (32 bytes)
  typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
  
  class CKey
@@@ -290,82 -214,17 +290,83 @@@ public
  
      bool Sign(uint256 hash, std::vector<unsigned char>& vchSig)
      {
-         vchSig.clear();
-         unsigned char pchSig[10000];
-         unsigned int nSize = 0;
-         if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey))
+         unsigned int nSize = ECDSA_size(pkey);
+         vchSig.resize(nSize); // Make sure it is big enough
+         if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
+         {
+             vchSig.clear();
              return false;
-         vchSig.resize(nSize);
-         memcpy(&vchSig[0], pchSig, nSize);
+         }
+         vchSig.resize(nSize); // Shrink to fit actual size
          return true;
      }
  
 +    // create a compact signature (65 bytes), which allows reconstructing the used public key
 +    // The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
 +    // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
 +    //                  0x1D = second key with even y, 0x1E = second key with odd y
 +    bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
 +    {
 +        bool fOk = false;
 +        ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
 +        if (sig==NULL)
 +            return false;
 +        vchSig.clear();
 +        vchSig.resize(65,0);
 +        int nBitsR = BN_num_bits(sig->r);
 +        int nBitsS = BN_num_bits(sig->s);
 +        if (nBitsR <= 256 && nBitsS <= 256)
 +        {
 +            int nRecId = -1;
 +            for (int i=0; i<4; i++)
 +            {
 +                CKey keyRec;
 +                keyRec.fSet = true;
 +                if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
 +                    if (keyRec.GetPubKey() == this->GetPubKey())
 +                    {
 +                        nRecId = i;
 +                        break;
 +                    }
 +            }
 +
 +            if (nRecId == -1)
 +                throw key_error("CKey::SignCompact() : unable to construct recoverable key");
 +
 +            vchSig[0] = nRecId+27;
 +            BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
 +            BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
 +            fOk = true;
 +        }
 +        ECDSA_SIG_free(sig);
 +        return fOk;
 +    }
 +
 +    // reconstruct public key from a compact signature
 +    // This is only slightly more CPU intensive than just verifying it.
 +    // If this function succeeds, the recovered public key is guaranteed to be valid
 +    // (the signature is a valid signature of the given data for that key)
 +    bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
 +    {
 +        if (vchSig.size() != 65)
 +            return false;
 +        if (vchSig[0]<27 || vchSig[0]>=31)
 +            return false;
 +        ECDSA_SIG *sig = ECDSA_SIG_new();
 +        BN_bin2bn(&vchSig[1],32,sig->r);
 +        BN_bin2bn(&vchSig[33],32,sig->s);
 +
 +        EC_KEY_free(pkey);
 +        pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
 +        if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), vchSig[0] - 27, 0) == 1)
 +        {
 +            fSet = true;
 +            ECDSA_SIG_free(sig);
 +            return true;
 +        }
 +        return false;
 +    }
 +
      bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
      {
          // -1 = error, 0 = bad sig, 1 = good
          return true;
      }
  
 +    // Verify a compact signature
 +    bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
 +    {
 +        CKey key;
 +        if (!key.SetCompactSignature(hash, vchSig))
 +            return false;
 +        if (GetPubKey() != key.GetPubKey())
 +            return false;
 +        return true;
 +    }
 +
 +    // Get the address corresponding to this key
      CBitcoinAddress GetAddress() const
      {
          return CBitcoinAddress(GetPubKey());
diff --combined src/main.cpp
@@@ -7,6 -7,7 +7,6 @@@
  #include "db.h"
  #include "net.h"
  #include "init.h"
 -#include "cryptopp/sha.h"
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
@@@ -30,6 -31,7 +30,6 @@@ map<COutPoint, CInPoint> mapNextTx
  map<uint256, CBlockIndex*> mapBlockIndex;
  uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
  static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
 -const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
  CBlockIndex* pindexGenesisBlock = NULL;
  int nBestHeight = -1;
  CBigNum bnBestChainWork = 0;
@@@ -38,8 -40,6 +38,8 @@@ uint256 hashBestChain = 0
  CBlockIndex* pindexBest = NULL;
  int64 nTimeBestReceived = 0;
  
 +CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
 +
  map<uint256, CBlock*> mapOrphanBlocks;
  multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
  
@@@ -64,14 -64,16 +64,14 @@@ int fUseUPnP = false
  #endif
  
  
 -
 -
 -
 -
 -
  //////////////////////////////////////////////////////////////////////////////
  //
  // dispatching functions
  //
  
 +// These functions dispatch to one or all registered wallets
 +
 +
  void RegisterWallet(CWallet* pwalletIn)
  {
      CRITICAL_BLOCK(cs_setpwalletRegistered)
@@@ -88,7 -90,6 +88,7 @@@ void UnregisterWallet(CWallet* pwalletI
      }
  }
  
 +// check whether the passed transaction is from us
  bool static IsFromMe(CTransaction& tx)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@@ -97,7 -98,6 +97,7 @@@
      return false;
  }
  
 +// get the wallet transaction with the given hash (if it exists)
  bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
      return false;
  }
  
 +// erases transaction with the given hash from all wallets
  void static EraseFromWallets(uint256 hash)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->EraseFromWallet(hash);
  }
  
 +// make sure all wallets know about the given transaction, in the given block
  void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
  }
  
 +// notify wallets about a new best chain
  void static SetBestChain(const CBlockLocator& loc)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->SetBestChain(loc);
  }
  
 +// notify wallets about an updated transaction
  void static UpdatedTransaction(const uint256& hashTx)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->UpdatedTransaction(hashTx);
  }
  
 +// dump all wallets
  void static PrintWallets(const CBlock& block)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->PrintWallet(block);
  }
  
 +// notify wallets about an incoming inventory (for request counts)
  void static Inventory(const uint256& hash)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->Inventory(hash);
  }
  
 +// ask wallets to resend their transactions
  void static ResendWalletTransactions()
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@@ -321,24 -314,24 +321,24 @@@ bool CTransaction::CheckTransaction() c
  {
      // Basic checks that don't depend on any context
      if (vin.empty())
 -        return error("CTransaction::CheckTransaction() : vin empty");
 +        return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
      if (vout.empty())
 -        return error("CTransaction::CheckTransaction() : vout empty");
 +        return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
      // Size limits
      if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
 -        return error("CTransaction::CheckTransaction() : size limits failed");
 +        return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
  
      // Check for negative or overflow output values
      int64 nValueOut = 0;
      BOOST_FOREACH(const CTxOut& txout, vout)
      {
          if (txout.nValue < 0)
 -            return error("CTransaction::CheckTransaction() : txout.nValue negative");
 +            return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
          if (txout.nValue > MAX_MONEY)
 -            return error("CTransaction::CheckTransaction() : txout.nValue too high");
 +            return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
          nValueOut += txout.nValue;
          if (!MoneyRange(nValueOut))
 -            return error("CTransaction::CheckTransaction() : txout total out of range");
 +            return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
      }
  
      // Check for duplicate inputs
      if (IsCoinBase())
      {
          if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
 -            return error("CTransaction::CheckTransaction() : coinbase script size");
 +            return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
      }
      else
      {
          BOOST_FOREACH(const CTxIn& txin, vin)
              if (txin.prevout.IsNull())
 -                return error("CTransaction::CheckTransaction() : prevout is null");
 +                return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
      }
  
      return true;
@@@ -375,7 -368,7 +375,7 @@@ bool CTransaction::AcceptToMemoryPool(C
  
      // Coinbase is only valid in a block, not as a loose transaction
      if (IsCoinBase())
 -        return error("AcceptToMemoryPool() : coinbase as individual tx");
 +        return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
  
      // To help v0.1.5 clients who would see it as a negative number
      if ((int64)nLockTime > INT_MAX)
      // 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");
 +        return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
  
      // Rather not work on nonstandard transactions (unless -testnet)
      if (!fTestNet && !IsStandard())
@@@ -785,15 -778,9 +785,15 @@@ bool CheckProofOfWork(uint256 hash, uns
      return true;
  }
  
 +// Return maximum amount of blocks that other nodes claim to have
 +int GetNumBlocksOfPeers()
 +{
 +    return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate());
 +}
 +
  bool IsInitialBlockDownload()
  {
 -    if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
 +    if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
          return true;
      static int64 nLastUpdate;
      static CBlockIndex* pindexLastBest;
@@@ -886,9 -873,6 +886,9 @@@ bool CTransaction::ConnectInputs(CTxDB
      fInvalid = false;
  
      // 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
 +    // fMiner is true when called from the internal bitcoin miner
 +    // ... both are false when called from CTransaction::AcceptToMemoryPool
      if (!IsCoinBase())
      {
          int64 nValueIn = 0;
                  // Revisit this if/when transaction replacement is implemented and allows
                  // adding inputs:
                  fInvalid = true;
 -                return error("ConnectInputs() : %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 DoS(100, error("ConnectInputs() : %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()));
              }
  
              // If prev is coinbase, check that it's matured
                      if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
                          return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
  
 -            // Verify signature
 -            if (!VerifySignature(txPrev, *this, i))
 -                return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
 -
 -            // Check for conflicts
 +            // 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.
 +            if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate())))
 +                // Verify signature
 +                if (!VerifySignature(txPrev, *this, i))
 +                    return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
 +
 +            // Check for conflicts (double-spend)
 +            // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
 +            // for an attacker to attempt to split the network.
              if (!txindex.vSpent[prevout.n].IsNull())
                  return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
  
              // Check for negative or overflow input values
              nValueIn += txPrev.vout[prevout.n].nValue;
              if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
 -                return error("ConnectInputs() : txin values out of range");
 +                return DoS(100, error("ConnectInputs() : txin values out of range"));
  
              // Mark outpoints as spent
              txindex.vSpent[prevout.n] = posThisTx;
          }
  
          if (nValueIn < GetValueOut())
 -            return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str());
 +            return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
  
          // Tally transaction fees
          int64 nTxFee = nValueIn - GetValueOut();
          if (nTxFee < 0)
 -            return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str());
 +            return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
          if (nTxFee < nMinFee)
              return false;
          nFees += nTxFee;
          if (!MoneyRange(nFees))
 -            return error("ConnectInputs() : nFees out of range");
 +            return DoS(100, error("ConnectInputs() : nFees out of range"));
      }
  
      if (fBlock)
@@@ -1351,11 -1329,11 +1351,11 @@@ bool CBlock::CheckBlock() cons
  
      // Size limits
      if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
 -        return error("CheckBlock() : size limits failed");
 +        return DoS(100, error("CheckBlock() : size limits failed"));
  
      // Check proof of work matches claimed amount
      if (!CheckProofOfWork(GetHash(), nBits))
 -        return error("CheckBlock() : proof of work failed");
 +        return DoS(50, error("CheckBlock() : proof of work failed"));
  
      // Check timestamp
      if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
  
      // First transaction must be coinbase, the rest must not be
      if (vtx.empty() || !vtx[0].IsCoinBase())
 -        return error("CheckBlock() : first tx is not coinbase");
 +        return DoS(100, error("CheckBlock() : first tx is not coinbase"));
      for (int i = 1; i < vtx.size(); i++)
          if (vtx[i].IsCoinBase())
 -            return error("CheckBlock() : more than one coinbase");
 +            return DoS(100, error("CheckBlock() : more than one coinbase"));
  
      // Check transactions
      BOOST_FOREACH(const CTransaction& tx, vtx)
          if (!tx.CheckTransaction())
 -            return error("CheckBlock() : CheckTransaction failed");
 +            return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
  
      // Check that it's not full of nonstandard transactions
      if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
 -        return error("CheckBlock() : too many nonstandard transactions");
 +        return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
  
      // Check merkleroot
      if (hashMerkleRoot != BuildMerkleTree())
 -        return error("CheckBlock() : hashMerkleRoot mismatch");
 +        return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
  
      return true;
  }
@@@ -1394,13 -1372,13 +1394,13 @@@ bool CBlock::AcceptBlock(
      // Get prev block index
      map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
      if (mi == mapBlockIndex.end())
 -        return error("AcceptBlock() : prev block not found");
 +        return DoS(10, error("AcceptBlock() : prev block not found"));
      CBlockIndex* pindexPrev = (*mi).second;
      int nHeight = pindexPrev->nHeight+1;
  
      // Check proof of work
      if (nBits != GetNextWorkRequired(pindexPrev, this))
 -        return error("AcceptBlock() : incorrect proof of work");
 +        return DoS(100, error("AcceptBlock() : incorrect proof of work"));
  
      // Check timestamp against prev
      if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
      // Check that all transactions are finalized
      BOOST_FOREACH(const CTransaction& tx, vtx)
          if (!tx.IsFinal(nHeight, GetBlockTime()))
 -            return error("AcceptBlock() : contains a non-final transaction");
 +            return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
  
      // Check that the block chain matches the known block chain up to a checkpoint
      if (!Checkpoints::CheckBlock(nHeight, hash))
 -        return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
 +        return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
  
      // Write block to history file
      if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
      return true;
  }
  
 -bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
 +bool ProcessBlock(CNode* pfrom, CBlock* pblock)
  {
      // Check for duplicate
      uint256 hash = pblock->GetHash();
          int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
          if (deltaTime < 0)
          {
 +            if (pfrom)
 +                pfrom->Misbehaving(100);
              return error("ProcessBlock() : block with timestamp before last checkpoint");
          }
          CBigNum bnNewBlock;
          bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
          if (bnNewBlock > bnRequired)
          {
 +            if (pfrom)
 +                pfrom->Misbehaving(100);
              return error("ProcessBlock() : block with too little proof-of-work");
          }
      }
@@@ -1895,10 -1869,7 +1895,10 @@@ bool static ProcessMessage(CNode* pfrom
      {
          // Each connection can only send one version message
          if (pfrom->nVersion != 0)
 +        {
 +            pfrom->Misbehaving(1);
              return false;
 +        }
  
          int64 nTime;
          CAddress addrMe;
          }
  
          // Ask the first connected node for block updates
-         static int nAskedForBlocks;
+         static int nAskedForBlocks = 0;
          if (!pfrom->fClient &&
              (pfrom->nVersion < 32000 || pfrom->nVersion >= 32400) &&
               (nAskedForBlocks < 1 || vNodes.size() <= 1))
          pfrom->fSuccessfullyConnected = true;
  
          printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
 +
 +        cPeerBlockCounts.input(pfrom->nStartingHeight);
      }
  
  
      else if (pfrom->nVersion == 0)
      {
          // Must have a version message before anything else
 +        pfrom->Misbehaving(1);
          return false;
      }
  
          if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
              return true;
          if (vAddr.size() > 1000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message addr size() = %d", vAddr.size());
 +        }
  
          // Store the new addresses
          CAddrDB addrDB;
          vector<CInv> vInv;
          vRecv >> vInv;
          if (vInv.size() > 50000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message inv size() = %d", vInv.size());
 +        }
  
          CTxDB txdb("r");
          BOOST_FOREACH(const CInv& inv, vInv)
          vector<CInv> vInv;
          vRecv >> vInv;
          if (vInv.size() > 50000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message getdata size() = %d", vInv.size());
 +        }
  
          BOOST_FOREACH(const CInv& inv, vInv)
          {
              if (nEvicted > 0)
                  printf("mapOrphan overflow, removed %d tx\n", nEvicted);
          }
 +        if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
      }
  
  
  
          if (ProcessBlock(pfrom, &block))
              mapAlreadyAskedFor.erase(inv);
 +        if (block.nDoS) pfrom->Misbehaving(block.nDoS);
      }
  
  
@@@ -2740,25 -2697,15 +2740,25 @@@ int static FormatHashBlocks(void* pbuff
      return blocks;
  }
  
  static const unsigned int pSHA256InitState[8] =
  {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
  
 -inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
 +void SHA256Transform(void* pstate, void* pinput, const void* pinit)
  {
 -    memcpy(pstate, pinit, 32);
 -    CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput);
 +    SHA256_CTX ctx;
 +    unsigned char data[64];
 +
 +    SHA256_Init(&ctx);
 +
 +    for (int i = 0; i < 16; i++)
 +        ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]);
 +
 +    for (int i = 0; i < 8; i++)
 +        ctx.h[i] = ((uint32_t*)pinit)[i];
 +
 +    SHA256_Update(&ctx, data, sizeof(data));
 +    for (int i = 0; i < 8; i++) 
 +        ((uint32_t*)pstate)[i] = ctx.h[i];
  }
  
  //
@@@ -3060,6 -3007,7 +3060,6 @@@ bool CheckWork(CBlock* pblock, CWallet
              return error("BitcoinMiner : ProcessBlock, block not accepted");
      }
  
 -    Sleep(2000);
      return true;
  }