Merge with Bitcoin v0.6.3
authorScott Nadal <scott.nadal@gmail.com>
Mon, 23 Jul 2012 00:09:18 +0000 (01:09 +0100)
committerScott Nadal <scott.nadal@gmail.com>
Mon, 23 Jul 2012 00:09:18 +0000 (01:09 +0100)
24 files changed:
1  2 
src/base58.h
src/bignum.h
src/bitcoinrpc.cpp
src/checkpoints.cpp
src/checkpoints.h
src/db.cpp
src/db.h
src/init.cpp
src/main.cpp
src/main.h
src/makefile.mingw
src/makefile.unix
src/net.cpp
src/net.h
src/protocol.h
src/script.cpp
src/script.h
src/serialize.h
src/util.cpp
src/util.h
src/version.cpp
src/version.h
src/wallet.cpp
src/wallet.h

diff --combined src/base58.h
@@@ -1,8 -1,7 +1,8 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin Developers
- // Copyright (c) 2011 The PPCoin developers
+ // Copyright (c) 2009-2012 The Bitcoin Developers
++// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  
  //
@@@ -19,6 -18,7 +19,7 @@@
  #include <string>
  #include <vector>
  #include "bignum.h"
+ #include "key.h"
  
  static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
  
@@@ -169,7 -169,7 +170,7 @@@ inline bool DecodeBase58Check(const std
  
  
  
- // Base class for all base58-encoded data
+ /** Base class for all base58-encoded data */
  class CBase58Data
  {
  protected:
@@@ -252,35 -252,61 +253,61 @@@ public
      bool operator> (const CBase58Data& b58) const { return CompareTo(b58) >  0; }
  };
  
- #define PPCOIN_ADDRESS_VERSION   55   // ppcoin: addresses begin with 'P'
- // base58-encoded bitcoin addresses
- // Addresses have version 0 or 111 (testnet)
- // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key
+ /** base58-encoded bitcoin addresses.
 - * Public-key-hash-addresses have version 0 (or 111 testnet).
++ * Public-key-hash-addresses have version 55 (or 111 testnet).
+  * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
 - * Script-hash-addresses have version 5 (or 196 testnet).
++ * Script-hash-addresses have version 57 (or 196 testnet).
+  * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
+  */
  class CBitcoinAddress : public CBase58Data
  {
  public:
+     enum
+     {
 -        PUBKEY_ADDRESS = 0,
 -        SCRIPT_ADDRESS = 5,
++        PUBKEY_ADDRESS = 55,  // ppcoin: addresses begin with 'P'
++        SCRIPT_ADDRESS = 57,  // ppcoin: addresses begin with 'Q'
+         PUBKEY_ADDRESS_TEST = 111,
+         SCRIPT_ADDRESS_TEST = 196,
+     };
      bool SetHash160(const uint160& hash160)
      {
-         SetData(fTestNet ? 111 : PPCOIN_ADDRESS_VERSION, &hash160, 20);
+         SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &hash160, 20);
          return true;
      }
  
-     bool SetPubKey(const std::vector<unsigned char>& vchPubKey)
+     void SetPubKey(const std::vector<unsigned char>& vchPubKey)
+     {
+         SetHash160(Hash160(vchPubKey));
+     }
+     bool SetScriptHash160(const uint160& hash160)
      {
-         return SetHash160(Hash160(vchPubKey));
+         SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &hash160, 20);
+         return true;
      }
  
      bool IsValid() const
      {
-         int nExpectedSize = 20;
+         unsigned int nExpectedSize = 20;
          bool fExpectTestNet = false;
          switch(nVersion)
          {
-             case PPCOIN_ADDRESS_VERSION:
+             case PUBKEY_ADDRESS:
+                 nExpectedSize = 20; // Hash of public key
+                 fExpectTestNet = false;
+                 break;
+             case SCRIPT_ADDRESS:
+                 nExpectedSize = 20; // Hash of CScript
+                 fExpectTestNet = false;
                  break;
  
-             case 111:
+             case PUBKEY_ADDRESS_TEST:
+                 nExpectedSize = 20;
+                 fExpectTestNet = true;
+                 break;
+             case SCRIPT_ADDRESS_TEST:
+                 nExpectedSize = 20;
                  fExpectTestNet = true;
                  break;
  
          }
          return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize;
      }
+     bool IsScript() const
+     {
+         if (!IsValid())
+             return false;
+         if (fTestNet)
+             return nVersion == SCRIPT_ADDRESS_TEST;
+         return nVersion == SCRIPT_ADDRESS;
+     }
  
      CBitcoinAddress()
      {
      }
  };
  
+ /** A base58-encoded secret key */
+ class CBitcoinSecret : public CBase58Data
+ {
+ public:
+     void SetSecret(const CSecret& vchSecret, bool fCompressed)
+     { 
+         assert(vchSecret.size() == 32);
+         SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size());
+         if (fCompressed)
+             vchData.push_back(1);
+     }
+     CSecret GetSecret(bool &fCompressedOut)
+     {
+         CSecret vchSecret;
+         vchSecret.resize(32);
+         memcpy(&vchSecret[0], &vchData[0], 32);
+         fCompressedOut = vchData.size() == 33;
+         return vchSecret;
+     }
+     bool IsValid() const
+     {
+         bool fExpectTestNet = false;
+         switch(nVersion)
+         {
+             case 128:
+                 break;
+             case 239:
+                 fExpectTestNet = true;
+                 break;
+             default:
+                 return false;
+         }
+         return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1));
+     }
+     bool SetString(const char* pszSecret)
+     {
+         return CBase58Data::SetString(pszSecret) && IsValid();
+     }
+     bool SetString(const std::string& strSecret)
+     {
+         return SetString(strSecret.c_str());
+     }
+     CBitcoinSecret(const CSecret& vchSecret, bool fCompressed)
+     {
+         SetSecret(vchSecret, fCompressed);
+     }
+     CBitcoinSecret()
+     {
+     }
+ };
  #endif
diff --combined src/bignum.h
@@@ -1,7 -1,7 +1,7 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_BIGNUM_H
  #define BITCOIN_BIGNUM_H
  
@@@ -9,8 -9,9 +9,9 @@@
  #include <vector>
  #include <openssl/bn.h>
  
- #include "util.h"
+ #include "util.h" // for uint64
  
+ /** Errors thrown by the bignum class */
  class bignum_error : public std::runtime_error
  {
  public:
@@@ -18,7 -19,7 +19,7 @@@
  };
  
  
+ /** RAII encapsulated BN_CTX (OpenSSL bignum context) */
  class CAutoBN_CTX
  {
  protected:
@@@ -46,7 -47,7 +47,7 @@@ public
  };
  
  
+ /** C++ wrapper for BIGNUM (OpenSSL bignum) */
  class CBigNum : public BIGNUM
  {
  public:
@@@ -77,7 -78,8 +78,8 @@@
          BN_clear_free(this);
      }
  
-     CBigNum(char n)             { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
+     //CBigNum(char n) is not portable.  Use 'signed char' or 'unsigned char'.
+     CBigNum(signed char n)      { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
      CBigNum(short n)            { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
      CBigNum(int n)              { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
      CBigNum(long n)             { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
      {
          unsigned long n = BN_get_word(this);
          if (!BN_is_negative(this))
-             return (n > INT_MAX ? INT_MAX : n);
+             return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
          else
-             return (n > INT_MAX ? INT_MIN : -(int)n);
+             return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
      }
  
      void setint64(int64 n)
          BN_mpi2bn(pch, p - pch, this);
      }
  
 +    uint64 getuint64()
 +    {
 +        unsigned int nSize = BN_bn2mpi(this, NULL);
 +        if (nSize < 4)
 +            return 0;
 +        std::vector<unsigned char> vch(nSize);
 +        BN_bn2mpi(this, &vch[0]);
 +        if (vch.size() > 4)
 +            vch[4] &= 0x7f;
 +        uint64 n = 0;
 +        for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
 +            ((unsigned char*)&n)[i] = vch[j];
 +        return n;
 +    }
 +
      void setuint256(uint256 n)
      {
          unsigned char pch[sizeof(n) + 6];
          if (vch.size() > 4)
              vch[4] &= 0x7f;
          uint256 n = 0;
-         for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
+         for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
              ((unsigned char*)&n)[i] = vch[j];
          return n;
      }
      std::vector<unsigned char> getvch() const
      {
          unsigned int nSize = BN_bn2mpi(this, NULL);
-         if (nSize < 4)
+         if (nSize <= 4)
              return std::vector<unsigned char>();
          std::vector<unsigned char> vch(nSize);
          BN_bn2mpi(this, &vch[0]);
              psz++;
  
          // hex string to bignum
-         static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
+         static signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
          *this = 0;
          while (isxdigit(*psz))
          {
              *this <<= 4;
-             int n = phexdigit[*psz++];
+             int n = phexdigit[(unsigned char)*psz++];
              *this += n;
          }
          if (fNegative)
          return ToString(16);
      }
  
-     unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const
+     unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
      {
          return ::GetSerializeSize(getvch(), nType, nVersion);
      }
  
      template<typename Stream>
-     void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
+     void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
      {
          ::Serialize(s, getvch(), nType, nVersion);
      }
  
      template<typename Stream>
-     void Unserialize(Stream& s, int nType=0, int nVersion=VERSION)
+     void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
      {
          std::vector<unsigned char> vch;
          ::Unserialize(s, vch, nType, nVersion);
diff --combined src/bitcoinrpc.cpp
@@@ -1,28 -1,28 +1,30 @@@
  // Copyright (c) 2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
- #include "headers.h"
+ #include "main.h"
+ #include "wallet.h"
  #include "db.h"
+ #include "walletdb.h"
  #include "net.h"
  #include "init.h"
 +#include "checkpoints.h"
+ #include "ui_interface.h"
+ #include "bitcoinrpc.h"
  #undef printf
  #include <boost/asio.hpp>
+ #include <boost/filesystem.hpp>
  #include <boost/iostreams/concepts.hpp>
  #include <boost/iostreams/stream.hpp>
  #include <boost/algorithm/string.hpp>
- #ifdef USE_SSL
+ #include <boost/lexical_cast.hpp>
  #include <boost/asio/ssl.hpp> 
- #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
- #endif
- #include "json/json_spirit_reader_template.h"
- #include "json/json_spirit_writer_template.h"
- #include "json/json_spirit_utils.h"
  #define printf OutputDebugStringF
  // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
  // precompiled in headers.h.  The problem might be when the pch file goes over
@@@ -35,14 -35,14 +37,14 @@@ using namespace boost::asio
  using namespace json_spirit;
  
  void ThreadRPCServer2(void* parg);
- typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
- extern map<string, rpcfn_type> mapCallTable;
  
  static std::string strRPCUserColonPass;
  
  static int64 nWalletUnlockTime;
  static CCriticalSection cs_nWalletUnlockTime;
  
+ extern Value dumpprivkey(const Array& params, bool fHelp);
+ extern Value importprivkey(const Array& params, bool fHelp);
  
  Object JSONRPCError(int code, const string& message)
  {
      return error;
  }
  
- void PrintConsole(const std::string &format, ...)
+ double GetDifficulty(const CBlockIndex* blockindex = NULL)
  {
-     char buffer[50000];
-     int limit = sizeof(buffer);
-     va_list arg_ptr;
-     va_start(arg_ptr, format);
-     int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
-     va_end(arg_ptr);
-     if (ret < 0 || ret >= limit)
+     // Floating point number that is a multiple of the minimum difficulty,
+     // minimum difficulty = 1.0.
+     if (blockindex == NULL)
      {
-         ret = limit - 1;
-         buffer[limit-1] = 0;
+         if (pindexBest == NULL)
+             return 1.0;
+         else
 -            blockindex = pindexBest;
++            blockindex = GetLastBlockIndex(pindexBest, false);
      }
-     printf("%s", buffer);
-     fprintf(stdout, "%s", buffer);
+     int nShift = (blockindex->nBits >> 24) & 0xff;
+     double dDiff =
+         (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
+     while (nShift < 29)
+     {
+         dDiff *= 256.0;
+         nShift++;
+     }
+     while (nShift > 29)
+     {
+         dDiff /= 256.0;
+         nShift--;
+     }
+     return dDiff;
  }
  
  
  int64 AmountFromValue(const Value& value)
  {
      double dAmount = value.get_real();
 -    if (dAmount <= 0.0 || dAmount > 21000000.0)
 +    if (dAmount <= 0.0 || dAmount > MAX_MONEY)
          throw JSONRPCError(-3, "Invalid amount");
      int64 nAmount = roundint64(dAmount * COIN);
      if (!MoneyRange(nAmount))
@@@ -87,9 -100,26 +102,26 @@@ Value ValueFromAmount(int64 amount
      return (double)amount / (double)COIN;
  }
  
+ std::string
+ HexBits(unsigned int nBits)
+ {
+     union {
+         int32_t nBits;
+         char cBits[4];
+     } uBits;
+     uBits.nBits = htonl((int32_t)nBits);
+     return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
+ }
  void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
  {
-     entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
+     int confirms = wtx.GetDepthInMainChain();
+     entry.push_back(Pair("confirmations", confirms));
+     if (confirms)
+     {
+         entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
+         entry.push_back(Pair("blockindex", wtx.nIndex));
+     }
      entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
      entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
      BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
@@@ -104,29 -134,44 +136,44 @@@ string AccountFromValue(const Value& va
      return strAccount;
  }
  
+ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
+ {
+     Object result;
+     result.push_back(Pair("hash", block.GetHash().GetHex()));
+     result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
+     result.push_back(Pair("height", blockindex->nHeight));
+     result.push_back(Pair("version", block.nVersion));
+     result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
+     result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
+     result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
+     result.push_back(Pair("bits", HexBits(block.nBits)));
+     result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
+     Array txhashes;
+     BOOST_FOREACH (const CTransaction&tx, block.vtx)
+         txhashes.push_back(tx.GetHash().GetHex());
+     result.push_back(Pair("tx", txhashes));
+     if (blockindex->pprev)
+         result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
+     if (blockindex->pnext)
+         result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
+     return result;
+ }
  
  
  ///
  /// Note: This interface may still be subject to change.
  ///
  
- Value help(const Array& params, bool fHelp)
+ string CRPCTable::help(string strCommand) const
  {
-     if (fHelp || params.size() > 1)
-         throw runtime_error(
-             "help [command]\n"
-             "List commands, or get help for a command.");
-     string strCommand;
-     if (params.size() > 0)
-         strCommand = params[0].get_str();
      string strRet;
      set<rpcfn_type> setDone;
-     for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
+     for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
      {
-         string strMethod = (*mi).first;
+         const CRPCCommand *pcmd = mi->second;
+         string strMethod = mi->first;
          // We already filter duplicates, but these deprecated screw up the sort order
          if (strMethod == "getamountreceived" ||
              strMethod == "getallreceived" ||
          try
          {
              Array params;
-             rpcfn_type pfn = (*mi).second;
+             rpcfn_type pfn = pcmd->actor;
              if (setDone.insert(pfn).second)
                  (*pfn)(params, true);
          }
              // Help text is returned in an exception
              string strHelp = string(e.what());
              if (strCommand == "")
-                 if (strHelp.find('\n') != -1)
+                 if (strHelp.find('\n') != string::npos)
                      strHelp = strHelp.substr(0, strHelp.find('\n'));
              strRet += strHelp + "\n";
          }
      return strRet;
  }
  
+ Value help(const Array& params, bool fHelp)
+ {
+     if (fHelp || params.size() > 1)
+         throw runtime_error(
+             "help [command]\n"
+             "List commands, or get help for a command.");
+     string strCommand;
+     if (params.size() > 0)
+         strCommand = params[0].get_str();
+     return tableRPC.help(strCommand);
+ }
  
  Value stop(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 0)
          throw runtime_error(
              "stop\n"
 -            "Stop bitcoin server.");
 +            "Stop ppcoin server.");
- #ifndef QT_GUI
      // Shutdown will take long enough that the response should get back
-     CreateThread(Shutdown, NULL);
+     StartShutdown();
 -    return "bitcoin server stopping";
 +    return "ppcoin server stopping";
- #else
-     throw runtime_error("NYI: cannot shut down GUI with RPC command");
- #endif
  }
  
  
@@@ -209,33 -264,6 +266,6 @@@ Value getconnectioncount(const Array& p
  }
  
  
- double GetDifficulty()
- {
-     // Floating point number that is a multiple of the minimum difficulty,
-     // minimum difficulty = 1.0.
-     if (pindexBest == NULL)
-         return 1.0;
-     const CBlockIndex* pindexLastProofOfWork = GetLastBlockIndex(pindexBest, false);
-     int nShift = (pindexLastProofOfWork->nBits >> 24) & 0xff;
-     double dDiff =
-         (double)0x0000ffff / (double)(pindexLastProofOfWork->nBits & 0x00ffffff);
-     while (nShift < 29)
-     {
-         dDiff *= 256.0;
-         nShift++;
-     }
-     while (nShift > 29)
-     {
-         dDiff /= 256.0;
-         nShift--;
-     }
-     return dDiff;
- }
  Value getdifficulty(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 0)
@@@ -254,7 -282,7 +284,7 @@@ Value getgenerate(const Array& params, 
              "getgenerate\n"
              "Returns true or false.");
  
-     return (bool)fGenerateBitcoins;
+     return GetBoolArg("-gen");
  }
  
  
@@@ -273,13 -301,11 +303,11 @@@ Value setgenerate(const Array& params, 
      if (params.size() > 1)
      {
          int nGenProcLimit = params[1].get_int();
-         fLimitProcessors = (nGenProcLimit != -1);
-         WriteSetting("fLimitProcessors", fLimitProcessors);
-         if (nGenProcLimit != -1)
-             WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
+         mapArgs["-genproclimit"] = itostr(nGenProcLimit);
          if (nGenProcLimit == 0)
              fGenerate = false;
      }
+     mapArgs["-gen"] = (fGenerate ? "1" : "0");
  
      GenerateBitcoins(fGenerate, pwalletMain);
      return Value::null;
@@@ -307,25 -333,43 +335,46 @@@ Value getinfo(const Array& params, boo
              "Returns an object containing various state info.");
  
      Object obj;
 -    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
 +    obj.push_back(Pair("version",       FormatFullVersion()));
+     obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
+     obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
      obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
 +    obj.push_back(Pair("newmint",       ValueFromAmount(pwalletMain->GetNewMint())));
 +    obj.push_back(Pair("stake",         ValueFromAmount(pwalletMain->GetStake())));
      obj.push_back(Pair("blocks",        (int)nBestHeight));
      obj.push_back(Pair("connections",   (int)vNodes.size()));
      obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
 +    obj.push_back(Pair("ip",            addrSeenByPeer.ToStringIP()));
-     obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
-     obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
      obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
-     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
      obj.push_back(Pair("testnet",       fTestNet));
      obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
      obj.push_back(Pair("keypoolsize",   pwalletMain->GetKeyPoolSize()));
      obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
      if (pwalletMain->IsCrypted())
-         obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
+         obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
+     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
+     return obj;
+ }
+ Value getmininginfo(const Array& params, bool fHelp)
+ {
+     if (fHelp || params.size() != 0)
+         throw runtime_error(
+             "getmininginfo\n"
+             "Returns an object containing mining-related information.");
+     Object obj;
+     obj.push_back(Pair("blocks",        (int)nBestHeight));
+     obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
+     obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
+     obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
      obj.push_back(Pair("errors",        GetWarnings("statusbar")));
+     obj.push_back(Pair("generate",      GetBoolArg("-gen")));
+     obj.push_back(Pair("genproclimit",  (int)GetArg("-genproclimit", -1)));
+     obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
+     obj.push_back(Pair("pooledtx",      (uint64_t)mempool.size()));
+     obj.push_back(Pair("testnet",       fTestNet));
      return obj;
  }
  
@@@ -335,7 -379,7 +384,7 @@@ Value getnewaddress(const Array& params
      if (fHelp || params.size() > 1)
          throw runtime_error(
              "getnewaddress [account]\n"
 -            "Returns a new bitcoin address for receiving payments.  "
 +            "Returns a new ppcoin address for receiving payments.  "
              "If [account] is specified (recommended), it is added to the address book "
              "so payments received with the address will be credited to [account].");
  
@@@ -402,7 -446,7 +451,7 @@@ Value getaccountaddress(const Array& pa
      if (fHelp || params.size() != 1)
          throw runtime_error(
              "getaccountaddress <account>\n"
 -            "Returns the current bitcoin address for receiving payments to this account.");
 +            "Returns the current ppcoin address for receiving payments to this account.");
  
      // Parse the account first so we don't generate a key if there's an error
      string strAccount = AccountFromValue(params[0]);
@@@ -420,12 -464,12 +469,12 @@@ Value setaccount(const Array& params, b
  {
      if (fHelp || params.size() < 1 || params.size() > 2)
          throw runtime_error(
 -            "setaccount <bitcoinaddress> <account>\n"
 +            "setaccount <ppcoinaddress> <account>\n"
              "Sets the account associated with the given address.");
  
      CBitcoinAddress address(params[0].get_str());
      if (!address.IsValid())
 -        throw JSONRPCError(-5, "Invalid bitcoin address");
 +        throw JSONRPCError(-5, "Invalid ppcoin address");
  
  
      string strAccount;
@@@ -450,12 -494,12 +499,12 @@@ Value getaccount(const Array& params, b
  {
      if (fHelp || params.size() != 1)
          throw runtime_error(
 -            "getaccount <bitcoinaddress>\n"
 +            "getaccount <ppcoinaddress>\n"
              "Returns the account associated with the given address.");
  
      CBitcoinAddress address(params[0].get_str());
      if (!address.IsValid())
 -        throw JSONRPCError(-5, "Invalid bitcoin address");
 +        throw JSONRPCError(-5, "Invalid ppcoin address");
  
      string strAccount;
      map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
@@@ -488,14 -532,17 +537,14 @@@ Value getaddressesbyaccount(const Array
  
  Value settxfee(const Array& params, bool fHelp)
  {
 -    if (fHelp || params.size() < 1 || params.size() > 1)
 +    if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
          throw runtime_error(
              "settxfee <amount>\n"
 -            "<amount> is a real and is rounded to the nearest 0.00000001");
 +            "<amount> is a real and is rounded to 0.01 (cent)\n"
 +            "Minimum and default transaction fee per KB is 1 cent");
  
 -    // Amount
 -    int64 nAmount = 0;
 -    if (params[0].get_real() != 0.0)
 -        nAmount = AmountFromValue(params[0]);        // rejects 0.0 amounts
 -
 -    nTransactionFee = nAmount;
 +    nTransactionFee = AmountFromValue(params[0]);
 +    nTransactionFee = (nTransactionFee / CENT) * CENT;  // round to cent
      return true;
  }
  
@@@ -503,17 -550,17 +552,17 @@@ Value sendtoaddress(const Array& params
  {
      if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
          throw runtime_error(
 -            "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
 -            "<amount> is a real and is rounded to the nearest 0.00000001\n"
 +            "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
 +            "<amount> is a real and is rounded to the nearest 0.000001\n"
              "requires wallet passphrase to be set with walletpassphrase first");
      if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
          throw runtime_error(
 -            "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
 -            "<amount> is a real and is rounded to the nearest 0.00000001");
 +            "sendtoaddress <ppcoinaddress> <amount> [comment] [comment-to]\n"
 +            "<amount> is a real and is rounded to the nearest 0.000001");
  
      CBitcoinAddress address(params[0].get_str());
      if (!address.IsValid())
 -        throw JSONRPCError(-5, "Invalid bitcoin address");
 +        throw JSONRPCError(-5, "Invalid ppcoin address");
  
      // Amount
      int64 nAmount = AmountFromValue(params[1]);
      return wtx.GetHash().GetHex();
  }
  
- static const string strMessageMagic = "Bitcoin Signed Message:\n";
  Value signmessage(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 2)
          throw runtime_error(
 -            "signmessage <bitcoinaddress> <message>\n"
 +            "signmessage <ppcoinaddress> <message>\n"
              "Sign a message with the private key of an address");
  
      if (pwalletMain->IsLocked())
      if (!pwalletMain->GetKey(addr, key))
          throw JSONRPCError(-4, "Private key not available");
  
-     CDataStream ss(SER_GETHASH);
+     CDataStream ss(SER_GETHASH, 0);
      ss << strMessageMagic;
      ss << strMessage;
  
@@@ -573,7 -618,7 +620,7 @@@ Value verifymessage(const Array& params
  {
      if (fHelp || params.size() != 3)
          throw runtime_error(
 -            "verifymessage <bitcoinaddress> <signature> <message>\n"
 +            "verifymessage <ppcoinaddress> <signature> <message>\n"
              "Verify a signed message");
  
      string strAddress  = params[0].get_str();
      if (fInvalid)
          throw JSONRPCError(-5, "Malformed base64 encoding");
  
-     CDataStream ss(SER_GETHASH);
+     CDataStream ss(SER_GETHASH, 0);
      ss << strMessageMagic;
      ss << strMessage;
  
      if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
          return false;
  
-     return (key.GetAddress() == addr);
+     return (CBitcoinAddress(key.GetPubKey()) == addr);
  }
  
  
@@@ -606,14 -651,14 +653,14 @@@ Value getreceivedbyaddress(const Array
  {
      if (fHelp || params.size() < 1 || params.size() > 2)
          throw runtime_error(
 -            "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
 -            "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
 +            "getreceivedbyaddress <ppcoinaddress> [minconf=1]\n"
 +            "Returns the total amount received by <ppcoinaddress> in transactions with at least [minconf] confirmations.");
  
      // Bitcoin address
      CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
      CScript scriptPubKey;
      if (!address.IsValid())
 -        throw JSONRPCError(-5, "Invalid bitcoin address");
 +        throw JSONRPCError(-5, "Invalid ppcoin address");
      scriptPubKey.SetBitcoinAddress(address);
      if (!IsMine(*pwalletMain,scriptPubKey))
          return (double)0.0;
      for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
      {
          const CWalletTx& wtx = (*it).second;
 -        if (wtx.IsCoinBase() || !wtx.IsFinal())
 +        if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
              continue;
  
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
@@@ -665,7 -710,7 +712,7 @@@ Value getreceivedbyaccount(const Array
      if (params.size() > 1)
          nMinDepth = params[1].get_int();
  
-     // Get the set of pub keys that have the label
+     // Get the set of pub keys assigned to account
      string strAccount = AccountFromValue(params[0]);
      set<CBitcoinAddress> setAddress;
      GetAccountAddresses(strAccount, setAddress);
      for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
      {
          const CWalletTx& wtx = (*it).second;
 -        if (wtx.IsCoinBase() || !wtx.IsFinal())
 +        if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
              continue;
  
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
              CBitcoinAddress address;
-             if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
+             if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
                  if (wtx.GetDepthInMainChain() >= nMinDepth)
                      nAmount += txout.nValue;
          }
@@@ -756,8 -801,10 +803,10 @@@ Value getbalance(const Array& params, b
              list<pair<CBitcoinAddress, int64> > listSent;
              wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
              if (wtx.GetDepthInMainChain() >= nMinDepth)
+             {
                  BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
                      nBalance += r.second;
+             }
              BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
                  nBalance -= r.second;
              nBalance -= allFee;
@@@ -792,7 -839,8 +841,8 @@@ Value movecmd(const Array& params, boo
          strComment = params[4].get_str();
  
      CWalletDB walletdb(pwalletMain->strWalletFile);
-     walletdb.TxnBegin();
+     if (!walletdb.TxnBegin())
+         throw JSONRPCError(-20, "database error");
  
      int64 nNow = GetAdjustedTime();
  
      credit.strComment = strComment;
      walletdb.WriteAccountingEntry(credit);
  
-     walletdb.TxnCommit();
+     if (!walletdb.TxnCommit())
+         throw JSONRPCError(-20, "database error");
  
      return true;
  }
@@@ -824,18 -873,18 +875,18 @@@ Value sendfrom(const Array& params, boo
  {
      if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
          throw runtime_error(
 -            "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
 -            "<amount> is a real and is rounded to the nearest 0.00000001\n"
 +            "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
 +            "<amount> is a real and is rounded to the nearest 0.000001\n"
              "requires wallet passphrase to be set with walletpassphrase first");
      if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
          throw runtime_error(
 -            "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
 -            "<amount> is a real and is rounded to the nearest 0.00000001");
 +            "sendfrom <fromaccount> <toppcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
 +            "<amount> is a real and is rounded to the nearest 0.000001");
  
      string strAccount = AccountFromValue(params[0]);
      CBitcoinAddress address(params[1].get_str());
      if (!address.IsValid())
 -        throw JSONRPCError(-5, "Invalid bitcoin address");
 +        throw JSONRPCError(-5, "Invalid ppcoin address");
      int64 nAmount = AmountFromValue(params[2]);
      int nMinDepth = 1;
      if (params.size() > 3)
@@@ -896,7 -945,7 +947,7 @@@ Value sendmany(const Array& params, boo
      {
          CBitcoinAddress address(s.name_);
          if (!address.IsValid())
 -            throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
 +            throw JSONRPCError(-5, string("Invalid ppcoin address:")+s.name_);
  
          if (setAddress.count(address))
              throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
  
      if (pwalletMain->IsLocked())
          throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
 +    if (fWalletUnlockStakeOnly)
 +        throw JSONRPCError(-13, "Error: Wallet unlocked for coinstake only.");
  
      // Check funds
      int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
      return wtx.GetHash().GetHex();
  }
  
+ Value addmultisigaddress(const Array& params, bool fHelp)
+ {
+     if (fHelp || params.size() < 2 || params.size() > 3)
+     {
+         string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
+             "Add a nrequired-to-sign multisignature address to the wallet\"\n"
+             "each key is a bitcoin address or hex-encoded public key\n"
+             "If [account] is specified, assign address to [account].";
+         throw runtime_error(msg);
+     }
+     int nRequired = params[0].get_int();
+     const Array& keys = params[1].get_array();
+     string strAccount;
+     if (params.size() > 2)
+         strAccount = AccountFromValue(params[2]);
+     // Gather public keys
+     if (nRequired < 1)
+         throw runtime_error("a multisignature address must require at least one key to redeem");
+     if ((int)keys.size() < nRequired)
+         throw runtime_error(
+             strprintf("not enough keys supplied "
+                       "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
+     std::vector<CKey> pubkeys;
+     pubkeys.resize(keys.size());
+     for (unsigned int i = 0; i < keys.size(); i++)
+     {
+         const std::string& ks = keys[i].get_str();
+         // Case 1: bitcoin address and we have full public key:
+         CBitcoinAddress address(ks);
+         if (address.IsValid())
+         {
+             if (address.IsScript())
+                 throw runtime_error(
+                     strprintf("%s is a pay-to-script address",ks.c_str()));
+             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
+         else if (IsHex(ks))
+         {
+             vector<unsigned char> vchPubKey = ParseHex(ks);
+             if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
+                 throw runtime_error(" Invalid public key: "+ks);
+         }
+         else
+         {
+             throw runtime_error(" Invalid public key: "+ks);
+         }
+     }
+     // Construct using pay-to-script-hash:
+     CScript inner;
+     inner.SetMultisig(nRequired, pubkeys);
+     uint160 scriptHash = Hash160(inner);
+     CScript scriptPubKey;
+     scriptPubKey.SetPayToScriptHash(inner);
+     pwalletMain->AddCScript(inner);
+     CBitcoinAddress address;
+     address.SetScriptHash160(scriptHash);
+     pwalletMain->SetAddressBookName(address, strAccount);
+     return address.ToString();
+ }
  
  struct tallyitem
  {
      tallyitem()
      {
          nAmount = 0;
-         nConf = INT_MAX;
+         nConf = std::numeric_limits<int>::max();
      }
  };
  
@@@ -965,7 -1085,8 +1089,8 @@@ Value ListReceived(const Array& params
      for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
      {
          const CWalletTx& wtx = (*it).second;
 -        if (wtx.IsCoinBase() || !wtx.IsFinal())
 +        if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
              continue;
  
          int nDepth = wtx.GetDepthInMainChain();
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
              CBitcoinAddress address;
-             if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
+             if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
                  continue;
  
              tallyitem& item = mapTally[address];
              continue;
  
          int64 nAmount = 0;
-         int nConf = INT_MAX;
+         int nConf = std::numeric_limits<int>::max();
          if (it != mapTally.end())
          {
              nAmount = (*it).second.nAmount;
              obj.push_back(Pair("address",       address.ToString()));
              obj.push_back(Pair("account",       strAccount));
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
-             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
+             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
              ret.push_back(obj);
          }
      }
              Object obj;
              obj.push_back(Pair("account",       (*it).first));
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
-             obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
+             obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
              ret.push_back(obj);
          }
      }
@@@ -1074,6 -1195,7 +1199,7 @@@ void ListTransactions(const CWalletTx& 
      string strSentAccount;
      list<pair<CBitcoinAddress, int64> > listReceived;
      list<pair<CBitcoinAddress, int64> > listSent;
      wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
  
      bool fAllAccounts = (strAccount == string("*"));
  
      // Received
      if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
+     {
          BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
          {
              string account;
                  ret.push_back(entry);
              }
          }
+     }
  }
  
  void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
@@@ -1170,14 -1294,21 +1298,21 @@@ Value listtransactions(const Array& par
      if (params.size() > 2)
          nFrom = params[2].get_int();
  
+     if (nCount < 0)
+         throw JSONRPCError(-8, "Negative count");
+     if (nFrom < 0)
+         throw JSONRPCError(-8, "Negative from");
      Array ret;
      CWalletDB walletdb(pwalletMain->strWalletFile);
  
-     // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
+     // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
      typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
      typedef multimap<int64, TxPair > TxItems;
      TxItems txByTime;
  
+     // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
+     // would make this much faster for applications that do this a lot.
      for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
      {
          CWalletTx* wtx = &((*it).second);
          txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
      }
  
-     // Now: iterate backwards until we have nCount items to return:
-     TxItems::reverse_iterator it = txByTime.rbegin();
-     if (txByTime.size() > nFrom) std::advance(it, nFrom);
-     for (; it != txByTime.rend(); ++it)
+     // iterate backwards until we have nCount items to return:
+     for (TxItems::reverse_iterator it = txByTime.rbegin(); it != txByTime.rend(); ++it)
      {
          CWalletTx *const pwtx = (*it).second.first;
          if (pwtx != 0)
          if (pacentry != 0)
              AcentryToJSON(*pacentry, strAccount, ret);
  
-         if (ret.size() >= nCount) break;
+         if (ret.size() >= (nCount+nFrom)) break;
      }
-     // ret is now newest to oldest
+     // ret is newest to oldest
      
-     // Make sure we return only last nCount items (sends-to-self might give us an extra):
-     if (ret.size() > nCount)
-     {
-         Array::iterator last = ret.begin();
-         std::advance(last, nCount);
-         ret.erase(last, ret.end());
-     }
-     std::reverse(ret.begin(), ret.end()); // oldest to newest
+     if (nFrom > (int)ret.size())
+         nFrom = ret.size();
+     if ((nFrom + nCount) > (int)ret.size())
+         nCount = ret.size() - nFrom;
+     Array::iterator first = ret.begin();
+     std::advance(first, nFrom);
+     Array::iterator last = ret.begin();
+     std::advance(last, nFrom+nCount);
+     if (last != ret.end()) ret.erase(last, ret.end());
+     if (first != ret.begin()) ret.erase(ret.begin(), first);
+     std::reverse(ret.begin(), ret.end()); // Return oldest to newest
  
      return ret;
  }
@@@ -1273,8 -1407,8 +1411,8 @@@ Value listsinceblock(const Array& param
  {
      if (fHelp)
          throw runtime_error(
-             "listsinceblock [blockid] [target-confirmations]\n"
-             "Get all transactions in blocks since block [blockid], or all transactions if omitted");
+             "listsinceblock [blockhash] [target-confirmations]\n"
+             "Get all transactions in blocks since block [blockhash], or all transactions if omitted");
  
      CBlockIndex *pindex = NULL;
      int target_confirms = 1;
  
      if (target_confirms == 1)
      {
-         printf("oops!\n");
          lastblock = hashBestChain;
      }
      else
          CBlockIndex *block;
          for (block = pindexBest;
               block && block->nHeight > target_height;
-              block = block->pprev);
+              block = block->pprev)  { }
  
          lastblock = block ? block->GetBlockHash() : 0;
      }
@@@ -1412,53 -1545,58 +1549,59 @@@ void ThreadTopUpKeyPool(void* parg
  
  void ThreadCleanWalletPassphrase(void* parg)
  {
-     int64 nMyWakeTime = GetTime() + *((int*)parg);
+     int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000;
+     ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
  
      if (nWalletUnlockTime == 0)
      {
-         CRITICAL_BLOCK(cs_nWalletUnlockTime)
+         nWalletUnlockTime = nMyWakeTime;
+         do
          {
-             nWalletUnlockTime = nMyWakeTime;
-         }
+             if (nWalletUnlockTime==0)
+                 break;
+             int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
+             if (nToSleep <= 0)
+                 break;
+             LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
+             Sleep(nToSleep);
+             ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
  
-         while (GetTime() < nWalletUnlockTime)
-             Sleep(GetTime() - nWalletUnlockTime);
+         } while(1);
  
-         CRITICAL_BLOCK(cs_nWalletUnlockTime)
+         if (nWalletUnlockTime)
          {
              nWalletUnlockTime = 0;
+             pwalletMain->Lock();
          }
      }
      else
      {
-         CRITICAL_BLOCK(cs_nWalletUnlockTime)
-         {
-             if (nWalletUnlockTime < nMyWakeTime)
-                 nWalletUnlockTime = nMyWakeTime;
-         }
-         free(parg);
-         return;
+         if (nWalletUnlockTime < nMyWakeTime)
+             nWalletUnlockTime = nMyWakeTime;
      }
  
-     pwalletMain->Lock();
+     LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
  
-     delete (int*)parg;
+     delete (int64*)parg;
  }
  
  Value walletpassphrase(const Array& params, bool fHelp)
  {
 -    if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
 +    if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3))
          throw runtime_error(
 -            "walletpassphrase <passphrase> <timeout>\n"
 -            "Stores the wallet decryption key in memory for <timeout> seconds.");
 +            "walletpassphrase <passphrase> <timeout> [stakeonly]\n"
 +            "Stores the wallet decryption key in memory for <timeout> seconds.\n"
 +            "stakeonly is optional true/false allowing only stake creation.");
      if (fHelp)
          return true;
      if (!pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
  
      if (!pwalletMain->IsLocked())
 -        throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
 +        throw JSONRPCError(-17, "Error: Wallet is already unlocked, use walletlock first if need to change unlock settings.");
  
      // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
      SecureString strWalletPass;
              "Stores the wallet decryption key in memory for <timeout> seconds.");
  
      CreateThread(ThreadTopUpKeyPool, NULL);
-     int* pnSleepTime = new int(params[1].get_int());
+     int64* pnSleepTime = new int64(params[1].get_int64());
      CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
  
 +    // ppcoin: if user OS account compromised prevent trivial sendmoney commands
 +    if (params.size() > 2)
 +        fWalletUnlockStakeOnly = params[2].get_bool();
 +    else
 +        fWalletUnlockStakeOnly = false;
 +
      return Value::null;
  }
  
@@@ -1537,9 -1669,9 +1680,9 @@@ Value walletlock(const Array& params, b
      if (!pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
  
-     pwalletMain->Lock();
-     CRITICAL_BLOCK(cs_nWalletUnlockTime)
      {
+         LOCK(cs_nWalletUnlockTime);
+         pwalletMain->Lock();
          nWalletUnlockTime = 0;
      }
  
@@@ -1558,11 -1690,6 +1701,6 @@@ Value encryptwallet(const Array& params
      if (pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
  
- #ifdef QT_GUI
-     // shutting down via RPC while the GUI is running does not work (yet):
-     throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
- #endif
      // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
      // Alternately, find a way to make params[0] mlock()'d to begin with.
      SecureString strWalletPass;
      // BDB seems to have a bad habit of writing old data into
      // slack space in .dat files; that is bad if the old data is
      // unencrypted private keys.  So:
-     CreateThread(Shutdown, NULL);
+     StartShutdown();
 -    return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
 +    return "wallet encrypted; ppcoin server stopping, restart to run with encrypted wallet";
  }
  
  
@@@ -1589,8 -1716,8 +1727,8 @@@ Value validateaddress(const Array& para
  {
      if (fHelp || params.size() != 1)
          throw runtime_error(
 -            "validateaddress <bitcoinaddress>\n"
 -            "Return information about <bitcoinaddress>.");
 +            "validateaddress <ppcoinaddress>\n"
 +            "Return information about <ppcoinaddress>.");
  
      CBitcoinAddress address(params[0].get_str());
      bool isValid = address.IsValid();
          // version of the address:
          string currentAddress = address.ToString();
          ret.push_back(Pair("address", currentAddress));
-         ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
+         if (pwalletMain->HaveKey(address))
+         {
+             ret.push_back(Pair("ismine", true));
+             std::vector<unsigned char> vchPubKey;
+             pwalletMain->GetPubKey(address, vchPubKey);
+             ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
+             CKey key;
+             key.SetPubKey(vchPubKey);
+             ret.push_back(Pair("iscompressed", key.IsCompressed()));
+         }
+         else if (pwalletMain->HaveCScript(address.GetHash160()))
+         {
+             ret.push_back(Pair("isscript", true));
+             CScript subscript;
+             pwalletMain->GetCScript(address.GetHash160(), subscript);
+             ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
+             std::vector<CBitcoinAddress> addresses;
+             txnouttype whichType;
+             int nRequired;
+             ExtractAddresses(subscript, whichType, addresses, nRequired);
+             ret.push_back(Pair("script", GetTxnOutputType(whichType)));
+             Array a;
+             BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
+                 a.push_back(addr.ToString());
+             ret.push_back(Pair("addresses", a));
+             if (whichType == TX_MULTISIG)
+                 ret.push_back(Pair("sigsrequired", nRequired));
+         }
+         else
+             ret.push_back(Pair("ismine", false));
          if (pwalletMain->mapAddressBook.count(address))
              ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
      }
      return ret;
  }
  
  Value getwork(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() > 1)
              "If [data] is specified, tries to solve the block and returns true if it was successful.");
  
      if (vNodes.empty())
 -        throw JSONRPCError(-9, "Bitcoin is not connected!");
 +        throw JSONRPCError(-9, "PPCoin is not connected!");
  
      if (IsInitialBlockDownload())
 -        throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
 +        throw JSONRPCError(-10, "PPCoin is downloading blocks...");
  
      typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
      static mapNewBlock_t mapNewBlock;
              nStart = GetTime();
  
              // Create new block
 -            pblock = CreateNewBlock(reservekey);
 +            pblock = CreateNewBlock(pwalletMain, true);
              if (!pblock)
                  throw JSONRPCError(-7, "Out of memory");
              vNewBlock.push_back(pblock);
          }
  
          // Update nTime
-         pblock->nTime = max(pblock->GetBlockTime(), GetAdjustedTime());
+         pblock->UpdateTime(pindexPrev);
          pblock->nNonce = 0;
  
          // Update nExtraNonce
          pblock->nNonce = pdata->nNonce;
          pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
          pblock->hashMerkleRoot = pblock->BuildMerkleTree();
 +        if (!pblock->SignBlock(*pwalletMain))
 +            throw JSONRPCError(-100, "Unable to sign block");
  
          return CheckWork(pblock, *pwalletMain, reservekey);
      }
@@@ -1728,17 -1881,20 +1894,20 @@@ Value getmemorypool(const Array& params
              "  \"previousblockhash\" : hash of current highest block\n"
              "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
              "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
+             "  \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
              "  \"time\" : timestamp appropriate for next block\n"
+             "  \"mintime\" : minimum timestamp appropriate for next block\n"
+             "  \"curtime\" : current timestamp\n"
              "  \"bits\" : compressed target of next block\n"
              "If [data] is specified, tries to solve the block and returns true if it was successful.");
  
      if (params.size() == 0)
      {
          if (vNodes.empty())
 -            throw JSONRPCError(-9, "Bitcoin is not connected!");
 +            throw JSONRPCError(-9, "PPCoin is not connected!");
  
          if (IsInitialBlockDownload())
 -            throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
 +            throw JSONRPCError(-10, "PPCoin is downloading blocks...");
  
          static CReserveKey reservekey(pwalletMain);
  
              // Create new block
              if(pblock)
                  delete pblock;
 -            pblock = CreateNewBlock(reservekey);
 +            pblock = CreateNewBlock(pwalletMain);
              if (!pblock)
                  throw JSONRPCError(-7, "Out of memory");
          }
  
          // Update nTime
-         pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+         pblock->UpdateTime(pindexPrev);
          pblock->nNonce = 0;
  
          Array transactions;
          BOOST_FOREACH(CTransaction tx, pblock->vtx) {
 -            if(tx.IsCoinBase())
 +            if(tx.IsCoinBase() || tx.IsCoinStake())
                  continue;
  
-             CDataStream ssTx;
+             CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
              ssTx << tx;
  
              transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
          result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
          result.push_back(Pair("transactions", transactions));
          result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
+         result.push_back(Pair("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
          result.push_back(Pair("time", (int64_t)pblock->nTime));
-         union {
-             int32_t nBits;
-             char cBits[4];
-         } uBits;
-         uBits.nBits = htonl((int32_t)pblock->nBits);
-         result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
+         result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
+         result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
+         result.push_back(Pair("bits", HexBits(pblock->nBits)));
  
          return result;
      }
      else
      {
          // Parse parameters
-         CDataStream ssBlock(ParseHex(params[0].get_str()));
+         CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
          CBlock pblock;
          ssBlock >> pblock;
  
      }
  }
  
+ Value getblockhash(const Array& params, bool fHelp)
+ {
+     if (fHelp || params.size() != 1)
+         throw runtime_error(
+             "getblockhash <index>\n"
+             "Returns hash of block in best-block-chain at <index>.");
+     int nHeight = params[0].get_int();
+     if (nHeight < 0 || nHeight > nBestHeight)
+         throw runtime_error("Block number out of range.");
+     CBlock block;
+     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
+     while (pblockindex->nHeight > nHeight)
+         pblockindex = pblockindex->pprev;
+     return pblockindex->phashBlock->GetHex();
+ }
+ Value getblock(const Array& params, bool fHelp)
+ {
+     if (fHelp || params.size() != 1)
+         throw runtime_error(
+             "getblock <hash>\n"
+             "Returns details of a block with given block-hash.");
+     std::string strHash = params[0].get_str();
+     uint256 hash(strHash);
+     if (mapBlockIndex.count(hash) == 0)
+         throw JSONRPCError(-5, "Block not found");
+     CBlock block;
+     CBlockIndex* pblockindex = mapBlockIndex[hash];
+     block.ReadFromDisk(pblockindex, true);
+     return blockToJSON(block, pblockindex);
+ }
  
 +// ppcoin: get information of sync-checkpoint
 +Value getcheckpoint(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 0)
 +        throw runtime_error(
 +            "getcheckpoint\n"
 +            "Show info of synchronized checkpoint.\n");
 +
 +    Object result;
 +    CBlockIndex* pindexCheckpoint;
 +    
 +    result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
 +    pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];        
 +    result.push_back(Pair("height", pindexCheckpoint->nHeight));
 +    result.push_back(Pair("timestamp", DateTimeStrFormat("%x %H:%M:%S", pindexCheckpoint->GetBlockTime()).c_str()));
 +    
 +    return result;
 +}
 +
 +
 +// ppcoin: reserve balance from being staked for network protection
 +Value reservebalance(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() > 2)
 +        throw runtime_error(
 +            "reservebalance [<reserve> [amount]]\n"
 +            "<reserve> is true or false to turn balance reserve on or off.\n"
 +            "<amount> is a real and rounded to cent.\n"
 +            "Set reserve amount not participating in network protection.\n"
 +            "If no parameters provided current setting is printed.\n");
 +
 +    if (params.size() > 0)
 +    {
 +        bool fReserve = params[0].get_bool();
 +        if (fReserve)
 +        {
 +            if (params.size() == 1)
 +                throw runtime_error("must provide amount to reserve balance.\n");
 +            int64 nAmount = AmountFromValue(params[1]);
 +            nAmount = (nAmount / CENT) * CENT;  // round to cent
 +            if (nAmount < 0)
 +                throw runtime_error("amount cannot be negative.\n");
-             WriteSetting("nBalanceReserve", nBalanceReserve = nAmount);
++            // TODO: handle persistence of nBalanceReserve
++            // settings removed since bitcoin 0.6
++            // WriteSetting("nBalanceReserve", nBalanceReserve = nAmount);
++            nBalanceReserve = nAmount;
 +        }
 +        else
 +        {
 +            if (params.size() > 1)
 +                throw runtime_error("cannot specify amount to turn off reserve.\n");
-             WriteSetting("nBalanceReserve", nBalanceReserve = 0);
++            // TODO: handle persistence of nBalanceReserve
++            // settings removed since bitcoin 0.6
++            // WriteSetting("nBalanceReserve", nBalanceReserve = 0);
++            nBalanceReserve = 0;
 +        }
 +    }
 +
 +    Object result;
 +    result.push_back(Pair("reserve", (nBalanceReserve > 0)));
 +    result.push_back(Pair("amount", ValueFromAmount(nBalanceReserve)));
 +    return result;
 +}
 +
 +
 +// ppcoin: check wallet integrity
 +Value checkwallet(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() > 0)
 +        throw runtime_error(
 +            "checkwallet\n"
 +            "Check wallet for integrity.\n");
 +
 +    int nMismatchSpent;
 +    int64 nBalanceInQuestion;
 +    if (!pwalletMain->CheckSpentCoins(nMismatchSpent, nBalanceInQuestion))
 +    {
 +        Object result;
 +        result.push_back(Pair("mismatched spent coins", nMismatchSpent));
 +        result.push_back(Pair("amount in question", ValueFromAmount(nBalanceInQuestion)));
 +        return result;
 +    }
 +    return Value::null;
 +}
 +
 +
 +// ppcoin: repair wallet
 +Value repairwallet(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() > 0)
 +        throw runtime_error(
 +            "repairwallet\n"
 +            "Repair wallet if checkwallet reports any problem.\n");
 +
 +    int nMismatchSpent;
 +    int64 nBalanceInQuestion;
 +    pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
 +    Object result;
 +    if (nMismatchSpent == 0)
 +    {
 +        result.push_back(Pair("wallet check passed", true));
 +    }
 +    else
 +    {
 +        result.push_back(Pair("mismatched spent coins", nMismatchSpent));
 +        result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
 +    }
 +    return result;
 +}
 +
 +// ppcoin: make a public-private key pair
 +Value makekeypair(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() > 1)
 +        throw runtime_error(
 +            "makekeypair [prefix]\n"
 +            "Make a public/private key pair.\n"
 +            "[prefix] is optional preferred prefix for the public key.\n");
 +
 +    string strPrefix = "";
 +    if (params.size() > 0)
 +        strPrefix = params[0].get_str();
 + 
 +    CKey key;
 +    int nCount = 0;
 +    do
 +    {
-         key.MakeNewKey();
++        key.MakeNewKey(false);
 +        nCount++;
 +    } while (nCount < 10000 && strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()));
 +
 +    if (strPrefix != HexStr(key.GetPubKey()).substr(0, strPrefix.size()))
 +        return Value::null;
 +
 +    CPrivKey vchPrivKey = key.GetPrivKey();
 +    Object result;
 +    result.push_back(Pair("PrivateKey", HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end())));
 +    result.push_back(Pair("PublicKey", HexStr(key.GetPubKey())));
 +    return result;
 +}
 +
 +extern CCriticalSection cs_mapAlerts;
 +extern map<uint256, CAlert> mapAlerts;
 +
 +// ppcoin: send alert.  
 +// There is a known deadlock situation with ThreadMessageHandler
 +// ThreadMessageHandler: holds cs_vSend and acquiring cs_main in SendMessages()
 +// ThreadRPCServer: holds cs_main and acquiring cs_vSend in alert.RelayTo()/PushMessage()/BeginMessage()
 +Value sendalert(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() < 5)
 +      throw runtime_error(
 +            "sendalert <message> <privatekey> <minver> <maxver> <id> [cancelupto]\n"
 +            "<message> is the alert text message\n"
 +            "<privatekey> is hex string of alert master private key\n"
 +            "<minver> is the minimum applicable client version\n"
 +            "<maxver> is the maximum applicable client version\n"
 +            "<id> is the alert id\n"
 +            "[cancelupto] cancels all alert id's up to this number\n"
 +            "Returns true or false.");    
 +
 +    CAlert alert;
 +    CKey key;
 +
 +    alert.strStatusBar = params[0].get_str();
 +    alert.nMinVer = params[2].get_int();
 +    alert.nMaxVer = params[3].get_int();
 +    alert.nID = params[4].get_int();
 +    if (params.size() > 5)
 +        alert.nCancel = params[5].get_int();
-     alert.nVersion = VERSION;
++    alert.nVersion = PROTOCOL_VERSION;
 +    alert.nRelayUntil = GetAdjustedTime() + 365*24*60*60;
 +    alert.nExpiration = GetAdjustedTime() + 365*24*60*60;
 +    alert.nPriority = 1;
 +
-     CDataStream sMsg;
++    CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
 +    sMsg << (CUnsignedAlert)alert;
 +    alert.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
 +    
 +    vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
 +    key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
 +    if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
 +        throw runtime_error(
 +            "Unable to sign alert, check private key?\n");  
 +    if(!alert.ProcessAlert()) 
 +        throw runtime_error(
 +            "Failed to process alert.\n");
 +    // Relay alert
-     CRITICAL_BLOCK(cs_vNodes)
++    {
++        LOCK(cs_vNodes);
 +        BOOST_FOREACH(CNode* pnode, vNodes)
 +            alert.RelayTo(pnode);
++    }
  
 +    Object result;
 +    result.push_back(Pair("strStatusBar", alert.strStatusBar));
 +    result.push_back(Pair("nVersion", alert.nVersion));
 +    result.push_back(Pair("nMinVer", alert.nMinVer));
 +    result.push_back(Pair("nMaxVer", alert.nMaxVer));
 +    result.push_back(Pair("nID", alert.nID));
 +    if (alert.nCancel > 0)
 +        result.push_back(Pair("nCancel", alert.nCancel));
 +    return result;
 +}
 +
 +// ppcoin: send checkpoint
 +Value sendcheckpoint(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() > 2 || params.size() < 1 )
 +        throw runtime_error(
 +            "sendcheckpoint <privatekey> [checkpointhash]\n"
 +            "<privatekey> is hex string of checkpoint master private key\n"
 +            "<checkpointhash> is the hash of checkpoint block\n");
  
 +    CSyncCheckpoint checkpoint;
 +    CKey key;
  
 +    // TODO: omit checkpointhash parameter
 +    if (params.size() > 1)
 +    {
 +        checkpoint.hashCheckpoint = uint256(params[1].get_str());
 +        if (!mapBlockIndex.count(checkpoint.hashCheckpoint))
 +            throw runtime_error(
 +                "Provided checkpoint block is not on main chain\n");
 +    }
 +    else
 +    {
 +        checkpoint.hashCheckpoint = Checkpoints::AutoSelectSyncCheckpoint();
 +        if (checkpoint.hashCheckpoint == Checkpoints::hashSyncCheckpoint)
 +            throw runtime_error(
 +                "Unable to select a more recent sync-checkpoint");
 +    }
  
-     CDataStream sMsg;
++    CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
 +    sMsg << (CUnsignedSyncCheckpoint)checkpoint;
 +    checkpoint.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
  
 +    vector<unsigned char> vchPrivKey = ParseHex(params[0].get_str());
 +    key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
 +    if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
 +        throw runtime_error(
 +            "Unable to sign checkpoint, check private key?\n");
  
 +    if(!checkpoint.ProcessSyncCheckpoint(NULL))
 +        throw runtime_error(
 +            "Failed to process checkpoint.\n");
 +    // Relay checkpoint
-     CRITICAL_BLOCK(cs_vNodes)
++    {
++        LOCK(cs_vNodes);
 +        BOOST_FOREACH(CNode* pnode, vNodes)
 +            checkpoint.RelayTo(pnode);
++    }
  
 +    Object result;
 +    result.push_back(Pair("checkpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
 +    result.push_back(Pair("height", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->nHeight));
 +    result.push_back(Pair("timestamp", DateTimeStrFormat("%x %H:%M:%S", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->GetBlockTime()).c_str()));
 +    return result;
 +}
  
  
  //
  // Call Table
  //
  
- pair<string, rpcfn_type> pCallTable[] =
- {
-     make_pair("help",                   &help),
-     make_pair("stop",                   &stop),
-     make_pair("getblockcount",          &getblockcount),
-     make_pair("getblocknumber",         &getblocknumber),
-     make_pair("getconnectioncount",     &getconnectioncount),
-     make_pair("getdifficulty",          &getdifficulty),
-     make_pair("getgenerate",            &getgenerate),
-     make_pair("setgenerate",            &setgenerate),
-     make_pair("gethashespersec",        &gethashespersec),
-     make_pair("getinfo",                &getinfo),
-     make_pair("getnewaddress",          &getnewaddress),
-     make_pair("getaccountaddress",      &getaccountaddress),
-     make_pair("setaccount",             &setaccount),
-     make_pair("getaccount",             &getaccount),
-     make_pair("getaddressesbyaccount",  &getaddressesbyaccount),
-     make_pair("sendtoaddress",          &sendtoaddress),
-     make_pair("getreceivedbyaddress",   &getreceivedbyaddress),
-     make_pair("getreceivedbyaccount",   &getreceivedbyaccount),
-     make_pair("listreceivedbyaddress",  &listreceivedbyaddress),
-     make_pair("listreceivedbyaccount",  &listreceivedbyaccount),
-     make_pair("backupwallet",           &backupwallet),
-     make_pair("keypoolrefill",          &keypoolrefill),
-     make_pair("walletpassphrase",       &walletpassphrase),
-     make_pair("walletpassphrasechange", &walletpassphrasechange),
-     make_pair("walletlock",             &walletlock),
-     make_pair("encryptwallet",          &encryptwallet),
-     make_pair("validateaddress",        &validateaddress),
-     make_pair("getbalance",             &getbalance),
-     make_pair("move",                   &movecmd),
-     make_pair("sendfrom",               &sendfrom),
-     make_pair("sendmany",               &sendmany),
-     make_pair("gettransaction",         &gettransaction),
-     make_pair("listtransactions",       &listtransactions),
-     make_pair("signmessage",           &signmessage),
-     make_pair("verifymessage",         &verifymessage),
-     make_pair("getwork",                &getwork),
-     make_pair("listaccounts",           &listaccounts),
-     make_pair("settxfee",               &settxfee),
-     make_pair("getmemorypool",          &getmemorypool),
-     make_pair("listsinceblock",        &listsinceblock),
-     make_pair("getcheckpoint",         &getcheckpoint),
-     make_pair("reservebalance",         &reservebalance),
-     make_pair("checkwallet",            &checkwallet),
-     make_pair("repairwallet",           &repairwallet),
-     make_pair("makekeypair",            &makekeypair),
-     make_pair("sendalert",              &sendalert),
-     make_pair("sendcheckpoint",         &sendcheckpoint),
- };
- map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
- string pAllowInSafeMode[] =
- {
-     "help",
-     "stop",
-     "getblockcount",
-     "getblocknumber",  // deprecated
-     "getconnectioncount",
-     "getdifficulty",
-     "getgenerate",
-     "setgenerate",
-     "gethashespersec",
-     "getinfo",
-     "getnewaddress",
-     "getaccountaddress",
-     "getaccount",
-     "getaddressesbyaccount",
-     "backupwallet",
-     "keypoolrefill",
-     "walletpassphrase",
-     "walletlock",
-     "validateaddress",
-     "getwork",
-     "getmemorypool",
-     "getcheckpoint",
+ static const CRPCCommand vRPCCommands[] =
+ { //  name                      function                 safe mode?
+   //  ------------------------  -----------------------  ----------
+     { "help",                   &help,                   true },
+     { "stop",                   &stop,                   true },
+     { "getblockcount",          &getblockcount,          true },
+     { "getblocknumber",         &getblocknumber,         true },
+     { "getconnectioncount",     &getconnectioncount,     true },
+     { "getdifficulty",          &getdifficulty,          true },
+     { "getgenerate",            &getgenerate,            true },
+     { "setgenerate",            &setgenerate,            true },
+     { "gethashespersec",        &gethashespersec,        true },
+     { "getinfo",                &getinfo,                true },
+     { "getmininginfo",          &getmininginfo,          true },
+     { "getnewaddress",          &getnewaddress,          true },
+     { "getaccountaddress",      &getaccountaddress,      true },
+     { "setaccount",             &setaccount,             true },
+     { "getaccount",             &getaccount,             false },
+     { "getaddressesbyaccount",  &getaddressesbyaccount,  true },
+     { "sendtoaddress",          &sendtoaddress,          false },
+     { "getreceivedbyaddress",   &getreceivedbyaddress,   false },
+     { "getreceivedbyaccount",   &getreceivedbyaccount,   false },
+     { "listreceivedbyaddress",  &listreceivedbyaddress,  false },
+     { "listreceivedbyaccount",  &listreceivedbyaccount,  false },
+     { "backupwallet",           &backupwallet,           true },
+     { "keypoolrefill",          &keypoolrefill,          true },
+     { "walletpassphrase",       &walletpassphrase,       true },
+     { "walletpassphrasechange", &walletpassphrasechange, false },
+     { "walletlock",             &walletlock,             true },
+     { "encryptwallet",          &encryptwallet,          false },
+     { "validateaddress",        &validateaddress,        true },
+     { "getbalance",             &getbalance,             false },
+     { "move",                   &movecmd,                false },
+     { "sendfrom",               &sendfrom,               false },
+     { "sendmany",               &sendmany,               false },
+     { "addmultisigaddress",     &addmultisigaddress,     false },
+     { "getblock",               &getblock,               false },
+     { "getblockhash",           &getblockhash,           false },
+     { "gettransaction",         &gettransaction,         false },
+     { "listtransactions",       &listtransactions,       false },
+     { "signmessage",            &signmessage,            false },
+     { "verifymessage",          &verifymessage,          false },
+     { "getwork",                &getwork,                true },
+     { "listaccounts",           &listaccounts,           false },
+     { "settxfee",               &settxfee,               false },
+     { "getmemorypool",          &getmemorypool,          true },
+     { "listsinceblock",         &listsinceblock,         false },
+     { "dumpprivkey",            &dumpprivkey,            false },
+     { "importprivkey",          &importprivkey,          false },
++    { "getcheckpoint",          &getcheckpoint,          true },
++    { "reservebalance",         &reservebalance,         false},
++    { "checkwallet",            &checkwallet,            false},
++    { "repairwallet",           &repairwallet,           false},
++    { "makekeypair",            &makekeypair,            false},
++    { "sendalert",              &sendalert,              false},
++    { "sendcheckpoint",         &sendcheckpoint,         false},
  };
- set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
  
+ CRPCTable::CRPCTable()
+ {
+     unsigned int vcidx;
+     for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
+     {
+         const CRPCCommand *pcmd;
  
+         pcmd = &vRPCCommands[vcidx];
+         mapCommands[pcmd->name] = pcmd;
+     }
+ }
  
+ const CRPCCommand *CRPCTable::operator[](string name) const
+ {
+     map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
+     if (it == mapCommands.end())
+         return NULL;
+     return (*it).second;
+ }
  
  //
  // HTTP protocol
@@@ -2153,7 -2092,7 +2364,7 @@@ string HTTPPost(const string& strMsg, c
  {
      ostringstream s;
      s << "POST / HTTP/1.1\r\n"
 -      << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
 +      << "User-Agent: ppcoin-json-rpc/" << FormatFullVersion() << "\r\n"
        << "Host: 127.0.0.1\r\n"
        << "Content-Type: application/json\r\n"
        << "Content-Length: " << strMsg.size() << "\r\n"
@@@ -2184,7 -2123,7 +2395,7 @@@ static string HTTPReply(int nStatus, co
      if (nStatus == 401)
          return strprintf("HTTP/1.0 401 Authorization Required\r\n"
              "Date: %s\r\n"
 -            "Server: bitcoin-json-rpc/%s\r\n"
 +            "Server: ppcoin-json-rpc/%s\r\n"
              "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
              "Content-Type: text/html\r\n"
              "Content-Length: 296\r\n"
              "Connection: close\r\n"
              "Content-Length: %d\r\n"
              "Content-Type: application/json\r\n"
 -            "Server: bitcoin-json-rpc/%s\r\n"
 +            "Server: ppcoin-json-rpc/%s\r\n"
              "\r\n"
              "%s",
          nStatus,
@@@ -2268,7 -2207,7 +2479,7 @@@ int ReadHTTP(std::basic_istream<char>& 
  
      // Read header
      int nLen = ReadHTTPHeader(stream, mapHeadersRet);
-     if (nLen < 0 || nLen > MAX_SIZE)
+     if (nLen < 0 || nLen > (int)MAX_SIZE)
          return 500;
  
      // Read message
@@@ -2345,7 -2284,6 +2556,6 @@@ bool ClientAllowed(const string& strAdd
      return false;
  }
  
- #ifdef USE_SSL
  //
  // IOStream device that speaks SSL but can also speak non-SSL
  //
@@@ -2397,22 -2335,21 +2607,21 @@@ private
      bool fUseSSL;
      SSLStream& stream;
  };
- #endif
  
  void ThreadRPCServer(void* parg)
  {
      IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
      try
      {
-         vnThreadsRunning[4]++;
+         vnThreadsRunning[THREAD_RPCSERVER]++;
          ThreadRPCServer2(parg);
-         vnThreadsRunning[4]--;
+         vnThreadsRunning[THREAD_RPCSERVER]--;
      }
      catch (std::exception& e) {
-         vnThreadsRunning[4]--;
+         vnThreadsRunning[THREAD_RPCSERVER]--;
          PrintException(&e, "ThreadRPCServer()");
      } catch (...) {
-         vnThreadsRunning[4]--;
+         vnThreadsRunning[THREAD_RPCSERVER]--;
          PrintException(NULL, "ThreadRPCServer()");
      }
      printf("ThreadRPCServer exiting\n");
@@@ -2423,21 -2360,27 +2632,27 @@@ void ThreadRPCServer2(void* parg
      printf("ThreadRPCServer started\n");
  
      strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
-     if (strRPCUserColonPass == ":")
+     if (mapArgs["-rpcpassword"] == "")
      {
+         unsigned char rand_pwd[32];
+         RAND_bytes(rand_pwd, 32);
 -        string strWhatAmI = "To use bitcoind";
 +        string strWhatAmI = "To use ppcoind";
          if (mapArgs.count("-server"))
              strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
          else if (mapArgs.count("-daemon"))
              strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
-         PrintConsole(
-             _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
+         ThreadSafeMessageBox(strprintf(
+             _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
+               "It is recommended you use the following random password:\n"
+               "rpcuser=bitcoinrpc\n"
+               "rpcpassword=%s\n"
+               "(you do not need to remember this password)\n"
                "If the file does not exist, create it with owner-readable-only file permissions.\n"),
                  strWhatAmI.c_str(),
-                 GetConfigFile().c_str());
- #ifndef QT_GUI
-         CreateThread(Shutdown, NULL);
- #endif
+                 GetConfigFile().string().c_str(),
+                 EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
+             _("Error"), wxOK | wxMODAL);
+         StartShutdown();
          return;
      }
  
      asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
  
      asio::io_service io_service;
 -    ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
 +    ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", RPC_PORT));
-     ip::tcp::acceptor acceptor(io_service, endpoint);
-     acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+     ip::tcp::acceptor acceptor(io_service);
+     try
+     {
+         acceptor.open(endpoint.protocol());
+         acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+         acceptor.bind(endpoint);
+         acceptor.listen(socket_base::max_connections);
+     }
+     catch(boost::system::system_error &e)
+     {
+         ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
+                              _("Error"), wxOK | wxMODAL);
+         StartShutdown();
+         return;
+     }
  
- #ifdef USE_SSL
      ssl::context context(io_service, ssl::context::sslv23);
      if (fUseSSL)
      {
          context.set_options(ssl::context::no_sslv2);
-         filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
-         if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
-         if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
-         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
-         filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
-         if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
-         if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
-         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
-         string ciphers = GetArg("-rpcsslciphers",
-                                          "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
-         SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
-     }
- #else
-     if (fUseSSL)
-         throw runtime_error("-rpcssl=1, but ppcoin compiled without full openssl libraries.");
- #endif
+         filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
+         if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
+         if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
+         else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
+         filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
+         if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
+         if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
+         else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
+         string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
+         SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
+     }
  
      loop
      {
          // Accept connection
          SSLStream sslStream(io_service, context);
          SSLIOStreamDevice d(sslStream, fUseSSL);
          iostreams::stream<SSLIOStreamDevice> stream(d);
- #else
-         ip::tcp::iostream stream;
- #endif
  
          ip::tcp::endpoint peer;
-         vnThreadsRunning[4]--;
- #ifdef USE_SSL
+         vnThreadsRunning[THREAD_RPCSERVER]--;
          acceptor.accept(sslStream.lowest_layer(), peer);
- #else
-         acceptor.accept(*stream.rdbuf(), peer);
- #endif
          vnThreadsRunning[4]++;
          if (fShutdown)
              return;
          }
          if (!HTTPAuthorized(mapHeaders))
          {
-             // Deter brute-forcing short passwords
-             if (mapArgs["-rpcpassword"].size() < 15)
-                 Sleep(50);
+             printf("ThreadRPCServer incorrect password attempt from %s\n",peer.address().to_string().c_str());
+             /* Deter brute-forcing short passwords.
+                If this results in a DOS the user really
+                shouldn't have their RPC port exposed.*/
+             if (mapArgs["-rpcpassword"].size() < 20)
+                 Sleep(250);
  
              stream << HTTPReply(401, "") << std::flush;
-             printf("ThreadRPCServer incorrect password attempt\n");
              continue;
          }
  
                  throw JSONRPCError(-32600, "Params must be an array");
  
              // Find method
-             map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
-             if (mi == mapCallTable.end())
+             const CRPCCommand *pcmd = tableRPC[strMethod];
+             if (!pcmd)
                  throw JSONRPCError(-32601, "Method not found");
  
              // Observe safe mode
              string strWarning = GetWarnings("rpc");
-             if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
+             if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
+                 !pcmd->okSafeMode)
                  throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
  
              try
              {
                  // Execute
                  Value result;
-                 CRITICAL_BLOCK(cs_main)
-                 CRITICAL_BLOCK(pwalletMain->cs_wallet)
-                     result = (*(*mi).second)(params, false);
+                 {
+                     LOCK2(cs_main, pwalletMain->cs_wallet);
+                     result = pcmd->actor(params, false);
+                 }
  
                  // Send reply
                  string strReply = JSONRPCReply(result, Value::null, id);
@@@ -2611,28 -2558,18 +2830,18 @@@ Object CallRPC(const string& strMethod
          throw runtime_error(strprintf(
              _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
                "If the file does not exist, create it with owner-readable-only file permissions."),
-                 GetConfigFile().c_str()));
+                 GetConfigFile().string().c_str()));
  
      // Connect to localhost
      bool fUseSSL = GetBoolArg("-rpcssl");
- #ifdef USE_SSL
      asio::io_service io_service;
      ssl::context context(io_service, ssl::context::sslv23);
      context.set_options(ssl::context::no_sslv2);
      SSLStream sslStream(io_service, context);
      SSLIOStreamDevice d(sslStream, fUseSSL);
      iostreams::stream<SSLIOStreamDevice> stream(d);
 -    if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
 +    if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str())))
          throw runtime_error("couldn't connect to server");
- #else
-     if (fUseSSL)
-         throw runtime_error("-rpcssl=1, but ppcoin compiled without full openssl libraries.");
-     ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", CBigNum(RPC_PORT).ToString().c_str()));
-     if (stream.fail())
-         throw runtime_error("couldn't connect to server");
- #endif
  
      // HTTP basic authentication
      string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
@@@ -2724,6 -2661,7 +2933,7 @@@ int CommandLineRPC(int argc, char *argv
          if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
          if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
+         if (strMethod == "getblockhash"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
          if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
          if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
          if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
          if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
 +        if (strMethod == "walletpassphrase"       && n > 2) ConvertTo<bool>(params[2]);
          if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
 +        if (strMethod == "sendalert"              && n > 2) ConvertTo<boost::int64_t>(params[2]);
 +        if (strMethod == "sendalert"              && n > 3) ConvertTo<boost::int64_t>(params[3]);
 +        if (strMethod == "sendalert"              && n > 4) ConvertTo<boost::int64_t>(params[4]);
 +        if (strMethod == "sendalert"              && n > 5) ConvertTo<boost::int64_t>(params[5]);
          if (strMethod == "sendmany"               && n > 1)
          {
              string s = params[1].get_str();
              params[1] = v.get_obj();
          }
          if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
 +        if (strMethod == "reservebalance"          && n > 0) ConvertTo<bool>(params[0]);
 +        if (strMethod == "reservebalance"          && n > 1) ConvertTo<double>(params[1]);
+         if (strMethod == "addmultisigaddress"      && n > 0) ConvertTo<boost::int64_t>(params[0]);
+         if (strMethod == "addmultisigaddress"      && n > 1)
+         {
+             string s = params[1].get_str();
+             Value v;
+             if (!read_string(s, v) || v.type() != array_type)
+                 throw runtime_error("type mismatch "+s);
+             params[1] = v.get_array();
+         }
  
          // Execute
          Object reply = CallRPC(strMethod, params);
@@@ -2827,3 -2767,5 +3046,5 @@@ int main(int argc, char *argv[]
      return 0;
  }
  #endif
+ const CRPCTable tableRPC;
diff --combined src/checkpoints.cpp
@@@ -1,17 -1,18 +1,20 @@@
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #include <boost/assign/list_of.hpp> // for 'map_list_of()'
  #include <boost/foreach.hpp>
  
- #include "headers.h"
  #include "checkpoints.h"
  
++#include "db.h"
+ #include "main.h"
+ #include "uint256.h"
  namespace Checkpoints
  {
 -    typedef std::map<int, uint256> MapCheckpoints;
 +    typedef std::map<int, uint256> MapCheckpoints;   // hardened checkpoints
  
      //
      // What makes a good checkpoint block?
      //
      static MapCheckpoints mapCheckpoints =
          boost::assign::map_list_of
 -        ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
 -        ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
 -        ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
 -        (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
 -        (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
 -        (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
 -        (185333, uint256("0x00000000000002334c71b8706940c20348af897a9cfc0f1a6dab0d14d4ceb815"))
 -        ;
 -
 -    bool CheckBlock(int nHeight, const uint256& hash)
 +        ( 0, hashGenesisBlockOfficial )
 +        ; // ppcoin: no checkpoint yet; to be created in future releases
 +
 +    bool CheckHardened(int nHeight, const uint256& hash)
      {
          if (fTestNet) return true; // Testnet has no checkpoints
  
  
      CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
      {
 -        if (fTestNet) return NULL;
 +        if (fTestNet) {
 +            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hashGenesisBlock);
 +            if (t != mapBlockIndex.end())
 +                return t->second;
 +            return NULL;
 +        }
  
-         int64 nResult;
          BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
          {
              const uint256& hash = i.second;
          }
          return NULL;
      }
 +
 +    // ppcoin: synchronized checkpoint (centrally broadcasted)
 +    uint256 hashSyncCheckpoint = 0;
 +    uint256 hashPendingCheckpoint = 0;
 +    CSyncCheckpoint checkpointMessage;
 +    CSyncCheckpoint checkpointMessagePending;
 +    uint256 hashInvalidCheckpoint = 0;
 +    CCriticalSection cs_hashSyncCheckpoint;
 +
 +    // ppcoin: get last synchronized checkpoint
 +    CBlockIndex* GetLastSyncCheckpoint()
 +    {
-         CRITICAL_BLOCK(cs_hashSyncCheckpoint)
-         {
-             if (!mapBlockIndex.count(hashSyncCheckpoint))
-                 error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
-             else
-                 return mapBlockIndex[hashSyncCheckpoint];
-         }
++        LOCK(cs_hashSyncCheckpoint);
++        if (!mapBlockIndex.count(hashSyncCheckpoint))
++            error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
++        else
++            return mapBlockIndex[hashSyncCheckpoint];
 +        return NULL;
 +    }
 +
 +    // ppcoin: only descendant of current sync-checkpoint is allowed
 +    bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
 +    {
 +        if (!mapBlockIndex.count(hashSyncCheckpoint))
 +            return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
 +        if (!mapBlockIndex.count(hashCheckpoint))
 +            return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str());
 +
 +        CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint];
 +        CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint];
 +
 +        if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight)
 +        {
 +            // Received an older checkpoint, trace back from current checkpoint
 +            // to the same height of the received checkpoint to verify
 +            // that current checkpoint should be a descendant block
 +            CBlockIndex* pindex = pindexSyncCheckpoint;
 +            while (pindex->nHeight > pindexCheckpointRecv->nHeight)
 +                if (!(pindex = pindex->pprev))
 +                    return error("ValidateSyncCheckpoint: pprev1 null - block index structure failure");
 +            if (pindex->GetBlockHash() != hashCheckpoint)
 +            {
 +                hashInvalidCheckpoint = hashCheckpoint;
 +                return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
 +            }
 +            return false; // ignore older checkpoint
 +        }
 +
 +        // Received checkpoint should be a descendant block of the current
 +        // checkpoint. Trace back to the same height of current checkpoint
 +        // to verify.
 +        CBlockIndex* pindex = pindexCheckpointRecv;
 +        while (pindex->nHeight > pindexSyncCheckpoint->nHeight)
 +            if (!(pindex = pindex->pprev))
 +                return error("ValidateSyncCheckpoint: pprev2 null - block index structure failure");
 +        if (pindex->GetBlockHash() != hashSyncCheckpoint)
 +        {
 +            hashInvalidCheckpoint = hashCheckpoint;
 +            return error("ValidateSyncCheckpoint: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
 +        }
 +        return true;
 +    }
 +
 +    bool WriteSyncCheckpoint(const uint256& hashCheckpoint)
 +    {
 +        CTxDB txdb;
 +        txdb.TxnBegin();
 +        if (!txdb.WriteSyncCheckpoint(hashCheckpoint))
 +        {
 +            txdb.TxnAbort();
 +            return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
 +        }
 +        if (!txdb.TxnCommit())
 +            return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
 +        txdb.Close();
 +
 +        Checkpoints::hashSyncCheckpoint = hashCheckpoint;
 +        return true;
 +    }
 +
 +    bool AcceptPendingSyncCheckpoint()
 +    {
-         CRITICAL_BLOCK(cs_hashSyncCheckpoint)
++        LOCK(cs_hashSyncCheckpoint);
++        if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint))
 +        {
-             if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint))
++            if (!ValidateSyncCheckpoint(hashPendingCheckpoint))
 +            {
-                 if (!ValidateSyncCheckpoint(hashPendingCheckpoint))
-                 {
-                     hashPendingCheckpoint = 0;
-                     checkpointMessagePending.SetNull();
-                     return false;
-                 }
++                hashPendingCheckpoint = 0;
++                checkpointMessagePending.SetNull();
++                return false;
++            }
 +
-                 CTxDB txdb;
-                 CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint];
-                 if (!pindexCheckpoint->IsInMainChain())
++            CTxDB txdb;
++            CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint];
++            if (!pindexCheckpoint->IsInMainChain())
++            {
++                txdb.TxnBegin();
++                if (!Reorganize(txdb, pindexCheckpoint))
 +                {
-                     txdb.TxnBegin();
-                     if (!Reorganize(txdb, pindexCheckpoint))
-                     {
-                         txdb.TxnAbort();
-                         hashInvalidCheckpoint = hashPendingCheckpoint;
-                         return error("ProcessSyncCheckpoint: Reorganize failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
-                     }
++                    txdb.TxnAbort();
++                    hashInvalidCheckpoint = hashPendingCheckpoint;
++                    return error("ProcessSyncCheckpoint: Reorganize failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
 +                }
-                 txdb.Close();
-                 if (!WriteSyncCheckpoint(hashPendingCheckpoint))
-                     return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
-                 hashPendingCheckpoint = 0;
-                 checkpointMessage = checkpointMessagePending;
-                 checkpointMessagePending.SetNull();
-                 printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str());
-                 // relay the checkpoint
-                 if (!checkpointMessage.IsNull())
-                     BOOST_FOREACH(CNode* pnode, vNodes)
-                         checkpointMessage.RelayTo(pnode);
-                 return true;
 +            }
++            txdb.Close();
++
++            if (!WriteSyncCheckpoint(hashPendingCheckpoint))
++                return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
++            hashPendingCheckpoint = 0;
++            checkpointMessage = checkpointMessagePending;
++            checkpointMessagePending.SetNull();
++            printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str());
++            // relay the checkpoint
++            if (!checkpointMessage.IsNull())
++            {
++                BOOST_FOREACH(CNode* pnode, vNodes)
++                    checkpointMessage.RelayTo(pnode);
++            }
++            return true;
 +        }
 +        return false;
 +    }
 +
 +    uint256 AutoSelectSyncCheckpoint()
 +    {
 +        // select a block some time ago
 +        CBlockIndex *pindex = mapBlockIndex[hashSyncCheckpoint];
 +        while (pindex->pnext && pindex->pnext->GetBlockTime() + CHECKPOINT_MIN_SPAN <= GetAdjustedTime())
 +            pindex = pindex->pnext;
 +        return pindex->GetBlockHash();
 +    }
 +
 +    // Check against synchronized checkpoint
 +    bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev)
 +    {
 +        if (fTestNet) return true; // Testnet has no checkpoints
 +        int nHeight = pindexPrev->nHeight + 1;
 +
-         CRITICAL_BLOCK(cs_hashSyncCheckpoint)
-         {
-             // sync-checkpoint should always be accepted block
-             assert(mapBlockIndex.count(hashSyncCheckpoint));
-             const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
++        LOCK(cs_hashSyncCheckpoint);
++        // sync-checkpoint should always be accepted block
++        assert(mapBlockIndex.count(hashSyncCheckpoint));
++        const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
 +
-             if (nHeight > pindexSync->nHeight)
-             {
-                 // trace back to same height as sync-checkpoint
-                 const CBlockIndex* pindex = pindexPrev;
-                 while (pindex->nHeight > pindexSync->nHeight)
-                     if (!(pindex = pindex->pprev))
-                         return error("CheckSync: pprev null - block index structure failure");
-                 if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint)
-                     return false; // only descendant of sync-checkpoint can pass check
-             }
-             if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint)
-                 return false; // same height with sync-checkpoint
-             if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
-                 return false; // lower height than sync-checkpoint
++        if (nHeight > pindexSync->nHeight)
++        {
++            // trace back to same height as sync-checkpoint
++            const CBlockIndex* pindex = pindexPrev;
++            while (pindex->nHeight > pindexSync->nHeight)
++                if (!(pindex = pindex->pprev))
++                    return error("CheckSync: pprev null - block index structure failure");
++            if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint)
++                return false; // only descendant of sync-checkpoint can pass check
 +        }
++        if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint)
++            return false; // same height with sync-checkpoint
++        if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
++            return false; // lower height than sync-checkpoint
 +        return true;
 +    }
 +
 +    bool WantedByPendingSyncCheckpoint(uint256 hashBlock)
 +    {
-         CRITICAL_BLOCK(cs_hashSyncCheckpoint)
-         {
-             if (hashPendingCheckpoint == 0)
-                 return false;
-             if (hashBlock == hashPendingCheckpoint)
-                 return true;
-             if (mapOrphanBlocks.count(hashPendingCheckpoint) 
-                 && hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint]))
-                 return true;
-         }
++        LOCK(cs_hashSyncCheckpoint);
++        if (hashPendingCheckpoint == 0)
++            return false;
++        if (hashBlock == hashPendingCheckpoint)
++            return true;
++        if (mapOrphanBlocks.count(hashPendingCheckpoint) 
++            && hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint]))
++            return true;
 +        return false;
 +    }
 +
 +    // ppcoin: reset synchronized checkpoint to last hardened checkpoint
 +    bool ResetSyncCheckpoint()
 +    {
-         CRITICAL_BLOCK(cs_hashSyncCheckpoint)
++        LOCK(cs_hashSyncCheckpoint);
++        const uint256& hash = mapCheckpoints.rbegin()->second;
++        if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain())
 +        {
-             const uint256& hash = mapCheckpoints.rbegin()->second;
-             if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain())
-             {
-                 // checkpoint block accepted but not yet in main chain
-                 printf("ResetSyncCheckpoint: Reorganize to hardened checkpoint %s\n", hash.ToString().c_str());
-                 CTxDB txdb;
-                 txdb.TxnBegin();
-                 if (!Reorganize(txdb, mapBlockIndex[hash]))
-                 {
-                     txdb.TxnAbort();
-                     return error("ResetSyncCheckpoint: Reorganize failed for hardened checkpoint %s", hash.ToString().c_str());
-                 }
-                 txdb.Close();
-             }
-             else if(!mapBlockIndex.count(hash))
++            // checkpoint block accepted but not yet in main chain
++            printf("ResetSyncCheckpoint: Reorganize to hardened checkpoint %s\n", hash.ToString().c_str());
++            CTxDB txdb;
++            txdb.TxnBegin();
++            if (!Reorganize(txdb, mapBlockIndex[hash]))
 +            {
-                 // checkpoint block not yet accepted
-                 hashPendingCheckpoint = hash;
-                 checkpointMessagePending.SetNull();
-                 printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str());
++                txdb.TxnAbort();
++                return error("ResetSyncCheckpoint: Reorganize failed for hardened checkpoint %s", hash.ToString().c_str());
 +            }
++            txdb.Close();
++        }
++        else if(!mapBlockIndex.count(hash))
++        {
++            // checkpoint block not yet accepted
++            hashPendingCheckpoint = hash;
++            checkpointMessagePending.SetNull();
++            printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str());
++        }
 +
-             BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
++        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
++        {
++            const uint256& hash = i.second;
++            if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
 +            {
-                 const uint256& hash = i.second;
-                 if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
-                 {
-                     if (!WriteSyncCheckpoint(hash))
-                         return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str());
-                     printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str());
-                     return true;
-                 }
++                if (!WriteSyncCheckpoint(hash))
++                    return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str());
++                printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str());
++                return true;
 +            }
-             return false;
 +        }
++
++        return false;
 +    }
 +
 +    void AskForPendingSyncCheckpoint(CNode* pfrom)
 +    {
-         CRITICAL_BLOCK(cs_hashSyncCheckpoint)
-             if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint)))
-                 pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint));
++        LOCK(cs_hashSyncCheckpoint);
++        if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint)))
++            pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint));
 +    }
 +}
 +
 +// ppcoin: sync-checkpoint master key
 +const std::string CSyncCheckpoint::strMasterPubKey = "0424f20205e5da98ba632bbd278a11a6499585f62bfb2c782377ef59f0251daab8085fc31471bcb8180bc75ed0fa41bb50c7c084511d54015a3a5241d645c7268a";
 +
 +// ppcoin: verify signature of sync-checkpoint message
 +bool CSyncCheckpoint::CheckSignature()
 +{
 +    CKey key;
 +    if (!key.SetPubKey(ParseHex(CSyncCheckpoint::strMasterPubKey)))
 +        return error("CSyncCheckpoint::CheckSignature() : SetPubKey failed");
 +    if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
 +        return error("CSyncCheckpoint::CheckSignature() : verify signature failed");
 +
 +    // Now unserialize the data
-     CDataStream sMsg(vchMsg);
++    CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
 +    sMsg >> *(CUnsignedSyncCheckpoint*)this;
 +    return true;
 +}
 +
 +// ppcoin: process synchronized checkpoint
 +bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom)
 +{
 +    if (!CheckSignature())
 +        return false;
 +
-     CRITICAL_BLOCK(Checkpoints::cs_hashSyncCheckpoint)
++    LOCK(Checkpoints::cs_hashSyncCheckpoint);
++    if (!mapBlockIndex.count(hashCheckpoint))
 +    {
-         if (!mapBlockIndex.count(hashCheckpoint))
++        // We haven't received the checkpoint chain, keep the checkpoint as pending
++        Checkpoints::hashPendingCheckpoint = hashCheckpoint;
++        Checkpoints::checkpointMessagePending = *this;
++        printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str());
++        // Ask this guy to fill in what we're missing
++        if (pfrom)
 +        {
-             // We haven't received the checkpoint chain, keep the checkpoint as pending
-             Checkpoints::hashPendingCheckpoint = hashCheckpoint;
-             Checkpoints::checkpointMessagePending = *this;
-             printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str());
-             // Ask this guy to fill in what we're missing
-             if (pfrom)
-             {
-                 pfrom->PushGetBlocks(pindexBest, hashCheckpoint);
-                 // ask directly as well in case rejected earlier by duplicate
-                 // proof-of-stake because getblocks may not get it this time
-                 pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
-             }
-             return false;
++            pfrom->PushGetBlocks(pindexBest, hashCheckpoint);
++            // ask directly as well in case rejected earlier by duplicate
++            // proof-of-stake because getblocks may not get it this time
++            pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
 +        }
++        return false;
++    }
 +
-         if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint))
-             return false;
++    if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint))
++        return false;
 +
-         CTxDB txdb;
-         CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint];
-         if (!pindexCheckpoint->IsInMainChain())
++    CTxDB txdb;
++    CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint];
++    if (!pindexCheckpoint->IsInMainChain())
++    {
++        // checkpoint chain received but not yet main chain
++        txdb.TxnBegin();
++        if (!Reorganize(txdb, pindexCheckpoint))
 +        {
-             // checkpoint chain received but not yet main chain
-             txdb.TxnBegin();
-             if (!Reorganize(txdb, pindexCheckpoint))
-             {
-                 txdb.TxnAbort();
-                 Checkpoints::hashInvalidCheckpoint = hashCheckpoint;
-                 return error("ProcessSyncCheckpoint: Reorganize failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
-             }
++            txdb.TxnAbort();
++            Checkpoints::hashInvalidCheckpoint = hashCheckpoint;
++            return error("ProcessSyncCheckpoint: Reorganize failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
 +        }
-         txdb.Close();
-         if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint))
-             return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str());
-         Checkpoints::checkpointMessage = *this;
-         Checkpoints::hashPendingCheckpoint = 0;
-         Checkpoints::checkpointMessagePending.SetNull();
-         printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str());
 +    }
++    txdb.Close();
++
++    if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint))
++        return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str());
++    Checkpoints::checkpointMessage = *this;
++    Checkpoints::hashPendingCheckpoint = 0;
++    Checkpoints::checkpointMessagePending.SetNull();
++    printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str());
 +    return true;
  }
diff --combined src/checkpoints.h
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_CHECKPOINT_H
  #define  BITCOIN_CHECKPOINT_H
  
  #include <map>
++#include "net.h"
 +#include "util.h"
 +
 +#define STAKE_MIN_AGE (60 * 60 * 24)      // minimum age for coin age
 +#define CHECKPOINT_MIN_SPAN (60 * 60 * 4) // 4 hours checkpoint
  
  class uint256;
  class CBlockIndex;
 +class CSyncCheckpoint;
  
- //
- // Block-chain checkpoints are compiled-in sanity checks.
- // They are updated every release or three.
- //
+ /** Block-chain checkpoints are compiled-in sanity checks.
+  * They are updated every release or three.
+  */
  namespace Checkpoints
  {
      // Returns true if block passes checkpoint checks
 -    bool CheckBlock(int nHeight, const uint256& hash);
 +    bool CheckHardened(int nHeight, const uint256& hash);
  
      // Return conservative estimate of total number of blocks, 0 if unknown
      int GetTotalBlocksEstimate();
  
      // Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
      CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex);
 +
 +    extern uint256 hashSyncCheckpoint;
 +    extern CSyncCheckpoint checkpointMessage;
 +    extern uint256 hashInvalidCheckpoint;
 +    extern CCriticalSection cs_hashSyncCheckpoint;
 +
 +    CBlockIndex* GetLastSyncCheckpoint();
 +    bool WriteSyncCheckpoint(const uint256& hashCheckpoint);
 +    bool AcceptPendingSyncCheckpoint();
 +    uint256 AutoSelectSyncCheckpoint();
 +    bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev);
 +    bool WantedByPendingSyncCheckpoint(uint256 hashBlock);
 +    bool ResetSyncCheckpoint();
 +    void AskForPendingSyncCheckpoint(CNode* pfrom);
  }
  
 +// ppcoin: synchronized checkpoint
 +class CUnsignedSyncCheckpoint
 +{
 +public:
 +    int nVersion;
 +    uint256 hashCheckpoint;      // checkpoint block
 +
 +    IMPLEMENT_SERIALIZE
 +    (
 +        READWRITE(this->nVersion);
 +        nVersion = this->nVersion;
 +        READWRITE(hashCheckpoint);
 +    )
 +
 +    void SetNull()
 +    {
 +        nVersion = 1;
 +        hashCheckpoint = 0;
 +    }
 +
 +    std::string ToString() const
 +    {
 +        return strprintf(
 +                "CSyncCheckpoint(\n"
 +                "    nVersion       = %d\n"
 +                "    hashCheckpoint = %s\n"
 +                ")\n",
 +            nVersion,
 +            hashCheckpoint.ToString().c_str());
 +    }
 +
 +    void print() const
 +    {
 +        printf("%s", ToString().c_str());
 +    }
 +};
 +
 +class CSyncCheckpoint : public CUnsignedSyncCheckpoint
 +{
 +public:
 +    static const std::string strMasterPubKey;
 +
 +    std::vector<unsigned char> vchMsg;
 +    std::vector<unsigned char> vchSig;
 +
 +    CSyncCheckpoint()
 +    {
 +        SetNull();
 +    }
 +
 +    IMPLEMENT_SERIALIZE
 +    (
 +        READWRITE(vchMsg);
 +        READWRITE(vchSig);
 +    )
 +
 +    void SetNull()
 +    {
 +        CUnsignedSyncCheckpoint::SetNull();
 +        vchMsg.clear();
 +        vchSig.clear();
 +    }
 +
 +    bool IsNull() const
 +    {
 +        return (hashCheckpoint == 0);
 +    }
 +
 +    uint256 GetHash() const
 +    {
 +        return SerializeHash(*this);
 +    }
 +
 +    bool RelayTo(CNode* pnode) const
 +    {
 +        // returns true if wasn't already sent
 +        if (pnode->hashCheckpointKnown != hashCheckpoint)
 +        {
 +            pnode->hashCheckpointKnown = hashCheckpoint;
 +            pnode->PushMessage("checkpoint", *this);
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +    bool CheckSignature();
 +    bool ProcessSyncCheckpoint(CNode* pfrom);
 +};
 +
  #endif
diff --combined src/db.cpp
@@@ -1,22 -1,24 +1,27 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
- #include "headers.h"
  #include "db.h"
 +#include "net.h"
 +#include "checkpoints.h"
+ #include "util.h"
+ #include "main.h"
+ #include <boost/version.hpp>
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
+ #ifndef WIN32
+ #include "sys/stat.h"
+ #endif
  using namespace std;
  using namespace boost;
  
  
  unsigned int nWalletDBUpdated;
- uint64 nAccountingEntryNumber = 0;
  
  
  
  // CDB
  //
  
- static CCriticalSection cs_db;
+ CCriticalSection cs_db;
  static bool fDbEnvInit = false;
+ bool fDetachDB = false;
  DbEnv dbenv(0);
- static map<string, int> mapFileUseCount;
+ map<string, int> mapFileUseCount;
  static map<string, Db*> mapDb;
  
  static void EnvShutdown()
@@@ -44,7 -47,7 +50,7 @@@
      {
          printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno());
      }
-     DbEnv(0).remove(GetDataDir().c_str(), 0);
+     DbEnv(0).remove(GetDataDir().string().c_str(), 0);
  }
  
  class CDBInit
@@@ -61,7 -64,7 +67,7 @@@ public
  instance_of_cdbinit;
  
  
- CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
+ CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL)
  {
      int ret;
      if (pszFile == NULL)
      if (fCreate)
          nFlags |= DB_CREATE;
  
-     CRITICAL_BLOCK(cs_db)
      {
+         LOCK(cs_db);
          if (!fDbEnvInit)
          {
              if (fShutdown)
                  return;
-             string strDataDir = GetDataDir();
-             string strLogDir = strDataDir + "/database";
-             filesystem::create_directory(strLogDir.c_str());
-             string strErrorFile = strDataDir + "/db.log";
-             printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
-             dbenv.set_lg_dir(strLogDir.c_str());
-             dbenv.set_lg_max(10000000);
+             filesystem::path pathDataDir = GetDataDir();
+             filesystem::path pathLogDir = pathDataDir / "database";
+             filesystem::create_directory(pathLogDir);
+             filesystem::path pathErrorFile = pathDataDir / "db.log";
+             printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str());
+             int nDbCache = GetArg("-dbcache", 25);
+             dbenv.set_lg_dir(pathLogDir.string().c_str());
+             dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
+             dbenv.set_lg_bsize(1048576);
+             dbenv.set_lg_max(10485760);
              dbenv.set_lk_max_locks(10000);
              dbenv.set_lk_max_objects(10000);
-             dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
+             dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
+             dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
              dbenv.set_flags(DB_AUTO_COMMIT, 1);
-             ret = dbenv.open(strDataDir.c_str(),
+             dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
+             ret = dbenv.open(pathDataDir.string().c_str(),
                               DB_CREATE     |
                               DB_INIT_LOCK  |
                               DB_INIT_LOG   |
              {
                  delete pdb;
                  pdb = NULL;
-                 CRITICAL_BLOCK(cs_db)
+                 {
+                      LOCK(cs_db);
                      --mapFileUseCount[strFile];
+                 }
                  strFile = "";
                  throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
              }
              {
                  bool fTmp = fReadOnly;
                  fReadOnly = false;
-                 WriteVersion(VERSION);
+                 WriteVersion(CLIENT_VERSION);
                  fReadOnly = fTmp;
              }
  
@@@ -157,18 -167,23 +170,23 @@@ void CDB::Close(
          nMinutes = 1;
      if (strFile == "addr.dat")
          nMinutes = 2;
-     if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
-         nMinutes = 1;
-     dbenv.txn_checkpoint(0, nMinutes, 0);
+     if (strFile == "blkindex.dat")
+         nMinutes = 2;
+     if (strFile == "blkindex.dat" && IsInitialBlockDownload())
+         nMinutes = 5;
  
-     CRITICAL_BLOCK(cs_db)
+     dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
+     {
+         LOCK(cs_db);
          --mapFileUseCount[strFile];
+     }
  }
  
- void static CloseDb(const string& strFile)
+ void CloseDb(const string& strFile)
  {
-     CRITICAL_BLOCK(cs_db)
      {
+         LOCK(cs_db);
          if (mapDb[strFile] != NULL)
          {
              // Close the database handle
@@@ -184,8 -199,8 +202,8 @@@ bool CDB::Rewrite(const string& strFile
  {
      while (!fShutdown)
      {
-         CRITICAL_BLOCK(cs_db)
          {
+             LOCK(cs_db);
              if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
              {
                  // Flush log data to the dat file
                      if (pcursor)
                          while (fSuccess)
                          {
-                             CDataStream ssKey;
-                             CDataStream ssValue;
+                             CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+                             CDataStream ssValue(SER_DISK, CLIENT_VERSION);
                              int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
                              if (ret == DB_NOTFOUND)
                              {
                              {
                                  // Update version:
                                  ssValue.clear();
-                                 ssValue << VERSION;
+                                 ssValue << CLIENT_VERSION;
                              }
                              Dbt datKey(&ssKey[0], ssKey.size());
                              Dbt datValue(&ssValue[0], ssValue.size());
@@@ -282,8 -297,8 +300,8 @@@ void DBFlush(bool fShutdown
      printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
      if (!fDbEnvInit)
          return;
-     CRITICAL_BLOCK(cs_db)
      {
+         LOCK(cs_db);
          map<string, int>::iterator mi = mapFileUseCount.begin();
          while (mi != mapFileUseCount.end())
          {
              {
                  // Move log data to the dat file
                  CloseDb(strFile);
+                 printf("%s checkpoint\n", strFile.c_str());
                  dbenv.txn_checkpoint(0, 0, 0);
-                 printf("%s flush\n", strFile.c_str());
-                 dbenv.lsn_reset(strFile.c_str(), 0);
+                 if ((strFile != "blkindex.dat" && strFile != "addr.dat") || fDetachDB) {
+                     printf("%s detach\n", strFile.c_str());
+                     dbenv.lsn_reset(strFile.c_str(), 0);
+                 }
+                 printf("%s closed\n", strFile.c_str());
                  mapFileUseCount.erase(mi++);
              }
              else
@@@ -374,10 -393,10 +396,10 @@@ bool CTxDB::ReadOwnerTxes(uint160 hash1
      loop
      {
          // Read next record
-         CDataStream ssKey;
+         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
          if (fFlags == DB_SET_RANGE)
              ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
-         CDataStream ssValue;
+         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
          int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
          fFlags = DB_NEXT;
          if (ret == DB_NOTFOUND)
          string strType;
          uint160 hashItem;
          CDiskTxPos pos;
-         ssKey >> strType >> hashItem >> pos;
          int nItemHeight;
-         ssValue >> nItemHeight;
+         try {
+             ssKey >> strType >> hashItem >> pos;
+             ssValue >> nItemHeight;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+         }
  
          // Read transaction
          if (strType != "owner" || hashItem != hash160)
@@@ -460,34 -485,14 +488,34 @@@ bool CTxDB::WriteHashBestChain(uint256 
      return Write(string("hashBestChain"), hashBestChain);
  }
  
 -bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
 +bool CTxDB::ReadBestInvalidTrust(uint64& nBestInvalidTrust)
  {
 -    return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
 +    return Read(string("nBestInvalidTrust"), nBestInvalidTrust);
  }
  
 -bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
 +bool CTxDB::WriteBestInvalidTrust(uint64 nBestInvalidTrust)
  {
 -    return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
 +    return Write(string("nBestInvalidTrust"), nBestInvalidTrust);
 +}
 +
 +bool CTxDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
 +{
 +    return Read(string("hashSyncCheckpoint"), hashCheckpoint);
 +}
 +
 +bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
 +{
 +    return Write(string("hashSyncCheckpoint"), hashCheckpoint);
 +}
 +
 +bool CTxDB::ReadCheckpointPubKey(string& strPubKey)
 +{
 +    return Read(string("strCheckpointPubKey"), strPubKey);
 +}
 +
 +bool CTxDB::WriteCheckpointPubKey(const string& strPubKey)
 +{
 +    return Write(string("strCheckpointPubKey"), strPubKey);
  }
  
  CBlockIndex static * InsertBlockIndex(uint256 hash)
@@@ -522,10 -527,10 +550,10 @@@ bool CTxDB::LoadBlockIndex(
      loop
      {
          // Read next record
-         CDataStream ssKey;
+         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
          if (fFlags == DB_SET_RANGE)
              ssKey << make_pair(string("blockindex"), uint256(0));
-         CDataStream ssValue;
+         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
          int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
          fFlags = DB_NEXT;
          if (ret == DB_NOTFOUND)
              return false;
  
          // Unserialize
+         try {
          string strType;
          ssKey >> strType;
-         if (strType == "blockindex")
+         if (strType == "blockindex" && !fRequestShutdown)
          {
              CDiskBlockIndex diskindex;
              ssValue >> diskindex;
              pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
              pindexNew->nFile          = diskindex.nFile;
              pindexNew->nBlockPos      = diskindex.nBlockPos;
 +            pindexNew->nChainTrust    = diskindex.nChainTrust;
              pindexNew->nHeight        = diskindex.nHeight;
 +            pindexNew->fProofOfStake  = diskindex.fProofOfStake;
 +            pindexNew->prevoutStake   = diskindex.prevoutStake;
              pindexNew->nVersion       = diskindex.nVersion;
              pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
              pindexNew->nTime          = diskindex.nTime;
  
              if (!pindexNew->CheckIndex())
                  return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
 +
 +            // ppcoin: build setStakeSeen
 +            if (pindexNew->fProofOfStake)
 +                setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
          }
          else
          {
-             break;
+             break; // if shutdown requested or finished loading block index
+         }
+         }    // try
+         catch (std::exception &e) {
+             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
          }
      }
      pcursor->close();
  
+     if (fRequestShutdown)
+         return true;
 -    // Calculate bnChainWork
 -    vector<pair<int, CBlockIndex*> > vSortedByHeight;
 -    vSortedByHeight.reserve(mapBlockIndex.size());
 -    BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
 -    {
 -        CBlockIndex* pindex = item.second;
 -        vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
 -    }
 -    sort(vSortedByHeight.begin(), vSortedByHeight.end());
 -    BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
 -    {
 -        CBlockIndex* pindex = item.second;
 -        pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
 -    }
 -
      // Load hashBestChain pointer to end of best chain
      if (!ReadHashBestChain(hashBestChain))
      {
          return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
      pindexBest = mapBlockIndex[hashBestChain];
      nBestHeight = pindexBest->nHeight;
 -    bnBestChainWork = pindexBest->bnChainWork;
 -    printf("LoadBlockIndex(): hashBestChain=%s  height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);
 +    nBestChainTrust = pindexBest->nChainTrust;
 +    printf("LoadBlockIndex(): hashBestChain=%s  height=%d  trust=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, nBestChainTrust);
 +
 +    // ppcoin: load hashSyncCheckpoint
 +    if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint))
 +        return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded");
 +    printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str());
  
 -    // Load bnBestInvalidWork, OK if it doesn't exist
 -    ReadBestInvalidWork(bnBestInvalidWork);
 +    // Load nBestInvalidTrust, OK if it doesn't exist
 +    ReadBestInvalidTrust(nBestInvalidTrust);
  
      // Verify blocks in the best chain
+     int nCheckLevel = GetArg("-checklevel", 1);
+     int nCheckDepth = GetArg( "-checkblocks", 2500);
+     if (nCheckDepth == 0)
+         nCheckDepth = 1000000000; // suffices until the year 19000
+     if (nCheckDepth > nBestHeight)
+         nCheckDepth = nBestHeight;
+     printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
      CBlockIndex* pindexFork = NULL;
+     map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
      for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
      {
-         if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
+         if (pindex->nHeight < nBestHeight-nCheckDepth)
              break;
          CBlock block;
          if (!block.ReadFromDisk(pindex))
              return error("LoadBlockIndex() : block.ReadFromDisk failed");
-         if (!block.CheckBlock())
+         // check level 1: verify block validity
+         if (nCheckLevel>0 && !block.CheckBlock())
          {
              printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
              pindexFork = pindex->pprev;
          }
+         // check level 2: verify transaction index validity
+         if (nCheckLevel>1)
+         {
+             pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
+             mapBlockPos[pos] = pindex;
+             BOOST_FOREACH(const CTransaction &tx, block.vtx)
+             {
+                 uint256 hashTx = tx.GetHash();
+                 CTxIndex txindex;
+                 if (ReadTxIndex(hashTx, txindex))
+                 {
+                     // check level 3: checker transaction hashes
+                     if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
+                     {
+                         // either an error or a duplicate transaction
+                         CTransaction txFound;
+                         if (!txFound.ReadFromDisk(txindex.pos))
+                         {
+                             printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
+                             pindexFork = pindex->pprev;
+                         }
+                         else
+                             if (txFound.GetHash() != hashTx) // not a duplicate tx
+                             {
+                                 printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
+                                 pindexFork = pindex->pprev;
+                             }
+                     }
+                     // check level 4: check whether spent txouts were spent within the main chain
+                     unsigned int nOutput = 0;
+                     if (nCheckLevel>3)
+                     {
+                         BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
+                         {
+                             if (!txpos.IsNull())
+                             {
+                                 pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
+                                 if (!mapBlockPos.count(posFind))
+                                 {
+                                     printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
+                                     pindexFork = pindex->pprev;
+                                 }
+                                 // check level 6: check whether spent txouts were spent by a valid transaction that consume them
+                                 if (nCheckLevel>5)
+                                 {
+                                     CTransaction txSpend;
+                                     if (!txSpend.ReadFromDisk(txpos))
+                                     {
+                                         printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
+                                         pindexFork = pindex->pprev;
+                                     }
+                                     else if (!txSpend.CheckTransaction())
+                                     {
+                                         printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
+                                         pindexFork = pindex->pprev;
+                                     }
+                                     else
+                                     {
+                                         bool fFound = false;
+                                         BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
+                                             if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
+                                                 fFound = true;
+                                         if (!fFound)
+                                         {
+                                             printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
+                                             pindexFork = pindex->pprev;
+                                         }
+                                     }
+                                 }
+                             }
+                             nOutput++;
+                         }
+                     }
+                 }
+                 // check level 5: check whether all prevouts are marked spent
+                 if (nCheckLevel>4)
+                 {
+                      BOOST_FOREACH(const CTxIn &txin, tx.vin)
+                      {
+                           CTxIndex txindex;
+                           if (ReadTxIndex(txin.prevout.hash, txindex))
+                               if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
+                               {
+                                   printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
+                                   pindexFork = pindex->pprev;
+                               }
+                      }
+                 }
+             }
+         }
      }
      if (pindexFork)
      {
  // CAddrDB
  //
  
- bool CAddrDB::WriteAddress(const CAddress& addr)
- {
-     return Write(make_pair(string("addr"), addr.GetKey()), addr);
- }
- bool CAddrDB::EraseAddress(const CAddress& addr)
+ bool CAddrDB::WriteAddrman(const CAddrMan& addrman)
  {
-     return Erase(make_pair(string("addr"), addr.GetKey()));
+     return Write(string("addrman"), addrman);
  }
  
  bool CAddrDB::LoadAddresses()
  {
-     CRITICAL_BLOCK(cs_mapAddresses)
+     if (Read(string("addrman"), addrman))
      {
-         // Get cursor
-         Dbc* pcursor = GetCursor();
-         if (!pcursor)
-             return false;
-         loop
-         {
-             // Read next record
-             CDataStream ssKey;
-             CDataStream ssValue;
-             int ret = ReadAtCursor(pcursor, ssKey, ssValue);
-             if (ret == DB_NOTFOUND)
-                 break;
-             else if (ret != 0)
-                 return false;
-             // Unserialize
-             string strType;
-             ssKey >> strType;
-             if (strType == "addr")
-             {
-                 CAddress addr;
-                 ssValue >> addr;
-                 mapAddresses.insert(make_pair(addr.GetKey(), addr));
-             }
-         }
-         pcursor->close();
-         printf("Loaded %d addresses\n", mapAddresses.size());
+         printf("Loaded %i addresses\n", addrman.size());
+         return true;
      }
+     
+     // Read pre-0.6 addr records
  
-     return true;
- }
- bool LoadAddresses()
- {
-     return CAddrDB("cr+").LoadAddresses();
- }
- //
- // CWalletDB
- //
- bool CWalletDB::WriteName(const string& strAddress, const string& strName)
- {
-     nWalletDBUpdated++;
-     return Write(make_pair(string("name"), strAddress), strName);
- }
- bool CWalletDB::EraseName(const string& strAddress)
- {
-     // This should only be used for sending addresses, never for receiving addresses,
-     // receiving addresses must always have an address book entry if they're not change return.
-     nWalletDBUpdated++;
-     return Erase(make_pair(string("name"), strAddress));
- }
- bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
- {
-     account.SetNull();
-     return Read(make_pair(string("acc"), strAccount), account);
- }
- bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
- {
-     return Write(make_pair(string("acc"), strAccount), account);
- }
- bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
- {
-     return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
- }
- int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
- {
-     list<CAccountingEntry> entries;
-     ListAccountCreditDebit(strAccount, entries);
-     int64 nCreditDebit = 0;
-     BOOST_FOREACH (const CAccountingEntry& entry, entries)
-         nCreditDebit += entry.nCreditDebit;
-     return nCreditDebit;
- }
- void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
- {
-     bool fAllAccounts = (strAccount == "*");
+     vector<CAddress> vAddr;
+     vector<vector<unsigned char> > vDelete;
  
+     // Get cursor
      Dbc* pcursor = GetCursor();
      if (!pcursor)
-         throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
-     unsigned int fFlags = DB_SET_RANGE;
+         return false;
      loop
      {
          // Read next record
-         CDataStream ssKey;
-         if (fFlags == DB_SET_RANGE)
-             ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
-         CDataStream ssValue;
-         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
-         fFlags = DB_NEXT;
+         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
+         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
+         int ret = ReadAtCursor(pcursor, ssKey, ssValue);
          if (ret == DB_NOTFOUND)
              break;
          else if (ret != 0)
-         {
-             pcursor->close();
-             throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
-         }
+             return false;
  
          // Unserialize
          string strType;
          ssKey >> strType;
-         if (strType != "acentry")
-             break;
-         CAccountingEntry acentry;
-         ssKey >> acentry.strAccount;
-         if (!fAllAccounts && acentry.strAccount != strAccount)
-             break;
-         ssValue >> acentry;
-         entries.push_back(acentry);
-     }
-     pcursor->close();
- }
- int CWalletDB::LoadWallet(CWallet* pwallet)
- {
-     pwallet->vchDefaultKey.clear();
-     int nFileVersion = 0;
-     vector<uint256> vWalletUpgrade;
-     bool fIsEncrypted = false;
-     // Modify defaults
- #ifndef WIN32
-     // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
-     fMinimizeToTray = false;
-     fMinimizeOnClose = false;
- #endif
-     //// todo: shouldn't we catch exceptions and try to recover and continue?
-     CRITICAL_BLOCK(pwallet->cs_wallet)
-     {
-         // Get cursor
-         Dbc* pcursor = GetCursor();
-         if (!pcursor)
-             return DB_CORRUPT;
-         loop
+         if (strType == "addr")
          {
-             // Read next record
-             CDataStream ssKey;
-             CDataStream ssValue;
-             int ret = ReadAtCursor(pcursor, ssKey, ssValue);
-             if (ret == DB_NOTFOUND)
-                 break;
-             else if (ret != 0)
-                 return DB_CORRUPT;
-             // Unserialize
-             // Taking advantage of the fact that pair serialization
-             // is just the two items serialized one after the other
-             string strType;
-             ssKey >> strType;
-             if (strType == "name")
-             {
-                 string strAddress;
-                 ssKey >> strAddress;
-                 ssValue >> pwallet->mapAddressBook[strAddress];
-             }
-             else if (strType == "tx")
-             {
-                 uint256 hash;
-                 ssKey >> hash;
-                 CWalletTx& wtx = pwallet->mapWallet[hash];
-                 ssValue >> wtx;
-                 wtx.pwallet = pwallet;
-                 if (wtx.GetHash() != hash)
-                     printf("Error in wallet.dat, hash mismatch\n");
-                 // Undo serialize changes in 31600
-                 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
-                 {
-                     if (!ssValue.empty())
-                     {
-                         char fTmp;
-                         char fUnused;
-                         ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
-                         printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
-                         wtx.fTimeReceivedIsTxTime = fTmp;
-                     }
-                     else
-                     {
-                         printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
-                         wtx.fTimeReceivedIsTxTime = 0;
-                     }
-                     vWalletUpgrade.push_back(hash);
-                 }
-                 //// debug print
-                 //printf("LoadWallet  %s\n", wtx.GetHash().ToString().c_str());
-                 //printf(" %12I64d  %s  %s  %s\n",
-                 //    wtx.vout[0].nValue,
-                 //    DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
-                 //    wtx.hashBlock.ToString().substr(0,20).c_str(),
-                 //    wtx.mapValue["message"].c_str());
-             }
-             else if (strType == "acentry")
-             {
-                 string strAccount;
-                 ssKey >> strAccount;
-                 uint64 nNumber;
-                 ssKey >> nNumber;
-                 if (nNumber > nAccountingEntryNumber)
-                     nAccountingEntryNumber = nNumber;
-             }
-             else if (strType == "key" || strType == "wkey")
-             {
-                 vector<unsigned char> vchPubKey;
-                 ssKey >> vchPubKey;
-                 CKey key;
-                 if (strType == "key")
-                 {
-                     CPrivKey pkey;
-                     ssValue >> pkey;
-                     key.SetPrivKey(pkey);
-                 }
-                 else
-                 {
-                     CWalletKey wkey;
-                     ssValue >> wkey;
-                     key.SetPrivKey(wkey.vchPrivKey);
-                 }
-                 if (!pwallet->LoadKey(key))
-                     return DB_CORRUPT;
-             }
-             else if (strType == "mkey")
-             {
-                 unsigned int nID;
-                 ssKey >> nID;
-                 CMasterKey kMasterKey;
-                 ssValue >> kMasterKey;
-                 if(pwallet->mapMasterKeys.count(nID) != 0)
-                     return DB_CORRUPT;
-                 pwallet->mapMasterKeys[nID] = kMasterKey;
-                 if (pwallet->nMasterKeyMaxID < nID)
-                     pwallet->nMasterKeyMaxID = nID;
-             }
-             else if (strType == "ckey")
-             {
-                 vector<unsigned char> vchPubKey;
-                 ssKey >> vchPubKey;
-                 vector<unsigned char> vchPrivKey;
-                 ssValue >> vchPrivKey;
-                 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
-                     return DB_CORRUPT;
-                 fIsEncrypted = true;
-             }
-             else if (strType == "defaultkey")
-             {
-                 ssValue >> pwallet->vchDefaultKey;
-             }
-             else if (strType == "pool")
-             {
-                 int64 nIndex;
-                 ssKey >> nIndex;
-                 pwallet->setKeyPool.insert(nIndex);
-             }
-             else if (strType == "version")
-             {
-                 ssValue >> nFileVersion;
-                 if (nFileVersion == 10300)
-                     nFileVersion = 300;
-             }
-             else if (strType == "setting")
-             {
-                 string strKey;
-                 ssKey >> strKey;
-                 // Options
- #ifndef QT_GUI
-                 if (strKey == "fGenerateBitcoins")  ssValue >> fGenerateBitcoins;
- #endif
-                 if (strKey == "nTransactionFee")    ssValue >> nTransactionFee;
-                 if (strKey == "fLimitProcessors")   ssValue >> fLimitProcessors;
-                 if (strKey == "nLimitProcessors")   ssValue >> nLimitProcessors;
-                 if (strKey == "fMinimizeToTray")    ssValue >> fMinimizeToTray;
-                 if (strKey == "fMinimizeOnClose")   ssValue >> fMinimizeOnClose;
-                 if (strKey == "fUseProxy")          ssValue >> fUseProxy;
-                 if (strKey == "addrProxy")          ssValue >> addrProxy;
-                 if (fHaveUPnP && strKey == "fUseUPnP")           ssValue >> fUseUPnP;
-                 if (strKey == "nBalanceReserve")    ssValue >> nBalanceReserve;
-             }
-             else if (strType == "minversion")
-             {
-                 int nMinVersion = 0;
-                 ssValue >> nMinVersion;
-                 if (nMinVersion > VERSION)
-                     return DB_TOO_NEW;
-             }
+             CAddress addr;
+             ssValue >> addr;
+             vAddr.push_back(addr);
          }
-         pcursor->close();
      }
+     pcursor->close();
  
-     BOOST_FOREACH(uint256 hash, vWalletUpgrade)
-         WriteTx(hash, pwallet->mapWallet[hash]);
-     printf("nFileVersion = %d\n", nFileVersion);
-     printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
-     printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
-     printf("fMinimizeToTray = %d\n", fMinimizeToTray);
-     printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
-     printf("fUseProxy = %d\n", fUseProxy);
-     printf("addrProxy = %s\n", addrProxy.ToString().c_str());
-     if (fHaveUPnP)
-         printf("fUseUPnP = %d\n", fUseUPnP);
-     // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
-     if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
-         return DB_NEED_REWRITE;
+     addrman.Add(vAddr, CNetAddr("0.0.0.0"));
+     printf("Loaded %i addresses\n", addrman.size());
  
-     if (nFileVersion < VERSION) // Update
-     {
-         // Get rid of old debug.log file in current directory
-         if (nFileVersion <= 105 && !pszSetDataDir[0])
-             unlink("debug.log");
+     // Note: old records left; we ran into hangs-on-startup
+     // bugs for some users who (we think) were running after
+     // an unclean shutdown.
  
-         WriteVersion(VERSION);
-     }
-     return DB_LOAD_OK;
+     return true;
  }
  
- void ThreadFlushWalletDB(void* parg)
+ bool LoadAddresses()
  {
-     const string& strFile = ((const string*)parg)[0];
-     static bool fOneThread;
-     if (fOneThread)
-         return;
-     fOneThread = true;
-     if (mapArgs.count("-noflushwallet"))
-         return;
-     unsigned int nLastSeen = nWalletDBUpdated;
-     unsigned int nLastFlushed = nWalletDBUpdated;
-     int64 nLastWalletUpdate = GetTime();
-     while (!fShutdown)
-     {
-         Sleep(500);
-         if (nLastSeen != nWalletDBUpdated)
-         {
-             nLastSeen = nWalletDBUpdated;
-             nLastWalletUpdate = GetTime();
-         }
-         if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
-         {
-             TRY_CRITICAL_BLOCK(cs_db)
-             {
-                 // Don't do this if any databases are in use
-                 int nRefCount = 0;
-                 map<string, int>::iterator mi = mapFileUseCount.begin();
-                 while (mi != mapFileUseCount.end())
-                 {
-                     nRefCount += (*mi).second;
-                     mi++;
-                 }
-                 if (nRefCount == 0 && !fShutdown)
-                 {
-                     map<string, int>::iterator mi = mapFileUseCount.find(strFile);
-                     if (mi != mapFileUseCount.end())
-                     {
-                         printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
-                         printf("Flushing wallet.dat\n");
-                         nLastFlushed = nWalletDBUpdated;
-                         int64 nStart = GetTimeMillis();
-                         // Flush wallet.dat so it's self contained
-                         CloseDb(strFile);
-                         dbenv.txn_checkpoint(0, 0, 0);
-                         dbenv.lsn_reset(strFile.c_str(), 0);
-                         mapFileUseCount.erase(mi++);
-                         printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
-                     }
-                 }
-             }
-         }
-     }
+     return CAddrDB("cr+").LoadAddresses();
  }
  
- bool BackupWallet(const CWallet& wallet, const string& strDest)
- {
-     if (!wallet.fFileBacked)
-         return false;
-     while (!fShutdown)
-     {
-         CRITICAL_BLOCK(cs_db)
-         {
-             if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
-             {
-                 // Flush log data to the dat file
-                 CloseDb(wallet.strWalletFile);
-                 dbenv.txn_checkpoint(0, 0, 0);
-                 dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
-                 mapFileUseCount.erase(wallet.strWalletFile);
-                 // Copy wallet.dat
-                 filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
-                 filesystem::path pathDest(strDest);
-                 if (filesystem::is_directory(pathDest))
-                     pathDest = pathDest / wallet.strWalletFile;
- #if BOOST_VERSION >= 104000
-                 filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
- #else
-                 filesystem::copy_file(pathSrc, pathDest);
- #endif
-                 printf("copied wallet.dat to %s\n", pathDest.string().c_str());
  
-                 return true;
-             }
-         }
-         Sleep(100);
-     }
-     return false;
- }
diff --combined src/db.h
+++ b/src/db.h
@@@ -1,12 -1,11 +1,12 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_DB_H
  #define BITCOIN_DB_H
  
- #include "key.h"
+ #include "main.h"
  
  #include <map>
  #include <string>
  
  #include <db_cxx.h>
  
- class CTxIndex;
+ class CAddress;
+ class CAddrMan;
+ class CBlockLocator;
  class CDiskBlockIndex;
  class CDiskTxPos;
+ class CMasterKey;
  class COutPoint;
- class CAddress;
- class CWalletTx;
+ class CTxIndex;
  class CWallet;
- class CAccount;
- class CAccountingEntry;
- class CBlockLocator;
+ class CWalletTx;
  
  extern unsigned int nWalletDBUpdated;
+ extern bool fDetachDB;
  extern DbEnv dbenv;
  
  extern void DBFlush(bool fShutdown);
@@@ -34,7 -33,7 +34,7 @@@ void ThreadFlushWalletDB(void* parg)
  bool BackupWallet(const CWallet& wallet, const std::string& strDest);
  
  
+ /** RAII class that provides access to a Berkeley database */
  class CDB
  {
  protected:
@@@ -59,7 -58,7 +59,7 @@@ protected
              return false;
  
          // Key
-         CDataStream ssKey(SER_DISK);
+         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
          ssKey.reserve(1000);
          ssKey << key;
          Dbt datKey(&ssKey[0], ssKey.size());
              return false;
  
          // Unserialize value
-         CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
-         ssValue >> value;
+         try {
+             CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
+             ssValue >> value;
+         }
+         catch (std::exception &e) {
+             return false;
+         }
  
          // Clear and free memory
          memset(datValue.get_data(), 0, datValue.get_size());
              assert(!"Write called on database in read-only mode");
  
          // Key
-         CDataStream ssKey(SER_DISK);
+         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
          ssKey.reserve(1000);
          ssKey << key;
          Dbt datKey(&ssKey[0], ssKey.size());
  
          // Value
-         CDataStream ssValue(SER_DISK);
+         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
          ssValue.reserve(10000);
          ssValue << value;
          Dbt datValue(&ssValue[0], ssValue.size());
              assert(!"Erase called on database in read-only mode");
  
          // Key
-         CDataStream ssKey(SER_DISK);
+         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
          ssKey.reserve(1000);
          ssKey << key;
          Dbt datKey(&ssKey[0], ssKey.size());
              return false;
  
          // Key
-         CDataStream ssKey(SER_DISK);
+         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
          ssKey.reserve(1000);
          ssKey << key;
          Dbt datKey(&ssKey[0], ssKey.size());
@@@ -217,7 -221,7 +222,7 @@@ public
          if (!pdb)
              return false;
          DbTxn* ptxn = NULL;
-         int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC);
+         int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_WRITE_NOSYNC);
          if (!ptxn || ret != 0)
              return false;
          vTxn.push_back(ptxn);
  
  
  
+ /** Access to the transaction database (blkindex.dat) */
  class CTxDB : public CDB
  {
  public:
@@@ -289,19 -293,15 +294,19 @@@ public
      bool EraseBlockIndex(uint256 hash);
      bool ReadHashBestChain(uint256& hashBestChain);
      bool WriteHashBestChain(uint256 hashBestChain);
 -    bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
 -    bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
 +    bool ReadBestInvalidTrust(uint64& nBestInvalidTrust);
 +    bool WriteBestInvalidTrust(uint64 nBestInvalidTrust);
 +    bool ReadSyncCheckpoint(uint256& hashCheckpoint);
 +    bool WriteSyncCheckpoint(uint256 hashCheckpoint);
 +    bool ReadCheckpointPubKey(std::string& strPubKey);
 +    bool WriteCheckpointPubKey(const std::string& strPubKey);
      bool LoadBlockIndex();
  };
  
  
  
  
+ /** Access to the (IP) address database (addr.dat) */
  class CAddrDB : public CDB
  {
  public:
@@@ -310,181 -310,11 +315,11 @@@ private
      CAddrDB(const CAddrDB&);
      void operator=(const CAddrDB&);
  public:
-     bool WriteAddress(const CAddress& addr);
-     bool EraseAddress(const CAddress& addr);
+     bool WriteAddrman(const CAddrMan& addr);
      bool LoadAddresses();
  };
  
  bool LoadAddresses();
  
  
- class CKeyPool
- {
- public:
-     int64 nTime;
-     std::vector<unsigned char> vchPubKey;
-     CKeyPool()
-     {
-         nTime = GetTime();
-     }
-     CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
-     {
-         nTime = GetTime();
-         vchPubKey = vchPubKeyIn;
-     }
-     IMPLEMENT_SERIALIZE
-     (
-         if (!(nType & SER_GETHASH))
-             READWRITE(nVersion);
-         READWRITE(nTime);
-         READWRITE(vchPubKey);
-     )
- };
- enum DBErrors
- {
-     DB_LOAD_OK,
-     DB_CORRUPT,
-     DB_TOO_NEW,
-     DB_LOAD_FAIL,
-     DB_NEED_REWRITE
- };
- class CWalletDB : public CDB
- {
- public:
-     CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
-     {
-     }
- private:
-     CWalletDB(const CWalletDB&);
-     void operator=(const CWalletDB&);
- public:
-     bool ReadName(const std::string& strAddress, std::string& strName)
-     {
-         strName = "";
-         return Read(std::make_pair(std::string("name"), strAddress), strName);
-     }
-     bool WriteName(const std::string& strAddress, const std::string& strName);
-     bool EraseName(const std::string& strAddress);
-     bool ReadTx(uint256 hash, CWalletTx& wtx)
-     {
-         return Read(std::make_pair(std::string("tx"), hash), wtx);
-     }
-     bool WriteTx(uint256 hash, const CWalletTx& wtx)
-     {
-         nWalletDBUpdated++;
-         return Write(std::make_pair(std::string("tx"), hash), wtx);
-     }
-     bool EraseTx(uint256 hash)
-     {
-         nWalletDBUpdated++;
-         return Erase(std::make_pair(std::string("tx"), hash));
-     }
-     bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
-     {
-         vchPrivKey.clear();
-         return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey);
-     }
-     bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
-     {
-         nWalletDBUpdated++;
-         return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
-     }
-     bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
-     {
-         nWalletDBUpdated++;
-         if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
-             return false;
-         if (fEraseUnencryptedKey)
-         {
-             Erase(std::make_pair(std::string("key"), vchPubKey));
-             Erase(std::make_pair(std::string("wkey"), vchPubKey));
-         }
-         return true;
-     }
-     bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
-     {
-         nWalletDBUpdated++;
-         return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
-     }
-     bool WriteBestBlock(const CBlockLocator& locator)
-     {
-         nWalletDBUpdated++;
-         return Write(std::string("bestblock"), locator);
-     }
-     bool ReadBestBlock(CBlockLocator& locator)
-     {
-         return Read(std::string("bestblock"), locator);
-     }
-     bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey)
-     {
-         vchPubKey.clear();
-         return Read(std::string("defaultkey"), vchPubKey);
-     }
-     bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
-     {
-         nWalletDBUpdated++;
-         return Write(std::string("defaultkey"), vchPubKey);
-     }
-     bool ReadPool(int64 nPool, CKeyPool& keypool)
-     {
-         return Read(std::make_pair(std::string("pool"), nPool), keypool);
-     }
-     bool WritePool(int64 nPool, const CKeyPool& keypool)
-     {
-         nWalletDBUpdated++;
-         return Write(std::make_pair(std::string("pool"), nPool), keypool);
-     }
-     bool ErasePool(int64 nPool)
-     {
-         nWalletDBUpdated++;
-         return Erase(std::make_pair(std::string("pool"), nPool));
-     }
-     template<typename T>
-     bool ReadSetting(const std::string& strKey, T& value)
-     {
-         return Read(std::make_pair(std::string("setting"), strKey), value);
-     }
-     template<typename T>
-     bool WriteSetting(const std::string& strKey, const T& value)
-     {
-         nWalletDBUpdated++;
-         return Write(std::make_pair(std::string("setting"), strKey), value);
-     }
-     bool ReadAccount(const std::string& strAccount, CAccount& account);
-     bool WriteAccount(const std::string& strAccount, const CAccount& account);
-     bool WriteAccountingEntry(const CAccountingEntry& acentry);
-     int64 GetAccountCreditDebit(const std::string& strAccount);
-     void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
-     int LoadWallet(CWallet* pwallet);
- };
- #endif
+ #endif // BITCOIN_DB_H
diff --combined src/init.cpp
@@@ -1,26 -1,21 +1,22 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
- #include "headers.h"
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #include "db.h"
+ #include "walletdb.h"
  #include "bitcoinrpc.h"
  #include "net.h"
  #include "init.h"
- #include "strlcpy.h"
+ #include "util.h"
+ #include "ui_interface.h"
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
+ #include <boost/filesystem/convenience.hpp>
  #include <boost/interprocess/sync/file_lock.hpp>
  
- #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
- #define _BITCOIN_QT_PLUGINS_INCLUDED
- #define __INSURE__
- #include <QtPlugin>
- Q_IMPORT_PLUGIN(qcncodecs)
- Q_IMPORT_PLUGIN(qjpcodecs)
- Q_IMPORT_PLUGIN(qtwcodecs)
- Q_IMPORT_PLUGIN(qkrcodecs)
+ #ifndef WIN32
+ #include <signal.h>
  #endif
  
  using namespace std;
@@@ -41,15 -36,29 +37,29 @@@ void ExitTimeout(void* parg
  #endif
  }
  
+ void StartShutdown()
+ {
+ #ifdef QT_GUI
+     // ensure we leave the Qt main loop for a clean GUI exit (Shutdown() is called in bitcoin.cpp afterwards)
+     QueueShutdown();
+ #else
+     // Without UI, Shutdown() can simply be started in a new thread
+     CreateThread(Shutdown, NULL);
+ #endif
+ }
  void Shutdown(void* parg)
  {
      static CCriticalSection cs_Shutdown;
      static bool fTaken;
      bool fFirstThread = false;
-     TRY_CRITICAL_BLOCK(cs_Shutdown)
      {
-         fFirstThread = !fTaken;
-         fTaken = true;
+         TRY_LOCK(cs_Shutdown, lockShutdown);
+         if (lockShutdown)
+         {
+             fFirstThread = !fTaken;
+             fTaken = true;
+         }
      }
      static bool fExit;
      if (fFirstThread)
          delete pwalletMain;
          CreateThread(ExitTimeout, NULL);
          Sleep(50);
 -        printf("Bitcoin exiting\n\n");
 +        printf("PPCoin exiting\n\n");
          fExit = true;
+ #ifndef QT_GUI
+         // ensure non UI client get's exited here, but let Bitcoin-Qt reach return 0; in bitcoin.cpp
          exit(0);
+ #endif
      }
      else
      {
@@@ -92,7 -104,6 +105,7 @@@ void HandleSIGTERM(int
  // Start
  //
  #if !defined(QT_GUI)
 +#if !defined(PPCOIN_GENESIS)
  int main(int argc, char* argv[])
  {
      bool fRet = false;
      return 1;
  }
  #endif
 +#endif
  
  bool AppInit(int argc, char* argv[])
  {
@@@ -151,105 -161,118 +164,117 @@@ bool AppInit2(int argc, char* argv[]
      //
      // Parameters
      //
+     // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
+ #if !defined(QT_GUI)
      ParseParameters(argc, argv);
-     if (mapArgs.count("-datadir"))
+     if (!boost::filesystem::is_directory(GetDataDir(false)))
      {
-         if (filesystem::is_directory(filesystem::system_complete(mapArgs["-datadir"])))
-         {
-             filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
-             strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
-         }
-         else
-         {
-             fprintf(stderr, "Error: Specified directory does not exist\n");
-             Shutdown(NULL);
-         }
+         fprintf(stderr, "Error: Specified directory does not exist\n");
+         Shutdown(NULL);
      }
-     ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
+     ReadConfigFile(mapArgs, mapMultiArgs);
+ #endif
  
      if (mapArgs.count("-?") || mapArgs.count("--help"))
      {
          string strUsage = string() +
 -          _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" +
 +          _("PPCoin version") + " " + FormatFullVersion() + "\n\n" +
            _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
 -            "  bitcoind [options]                   \t  " + "\n" +
 -            "  bitcoind [options] <command> [params]\t  " + _("Send command to -server or bitcoind") + "\n" +
 -            "  bitcoind [options] help              \t\t  " + _("List commands") + "\n" +
 -            "  bitcoind [options] help <command>    \t\t  " + _("Get help for a command") + "\n" +
 +            "  ppcoind [options]                   \t  " + "\n" +
-             "  ppcoind [options] <command> [params]\t  " + _("Send command to -server or ppcoind\n") +
-             "  ppcoind [options] help              \t\t  " + _("List commands\n") +
-             "  ppcoind [options] help <command>    \t\t  " + _("Get help for a command\n") +
-           _("Options:\n") +
-             "  -conf=<file>     \t\t  " + _("Specify configuration file (default: ppcoin.conf)\n") +
-             "  -pid=<file>      \t\t  " + _("Specify pid file (default: ppcoind.pid)\n") +
-             "  -gen             \t\t  " + _("Generate coins\n") +
-             "  -gen=0           \t\t  " + _("Don't generate coins\n") +
-             "  -min             \t\t  " + _("Start minimized\n") +
-             "  -datadir=<dir>   \t\t  " + _("Specify data directory\n") +
-             "  -timeout=<n>     \t  "   + _("Specify connection timeout (in milliseconds)\n") +
-             "  -proxy=<ip:port> \t  "   + _("Connect through socks4 proxy\n") +
-             "  -dns             \t  "   + _("Allow DNS lookups for addnode and connect\n") +
-             "  -port=<port>     \t\t  " + _("Listen for connections on <port> (default: 9901 or testnet: 9903)\n") +
-             "  -maxconnections=<n>\t  " + _("Maintain at most <n> connections to peers (default: 125)\n") +
-             "  -addnode=<ip>    \t  "   + _("Add a node to connect to\n") +
-             "  -connect=<ip>    \t\t  " + _("Connect only to the specified node\n") +
-             "  -nolisten        \t  "   + _("Don't accept connections from outside\n") +
-             "  -nodnsseed       \t  "   + _("Don't bootstrap list of peers using DNS\n") +
-             "  -banscore=<n>    \t  "   + _("Threshold for disconnecting misbehaving peers (default: 100)\n") +
-             "  -bantime=<n>     \t  "   + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)\n") +
-             "  -maxreceivebuffer=<n>\t  " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)\n") +
-             "  -maxsendbuffer=<n>\t  "   + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)\n") +
++            "  ppcoind [options] <command> [params]\t  " + _("Send command to -server or ppcoind") + "\n" +
++            "  ppcoind [options] help              \t\t  " + _("List commands") + "\n" +
++            "  ppcoind [options] help <command>    \t\t  " + _("Get help for a command") + "\n" +
+           _("Options:") + "\n" +
 -            "  -conf=<file>     \t\t  " + _("Specify configuration file (default: bitcoin.conf)") + "\n" +
 -            "  -pid=<file>      \t\t  " + _("Specify pid file (default: bitcoind.pid)") + "\n" +
++            "  -conf=<file>     \t\t  " + _("Specify configuration file (default: ppcoin.conf)") + "\n" +
++            "  -pid=<file>      \t\t  " + _("Specify pid file (default: ppcoind.pid)") + "\n" +
+             "  -gen             \t\t  " + _("Generate coins") + "\n" +
+             "  -gen=0           \t\t  " + _("Don't generate coins") + "\n" +
+             "  -min             \t\t  " + _("Start minimized") + "\n" +
+             "  -splash          \t\t  " + _("Show splash screen on startup (default: 1)") + "\n" +
+             "  -datadir=<dir>   \t\t  " + _("Specify data directory") + "\n" +
+             "  -dbcache=<n>     \t\t  " + _("Set database cache size in megabytes (default: 25)") + "\n" +
+             "  -dblogsize=<n>   \t\t  " + _("Set database disk log size in megabytes (default: 100)") + "\n" +
+             "  -timeout=<n>     \t  "   + _("Specify connection timeout (in milliseconds)") + "\n" +
+             "  -proxy=<ip:port> \t  "   + _("Connect through socks4 proxy") + "\n" +
+             "  -dns             \t  "   + _("Allow DNS lookups for addnode and connect") + "\n" +
 -            "  -port=<port>     \t\t  " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" +
++            "  -port=<port>     \t\t  " + _("Listen for connections on <port> (default: 9901 or testnet: 9903)") + "\n" +
+             "  -maxconnections=<n>\t  " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" +
+             "  -addnode=<ip>    \t  "   + _("Add a node to connect to and attempt to keep the connection open") + "\n" +
+             "  -connect=<ip>    \t\t  " + _("Connect only to the specified node") + "\n" +
 -            "  -irc             \t  "   + _("Find peers using internet relay chat (default: 0)") + "\n" +
+             "  -listen          \t  "   + _("Accept connections from outside (default: 1)") + "\n" +
+ #ifdef QT_GUI
+             "  -lang=<lang>     \t\t  " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
+ #endif
+             "  -dnsseed         \t  "   + _("Find peers using DNS lookup (default: 1)") + "\n" +
+             "  -banscore=<n>    \t  "   + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
+             "  -bantime=<n>     \t  "   + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
+             "  -maxreceivebuffer=<n>\t  " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)") + "\n" +
+             "  -maxsendbuffer=<n>\t  "   + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)") + "\n" +
  #ifdef USE_UPNP
  #if USE_UPNP
-             "  -noupnp          \t  "   + _("Don't attempt to use UPnP to map the listening port\n") +
+             "  -upnp            \t  "   + _("Use Universal Plug and Play to map the listening port (default: 1)") + "\n" +
  #else
-             "  -upnp            \t  "   + _("Attempt to use UPnP to map the listening port\n") +
+             "  -upnp            \t  "   + _("Use Universal Plug and Play to map the listening port (default: 0)") + "\n" +
  #endif
+             "  -detachdb        \t  "   + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" +
  #endif
-             "  -paytxfee=<amt>  \t  "   + _("Fee per KB to add to transactions you send\n") +
- #ifdef GUI
-             "  -server          \t\t  " + _("Accept command line and JSON-RPC commands\n") +
+             "  -paytxfee=<amt>  \t  "   + _("Fee per KB to add to transactions you send") + "\n" +
+ #ifdef QT_GUI
+             "  -server          \t\t  " + _("Accept command line and JSON-RPC commands") + "\n" +
  #endif
- #ifndef WIN32
-             "  -daemon          \t\t  " + _("Run in the background as a daemon and accept commands\n") +
+ #if !defined(WIN32) && !defined(QT_GUI)
+             "  -daemon          \t\t  " + _("Run in the background as a daemon and accept commands") + "\n" +
  #endif
-             "  -testnet         \t\t  " + _("Use the test network\n") +
-             "  -debug           \t\t  " + _("Output extra debugging information\n") +
-             "  -logtimestamps   \t  "   + _("Prepend debug output with timestamp\n") +
-             "  -printtoconsole  \t  "   + _("Send trace/debug info to console instead of debug.log file\n") +
+             "  -testnet         \t\t  " + _("Use the test network") + "\n" +
+             "  -debug           \t\t  " + _("Output extra debugging information") + "\n" +
+             "  -logtimestamps   \t  "   + _("Prepend debug output with timestamp") + "\n" +
+             "  -printtoconsole  \t  "   + _("Send trace/debug info to console instead of debug.log file") + "\n" +
  #ifdef WIN32
-             "  -printtodebugger \t  "   + _("Send trace/debug info to debugger\n") +
+             "  -printtodebugger \t  "   + _("Send trace/debug info to debugger") + "\n" +
  #endif
-             "  -rpcuser=<user>  \t  "   + _("Username for JSON-RPC connections\n") +
-             "  -rpcpassword=<pw>\t  "   + _("Password for JSON-RPC connections\n") +
-             "  -rpcport=<port>  \t\t  " + _("Listen for JSON-RPC connections on <port> (default: 9902)\n") +
-             "  -rpcallowip=<ip> \t\t  " + _("Allow JSON-RPC connections from specified IP address\n") +
-             "  -rpcconnect=<ip> \t  "   + _("Send commands to node running on <ip> (default: 127.0.0.1)\n") +
-             "  -keypool=<n>     \t  "   + _("Set key pool size to <n> (default: 100)\n") +
-             "  -rescan          \t  "   + _("Rescan the block chain for missing wallet transactions\n");
- #ifdef USE_SSL
+             "  -rpcuser=<user>  \t  "   + _("Username for JSON-RPC connections") + "\n" +
+             "  -rpcpassword=<pw>\t  "   + _("Password for JSON-RPC connections") + "\n" +
 -            "  -rpcport=<port>  \t\t  " + _("Listen for JSON-RPC connections on <port> (default: 8332)") + "\n" +
++            "  -rpcport=<port>  \t\t  " + _("Listen for JSON-RPC connections on <port> (default: 9902)") + "\n" +
+             "  -rpcallowip=<ip> \t\t  " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
+             "  -rpcconnect=<ip> \t  "   + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
+             "  -blocknotify=<cmd> "     + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
+             "  -upgradewallet   \t  "   + _("Upgrade wallet to latest format") + "\n" +
+             "  -keypool=<n>     \t  "   + _("Set key pool size to <n> (default: 100)") + "\n" +
+             "  -rescan          \t  "   + _("Rescan the block chain for missing wallet transactions") + "\n" +
+             "  -checkblocks=<n> \t\t  " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
+             "  -checklevel=<n>  \t\t  " + _("How thorough the block verification is (0-6, default: 1)") + "\n";
          strUsage += string() +
-             _("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)\n") +
-             "  -rpcssl                                \t  " + _("Use OpenSSL (https) for JSON-RPC connections\n") +
-             "  -rpcsslcertificatechainfile=<file.cert>\t  " + _("Server certificate file (default: server.cert)\n") +
-             "  -rpcsslprivatekeyfile=<file.pem>       \t  " + _("Server private key (default: server.pem)\n") +
-             "  -rpcsslciphers=<ciphers>               \t  " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)\n");
- #endif
+             _("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" +
+             "  -rpcssl                                \t  " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" +
+             "  -rpcsslcertificatechainfile=<file.cert>\t  " + _("Server certificate file (default: server.cert)") + "\n" +
+             "  -rpcsslprivatekeyfile=<file.pem>       \t  " + _("Server private key (default: server.pem)") + "\n" +
+             "  -rpcsslciphers=<ciphers>               \t  " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n";
  
          strUsage += string() +
-             "  -?               \t\t  " + _("This help message\n");
+             "  -?               \t\t  " + _("This help message") + "\n";
  
          // Remove tabs
          strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
+ #if defined(QT_GUI) && defined(WIN32)
+         // On windows, show a message box, as there is no stderr
+         ThreadSafeMessageBox(strUsage, _("Usage"), wxOK | wxMODAL);
+ #else
          fprintf(stderr, "%s", strUsage.c_str());
+ #endif
          return false;
      }
  
+     fTestNet = GetBoolArg("-testnet");
+     if (fTestNet)
+     {
+         SoftSetBoolArg("-irc", true);
+     }
      fDebug = GetBoolArg("-debug");
-     fAllowDNS = GetBoolArg("-dns");
+     fDetachDB = GetBoolArg("-detachdb", false);
  
- #ifndef WIN32
+ #if !defined(WIN32) && !defined(QT_GUI)
      fDaemon = GetBoolArg("-daemon");
  #else
      fDaemon = false;
  #endif
      fPrintToConsole = GetBoolArg("-printtoconsole");
      fPrintToDebugger = GetBoolArg("-printtodebugger");
-     fTestNet = GetBoolArg("-testnet");
-     bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
-     fNoListen = GetBoolArg("-nolisten") || fTOR;
      fLogTimestamps = GetBoolArg("-logtimestamps");
  
  #ifndef QT_GUI
      for (int i = 1; i < argc; i++)
-         if (!IsSwitchChar(argv[i][0]))
+         if (!IsSwitchChar(argv[i][0]) && !(strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0))
              fCommandLine = true;
  
      if (fCommandLine)
      }
  #endif
  
- #ifndef WIN32
+ #if !defined(WIN32) && !defined(QT_GUI)
      if (fDaemon)
      {
          // Daemonize
      }
  #endif
  
-     if (!fDebug && !pszSetDataDir[0])
+     if (!fDebug)
          ShrinkDebugFile();
      printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
-     printf("PPCoin version %s\n", FormatFullVersion().c_str());
-     printf("Default data directory %s\n", GetDefaultDataDir().c_str());
 -    printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
++    printf("PPCoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
+     printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
  
      if (GetBoolArg("-loadblockindextest"))
      {
      }
  
      // Make sure only a single bitcoin process is using the data directory.
-     string strLockFile = GetDataDir() + "/.lock";
-     FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
+     boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
+     FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
      if (file) fclose(file);
-     static boost::interprocess::file_lock lock(strLockFile.c_str());
+     static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
      if (!lock.try_lock())
      {
-         wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s.  PPCoin is probably already running."), GetDataDir().c_str()), "PPCoin");
 -        ThreadSafeMessageBox(strprintf(_("Cannot obtain a lock on data directory %s.  Bitcoin is probably already running."), GetDataDir().string().c_str()), _("Bitcoin"), wxOK|wxMODAL);
++        ThreadSafeMessageBox(strprintf(_("Cannot obtain a lock on data directory %s.  PPCoin is probably already running."), GetDataDir().string().c_str()), _("PPCoin"), wxOK|wxMODAL);
          return false;
      }
  
-     // Bind to the port early so we can tell if another instance is already running.
-     string strErrors;
-     if (!fNoListen)
-     {
-         if (!BindListenPort(strErrors))
-         {
-             wxMessageBox(strErrors, "PPCoin");
-             return false;
-         }
-     }
+     std::ostringstream strErrors;
      //
      // Load data files
      //
      if (fDaemon)
 -        fprintf(stdout, "bitcoin server starting\n");
 +        fprintf(stdout, "ppcoin server starting\n");
-     strErrors = "";
      int64 nStart;
  
      InitMessage(_("Loading addresses..."));
      printf("Loading addresses...\n");
      nStart = GetTimeMillis();
      if (!LoadAddresses())
-         strErrors += _("Error loading addr.dat      \n");
+         strErrors << _("Error loading addr.dat") << "\n";
      printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
      InitMessage(_("Loading block index..."));
      printf("Loading block index...\n");
      nStart = GetTimeMillis();
      if (!LoadBlockIndex())
-         strErrors += _("Error loading blkindex.dat      \n");
+         strErrors << _("Error loading blkindex.dat") << "\n";
+     // as LoadBlockIndex can take several minutes, it's possible the user
+     // requested to kill bitcoin-qt during the last operation. If so, exit.
+     // As the program has not fully started yet, Shutdown() is possibly overkill.
+     if (fRequestShutdown)
+     {
+         printf("Shutdown requested. Exiting.\n");
+         return false;
+     }
      printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
      InitMessage(_("Loading wallet..."));
      if (nLoadWalletRet != DB_LOAD_OK)
      {
          if (nLoadWalletRet == DB_CORRUPT)
-             strErrors += _("Error loading wallet.dat: Wallet corrupted      \n");
+             strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
          else if (nLoadWalletRet == DB_TOO_NEW)
-             strErrors += _("Error loading wallet.dat: Wallet requires newer version of PPCoin      \n");
 -            strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin") << "\n";
++            strErrors << _("Error loading wallet.dat: Wallet requires newer version of PPCoin") << "\n";
          else if (nLoadWalletRet == DB_NEED_REWRITE)
          {
-             strErrors += _("Wallet needed to be rewritten: restart PPCoin to complete    \n");
-             wxMessageBox(strErrors, "PPCoin", wxOK | wxICON_ERROR);
 -            strErrors << _("Wallet needed to be rewritten: restart Bitcoin to complete") << "\n";
++            strErrors << _("Wallet needed to be rewritten: restart PPCoin to complete") << "\n";
+             printf("%s", strErrors.str().c_str());
 -            ThreadSafeMessageBox(strErrors.str(), _("Bitcoin"), wxOK | wxICON_ERROR | wxMODAL);
++            ThreadSafeMessageBox(strErrors.str(), _("PPCoin"), wxOK | wxICON_ERROR | wxMODAL);
              return false;
          }
          else
-             strErrors += _("Error loading wallet.dat      \n");
+             strErrors << _("Error loading wallet.dat") << "\n";
+     }
+     if (GetBoolArg("-upgradewallet", fFirstRun))
+     {
+         int nMaxVersion = GetArg("-upgradewallet", 0);
+         if (nMaxVersion == 0) // the -walletupgrade without argument case
+         {
+             printf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
+             nMaxVersion = CLIENT_VERSION;
+             pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
+         }
+         else
+             printf("Allowing wallet upgrade up to %i\n", nMaxVersion);
+         if (nMaxVersion < pwalletMain->GetVersion())
+             strErrors << _("Cannot downgrade wallet") << "\n";
+         pwalletMain->SetMaxVersion(nMaxVersion);
+     }
+     if (fFirstRun)
+     {
+         // Create new keyUser and set as default key
+         RandAddSeedPerfmon();
+         std::vector<unsigned char> newDefaultKey;
+         if (!pwalletMain->GetKeyFromPool(newDefaultKey, false))
+             strErrors << _("Cannot initialize keypool") << "\n";
+         pwalletMain->SetDefaultKey(newDefaultKey);
+         if (!pwalletMain->SetAddressBookName(CBitcoinAddress(pwalletMain->vchDefaultKey), ""))
+             strErrors << _("Cannot write default address") << "\n";
      }
+     printf("%s", strErrors.str().c_str());
      printf(" wallet      %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
      RegisterWallet(pwalletMain);
      InitMessage(_("Done loading"));
      printf("Done loading\n");
  
-         //// debug print
-         printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());
-         printf("nBestHeight = %d\n",            nBestHeight);
-         printf("setKeyPool.size() = %d\n",      pwalletMain->setKeyPool.size());
-         printf("mapWallet.size() = %d\n",       pwalletMain->mapWallet.size());
-         printf("mapAddressBook.size() = %d\n",  pwalletMain->mapAddressBook.size());
+     //// debug print
+     printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());
+     printf("nBestHeight = %d\n",            nBestHeight);
+     printf("setKeyPool.size() = %d\n",      pwalletMain->setKeyPool.size());
+     printf("mapWallet.size() = %d\n",       pwalletMain->mapWallet.size());
+     printf("mapAddressBook.size() = %d\n",  pwalletMain->mapAddressBook.size());
  
-     if (!strErrors.empty())
+     if (!strErrors.str().empty())
      {
-         wxMessageBox(strErrors, "PPCoin", wxOK | wxICON_ERROR);
 -        ThreadSafeMessageBox(strErrors.str(), _("Bitcoin"), wxOK | wxICON_ERROR | wxMODAL);
++        ThreadSafeMessageBox(strErrors.str(), _("PPCoin"), wxOK | wxICON_ERROR | wxMODAL);
          return false;
      }
  
      // Add wallet transactions that aren't already in a block to mapTransactions
      pwalletMain->ReacceptWalletTransactions();
  
+     // Note: Bitcoin-QT stores several settings in the wallet, so we want
+     // to load the wallet BEFORE parsing command-line arguments, so
+     // the command-line/bitcoin.conf settings override GUI setting.
      //
      // Parameters
      //
          return false;
      }
  
      if (mapArgs.count("-proxy"))
      {
          fUseProxy = true;
-         addrProxy = CAddress(mapArgs["-proxy"]);
+         addrProxy = CService(mapArgs["-proxy"], 9050);
          if (!addrProxy.IsValid())
          {
-             wxMessageBox(_("Invalid -proxy address"), "PPCoin");
 -            ThreadSafeMessageBox(_("Invalid -proxy address"), _("Bitcoin"), wxOK | wxMODAL);
++            ThreadSafeMessageBox(_("Invalid -proxy address"), _("PPCcoin"), wxOK | wxMODAL);
+             return false;
+         }
+     }
+     bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
+     if (fTor)
+     {
+         // Use SoftSetBoolArg here so user can override any of these if they wish.
+         // Note: the GetBoolArg() calls for all of these must happen later.
+         SoftSetBoolArg("-listen", false);
+         SoftSetBoolArg("-irc", false);
+         SoftSetBoolArg("-dnsseed", false);
+         SoftSetBoolArg("-upnp", false);
+         SoftSetBoolArg("-dns", false);
+     }
+     fAllowDNS = GetBoolArg("-dns");
+     fNoListen = !GetBoolArg("-listen", true);
+     // Continue to put "/P2SH/" in the coinbase to monitor
+     // BIP16 support.
+     // This can be removed eventually...
+     const char* pszP2SH = "/P2SH/";
+     COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
+     if (!fNoListen)
+     {
+         std::string strError;
+         if (!BindListenPort(strError))
+         {
 -            ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
++            ThreadSafeMessageBox(strError, _("PPCoin"), wxOK | wxMODAL);
              return false;
          }
      }
      {
          BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
          {
-             CAddress addr(strAddr, fAllowDNS);
+             CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
              addr.nTime = 0; // so it won't relay unless successfully connected
              if (addr.IsValid())
-                 AddAddress(addr);
+                 addrman.Add(addr, CNetAddr("127.0.0.1"));
          }
      }
  
      if (mapArgs.count("-paytxfee"))
      {
 -        if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
 +        if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee) || nTransactionFee < MIN_TX_FEE)
          {
-             wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "PPCoin");
 -            ThreadSafeMessageBox(_("Invalid amount for -paytxfee=<amount>"), _("Bitcoin"), wxOK | wxMODAL);
++            ThreadSafeMessageBox(_("Invalid amount for -paytxfee=<amount>"), _("PPCoin"), wxOK | wxMODAL);
              return false;
          }
-         nTransactionFee = (nTransactionFee / CENT) * CENT;  // round to cent
-         if (nTransactionFee >= 0.25 * COIN)
-             wxMessageBox(_("Warning: -paytxfee is set very high.  This is the transaction fee you will pay if you send a transaction."), "PPCoin", wxOK | wxICON_EXCLAMATION);
-     }
-     if (fHaveUPnP)
-     {
- #if USE_UPNP
-     if (GetBoolArg("-noupnp"))
-         fUseUPnP = false;
- #else
-     if (GetBoolArg("-upnp"))
-         fUseUPnP = true;
- #endif
+         if (nTransactionFee > 0.25 * COIN)
 -            ThreadSafeMessageBox(_("Warning: -paytxfee is set very high.  This is the transaction fee you will pay if you send a transaction."), _("Bitcoin"), wxOK | wxICON_EXCLAMATION | wxMODAL);
++            ThreadSafeMessageBox(_("Warning: -paytxfee is set very high.  This is the transaction fee you will pay if you send a transaction."), _("PPCoin"), wxOK | wxICON_EXCLAMATION | wxMODAL);
      }
  
      //
      RandAddSeedPerfmon();
  
      if (!CreateThread(StartNode, NULL))
-         wxMessageBox(_("Error: CreateThread(StartNode) failed"), "PPCoin");
 -        ThreadSafeMessageBox(_("Error: CreateThread(StartNode) failed"), _("Bitcoin"), wxOK | wxMODAL);
++        ThreadSafeMessageBox(_("Error: CreateThread(StartNode) failed"), _("PPCoin"), wxOK | wxMODAL);
  
      if (fServer)
          CreateThread(ThreadRPCServer, NULL);
  
+ #ifdef QT_GUI
+     if (GetStartOnSystemStartup())
+         SetStartOnSystemStartup(true); // Remove startup links
+ #endif
  #if !defined(QT_GUI)
      while (1)
          Sleep(5000);
  
      return true;
  }
diff --combined src/main.cpp
@@@ -1,13 -1,14 +1,15 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
- #include "headers.h"
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #include "checkpoints.h"
  #include "db.h"
  #include "net.h"
  #include "init.h"
+ #include "ui_interface.h"
+ #include <boost/algorithm/string/replace.hpp>
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
@@@ -23,20 -24,16 +25,17 @@@ set<CWallet*> setpwalletRegistered
  
  CCriticalSection cs_main;
  
- static map<uint256, CTransaction> mapTransactions;
- CCriticalSection cs_mapTransactions;
+ CTxMemPool mempool;
  unsigned int nTransactionsUpdated = 0;
- map<COutPoint, CInPoint> mapNextTx;
  
  map<uint256, CBlockIndex*> mapBlockIndex;
 -uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
 +set<pair<COutPoint, unsigned int> > setStakeSeen;
 +uint256 hashGenesisBlock = hashGenesisBlockOfficial;
  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;
 -CBigNum bnBestInvalidWork = 0;
 +uint64 nBestChainTrust = 0;
 +uint64 nBestInvalidTrust = 0;
  uint256 hashBestChain = 0;
  CBlockIndex* pindexBest = NULL;
  int64 nTimeBestReceived = 0;
@@@ -45,29 -42,23 +44,25 @@@ CMedianFilter<int> cPeerBlockCounts(5, 
  
  map<uint256, CBlock*> mapOrphanBlocks;
  multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
 +set<pair<COutPoint, unsigned int> > setStakeSeenOrphan;
  
  map<uint256, CDataStream*> mapOrphanTransactions;
- multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
+ map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
+ // Constant stuff for coinbase transactions we create:
+ CScript COINBASE_FLAGS;
  
+ const string strMessageMagic = "Bitcoin Signed Message:\n";
  
  double dHashesPerSec;
  int64 nHPSTimerStart;
  
  // Settings
- int fGenerateBitcoins = false;
- int64 nTransactionFee = MIN_TX_FEE;
- int fLimitProcessors = false;
- int nLimitProcessors = 1;
- int fMinimizeToTray = true;
- int fMinimizeOnClose = true;
- #if USE_UPNP
- int fUseUPnP = true;
- #else
- int fUseUPnP = false;
- #endif
+ int64 nTransactionFee = 0;
 +int64 nBalanceReserve = 0;
  
  //////////////////////////////////////////////////////////////////////////////
  //
  // dispatching functions
  
  void RegisterWallet(CWallet* pwalletIn)
  {
-     CRITICAL_BLOCK(cs_setpwalletRegistered)
      {
+         LOCK(cs_setpwalletRegistered);
          setpwalletRegistered.insert(pwalletIn);
      }
  }
  
  void UnregisterWallet(CWallet* pwalletIn)
  {
-     CRITICAL_BLOCK(cs_setpwalletRegistered)
      {
+         LOCK(cs_setpwalletRegistered);
          setpwalletRegistered.erase(pwalletIn);
      }
  }
@@@ -118,18 -109,8 +113,20 @@@ void static EraseFromWallets(uint256 ha
  }
  
  // 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)
 +void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true)
  {
 +    if (!fConnect)
 +    {
 +        // ppcoin: wallets need to refund inputs when disconnecting coinstake
 +        if (tx.IsCoinStake())
++        {
 +            BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
 +                if (pwallet->IsFromMe(tx))
 +                    pwallet->DisableTransaction(tx);
++        }
 +        return;
 +    }
 +
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
  }
@@@ -180,16 -161,37 +177,37 @@@ void static ResendWalletTransactions(
  // mapOrphanTransactions
  //
  
- void static AddOrphanTx(const CDataStream& vMsg)
+ bool AddOrphanTx(const CDataStream& vMsg)
  {
      CTransaction tx;
      CDataStream(vMsg) >> tx;
      uint256 hash = tx.GetHash();
      if (mapOrphanTransactions.count(hash))
-         return;
-     CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
+         return false;
+     CDataStream* pvMsg = new CDataStream(vMsg);
+     // Ignore big transactions, to avoid a
+     // send-big-orphans memory exhaustion attack. If a peer has a legitimate
+     // large transaction with a missing parent then we assume
+     // it will rebroadcast it later, after the parent transaction(s)
+     // have been mined or received.
+     // 10,000 orphans, each of which is at most 5,000 bytes big is
+     // at most 500 megabytes of orphans:
+     if (pvMsg->size() > 5000)
+     {
+         printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
+         delete pvMsg;
+         return false;
+     }
+     mapOrphanTransactions[hash] = pvMsg;
      BOOST_FOREACH(const CTxIn& txin, tx.vin)
-         mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
+         mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));
+     printf("stored orphan tx %s (mapsz %u)\n", hash.ToString().substr(0,10).c_str(),
+         mapOrphanTransactions.size());
+     return true;
  }
  
  void static EraseOrphanTx(uint256 hash)
      CDataStream(*pvMsg) >> tx;
      BOOST_FOREACH(const CTxIn& txin, tx.vin)
      {
-         for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash);
-              mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);)
-         {
-             if ((*mi).second == pvMsg)
-                 mapOrphanTransactionsByPrev.erase(mi++);
-             else
-                 mi++;
-         }
+         mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
+         if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
+             mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
      }
      delete pvMsg;
      mapOrphanTransactions.erase(hash);
  }
  
+ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
+ {
+     unsigned int nEvicted = 0;
+     while (mapOrphanTransactions.size() > nMaxOrphans)
+     {
+         // Evict a random orphan:
+         uint256 randomhash = GetRandHash();
+         map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
+         if (it == mapOrphanTransactions.end())
+             it = mapOrphanTransactions.begin();
+         EraseOrphanTx(it->first);
+         ++nEvicted;
+     }
+     return nEvicted;
+ }
  
  
  
@@@ -254,6 -266,103 +282,103 @@@ bool CTransaction::ReadFromDisk(COutPoi
      return ReadFromDisk(txdb, prevout, txindex);
  }
  
+ bool CTransaction::IsStandard() const
+ {
+     BOOST_FOREACH(const CTxIn& txin, vin)
+     {
+         // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
+         // pay-to-script-hash, which is 3 ~80-byte signatures, 3
+         // ~65-byte public keys, plus a few script ops.
+         if (txin.scriptSig.size() > 500)
+             return false;
+         if (!txin.scriptSig.IsPushOnly())
+             return false;
+     }
+     BOOST_FOREACH(const CTxOut& txout, vout)
+         if (!::IsStandard(txout.scriptPubKey))
+             return false;
+     return true;
+ }
+ //
+ // Check transaction inputs, and make sure any
+ // pay-to-script-hash transactions are evaluating IsStandard scripts
+ //
+ // Why bother? To avoid denial-of-service attacks; an attacker
+ // can submit a standard HASH... OP_EQUAL transaction,
+ // which will get accepted into blocks. The redemption
+ // script can be anything; an attacker could use a very
+ // expensive-to-check-upon-redemption script like:
+ //   DUP CHECKSIG DROP ... repeated 100 times... OP_1
+ //
+ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
+ {
+     if (IsCoinBase())
+         return true; // Coinbases don't use vin normally
+     for (unsigned int i = 0; i < vin.size(); i++)
+     {
+         const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
+         vector<vector<unsigned char> > vSolutions;
+         txnouttype whichType;
+         // get the scriptPubKey corresponding to this input:
+         const CScript& prevScript = prev.scriptPubKey;
+         if (!Solver(prevScript, whichType, vSolutions))
+             return false;
+         int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
+         if (nArgsExpected < 0)
+             return false;
+         // Transactions with extra stuff in their scriptSigs are
+         // non-standard. Note that this EvalScript() call will
+         // be quick, because if there are any operations
+         // beside "push data" in the scriptSig the
+         // IsStandard() call returns false
+         vector<vector<unsigned char> > stack;
+         if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
+             return false;
+         if (whichType == TX_SCRIPTHASH)
+         {
+             if (stack.empty())
+                 return false;
+             CScript subscript(stack.back().begin(), stack.back().end());
+             vector<vector<unsigned char> > vSolutions2;
+             txnouttype whichType2;
+             if (!Solver(subscript, whichType2, vSolutions2))
+                 return false;
+             if (whichType2 == TX_SCRIPTHASH)
+                 return false;
+             int tmpExpected;
+             tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
+             if (tmpExpected < 0)
+                 return false;
+             nArgsExpected += tmpExpected;
+         }
+         if (stack.size() != (unsigned int)nArgsExpected)
+             return false;
+     }
+     return true;
+ }
+ unsigned int
+ CTransaction::GetLegacySigOpCount() const
+ {
+     unsigned int nSigOps = 0;
+     BOOST_FOREACH(const CTxIn& txin, vin)
+     {
+         nSigOps += txin.scriptSig.GetSigOpCount(false);
+     }
+     BOOST_FOREACH(const CTxOut& txout, vout)
+     {
+         nSigOps += txout.scriptPubKey.GetSigOpCount(false);
+     }
+     return nSigOps;
+ }
  
  
  int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
          hashBlock = pblock->GetHash();
  
          // Locate the transaction
-         for (nIndex = 0; nIndex < pblock->vtx.size(); nIndex++)
+         for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
              if (pblock->vtx[nIndex] == *(CTransaction*)this)
                  break;
-         if (nIndex == pblock->vtx.size())
+         if (nIndex == (int)pblock->vtx.size())
          {
              vMerkleBranch.clear();
              nIndex = -1;
@@@ -321,16 -430,13 +446,16 @@@ bool CTransaction::CheckTransaction() c
      if (vout.empty())
          return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
      // Size limits
-     if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
+     if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
          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)
 +    for (int i = 0; i < vout.size(); i++)
      {
 +        const CTxOut& txout = vout[i];
 +        if (txout.IsEmpty() && (!IsCoinBase()) && (!IsCoinStake()))
 +            return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction"));
          if (txout.nValue < 0)
              return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
          if (txout.nValue > MAX_MONEY)
      return true;
  }
  
- bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
+ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
+                         bool* pfMissingInputs)
  {
      if (pfMissingInputs)
          *pfMissingInputs = false;
  
-     if (!CheckTransaction())
-         return error("AcceptToMemoryPool() : CheckTransaction failed");
+     if (!tx.CheckTransaction())
+         return error("CTxMemPool::accept() : CheckTransaction failed");
  
      // Coinbase is only valid in a block, not as a loose transaction
-     if (IsCoinBase())
-         return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
+     if (tx.IsCoinBase())
+         return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx"));
 +    // ppcoin: coinstake is also only valid in a block, not as a loose transaction
-     if (IsCoinStake())
-         return DoS(100, error("AcceptToMemoryPool() : coinstake as individual tx"));
++    if (tx.IsCoinStake())
++        return tx.DoS(100, error("CTxMemPool::accept() : coinstake as individual tx"));
  
      // To help v0.1.5 clients who would see it as a negative number
-     if ((int64)nLockTime > INT_MAX)
-         return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
-     // Safety limits
-     unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
-     // 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() : transaction with out-of-bounds SigOpCount");
+     if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
+         return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
  
      // Rather not work on nonstandard transactions (unless -testnet)
-     if (!fTestNet && !IsStandard())
-         return error("AcceptToMemoryPool() : nonstandard transaction type");
+     if (!fTestNet && !tx.IsStandard())
+         return error("CTxMemPool::accept() : nonstandard transaction type");
  
      // Do we already have it?
-     uint256 hash = GetHash();
-     CRITICAL_BLOCK(cs_mapTransactions)
-         if (mapTransactions.count(hash))
+     uint256 hash = tx.GetHash();
+     {
+         LOCK(cs);
+         if (mapTx.count(hash))
              return false;
+     }
      if (fCheckInputs)
          if (txdb.ContainsTx(hash))
              return false;
  
      // Check for conflicts with in-memory transactions
      CTransaction* ptxOld = NULL;
-     for (int i = 0; i < vin.size(); i++)
+     for (unsigned int i = 0; i < tx.vin.size(); i++)
      {
-         COutPoint outpoint = vin[i].prevout;
+         COutPoint outpoint = tx.vin[i].prevout;
          if (mapNextTx.count(outpoint))
          {
              // Disable replacement feature for now
              ptxOld = mapNextTx[outpoint].ptx;
              if (ptxOld->IsFinal())
                  return false;
-             if (!IsNewerThan(*ptxOld))
+             if (!tx.IsNewerThan(*ptxOld))
                  return false;
-             for (int i = 0; i < vin.size(); i++)
+             for (unsigned int i = 0; i < tx.vin.size(); i++)
              {
-                 COutPoint outpoint = vin[i].prevout;
+                 COutPoint outpoint = tx.vin[i].prevout;
                  if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
                      return false;
              }
  
      if (fCheckInputs)
      {
-         // Check against previous transactions
+         MapPrevTx mapInputs;
          map<uint256, CTxIndex> mapUnused;
-         int64 nFees = 0;
-         if (!ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false))
+         bool fInvalid = false;
+         if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
          {
+             if (fInvalid)
+                 return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
              if (pfMissingInputs)
                  *pfMissingInputs = true;
-             return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
+             return error("CTxMemPool::accept() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
          }
  
+         // Check for non-standard pay-to-script-hash in inputs
+         if (!tx.AreInputsStandard(mapInputs) && !fTestNet)
+             return error("CTxMemPool::accept() : 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 = tx.GetValueIn(mapInputs)-tx.GetValueOut();
+         unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
          // Don't accept it if it can't get into a block
-         if (nFees < GetMinFee(1000, false, true))
-             return error("AcceptToMemoryPool() : not enough fees");
 -        if (nFees < tx.GetMinFee(1000, true, GMF_RELAY))
++        if (nFees < tx.GetMinFee(1000, false, GMF_RELAY))
+             return error("CTxMemPool::accept() : not enough fees");
  
          // Continuously rate-limit free transactions
          // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
              static int64 nLastTime;
              int64 nNow = GetTime();
  
-             CRITICAL_BLOCK(cs)
              {
+                 LOCK(cs);
                  // Use an exponentially decaying ~10-minute window:
                  dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
                  nLastTime = nNow;
                  // -limitfreerelay unit is thousand-bytes-per-minute
                  // At default rate it would take over a month to fill 1GB
-                 if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(*this))
-                     return error("AcceptToMemoryPool() : free transaction rejected by rate limiter");
+                 if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
+                     return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
                  if (fDebug)
                      printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
                  dFreeCount += nSize;
              }
          }
+         // Check against previous transactions
+         // This is done last to help prevent CPU exhaustion denial-of-service attacks.
 -        if (!tx.ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
++        if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
+         {
+             return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
+         }
      }
  
      // Store transaction in memory
-     CRITICAL_BLOCK(cs_mapTransactions)
      {
+         LOCK(cs);
          if (ptxOld)
          {
-             printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
-             ptxOld->RemoveFromMemoryPool();
+             printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
+             remove(*ptxOld);
          }
-         AddToMemoryPoolUnchecked();
+         addUnchecked(tx);
      }
  
      ///// are we sure this is ok when loading transactions or restoring block txes
      if (ptxOld)
          EraseFromWallets(ptxOld->GetHash());
  
-     printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
+     printf("CTxMemPool::accept() : accepted %s\n", hash.ToString().substr(0,10).c_str());
      return true;
  }
  
- bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
+ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
  {
-     CTxDB txdb("r");
-     return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
+     return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs);
  }
  
- bool CTransaction::AddToMemoryPoolUnchecked()
+ bool CTxMemPool::addUnchecked(CTransaction &tx)
  {
+     printf("addUnchecked(): size %lu\n",  mapTx.size());
      // Add to memory pool without checking anything.  Don't call this directly,
-     // call AcceptToMemoryPool to properly check the transaction first.
-     CRITICAL_BLOCK(cs_mapTransactions)
+     // call CTxMemPool::accept to properly check the transaction first.
      {
-         uint256 hash = GetHash();
-         mapTransactions[hash] = *this;
-         for (int i = 0; i < vin.size(); i++)
-             mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
+         LOCK(cs);
+         uint256 hash = tx.GetHash();
+         mapTx[hash] = tx;
+         for (unsigned int i = 0; i < tx.vin.size(); i++)
+             mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
          nTransactionsUpdated++;
      }
      return true;
  }
  
  
- bool CTransaction::RemoveFromMemoryPool()
+ bool CTxMemPool::remove(CTransaction &tx)
  {
      // Remove transaction from memory pool
-     CRITICAL_BLOCK(cs_mapTransactions)
      {
-         BOOST_FOREACH(const CTxIn& txin, vin)
-             mapNextTx.erase(txin.prevout);
-         mapTransactions.erase(GetHash());
-         nTransactionsUpdated++;
+         LOCK(cs);
+         uint256 hash = tx.GetHash();
+         if (mapTx.count(hash))
+         {
+             BOOST_FOREACH(const CTxIn& txin, tx.vin)
+                 mapNextTx.erase(txin.prevout);
+             mapTx.erase(hash);
+             nTransactionsUpdated++;
+         }
      }
      return true;
  }
  
  
  
- int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const
+ int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
  {
      if (hashBlock == 0 || nIndex == -1)
          return 0;
          fMerkleVerified = true;
      }
  
-     nHeightRet = pindex->nHeight;
+     pindexRet = pindex;
      return pindexBest->nHeight - pindex->nHeight + 1;
  }
  
  
  int CMerkleTx::GetBlocksToMaturity() const
  {
 -    if (!IsCoinBase())
 +    if (!(IsCoinBase() || IsCoinStake()))
          return 0;
      return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());
  }
@@@ -593,15 -714,16 +736,16 @@@ bool CMerkleTx::AcceptToMemoryPool(
  
  bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
  {
-     CRITICAL_BLOCK(cs_mapTransactions)
      {
+         LOCK(mempool.cs);
          // Add previous supporting transactions first
          BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
          {
 -            if (!tx.IsCoinBase())
 +            if (!(tx.IsCoinBase() || tx.IsCoinStake()))
              {
                  uint256 hash = tx.GetHash();
-                 if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash))
+                 if (!mempool.exists(hash) && !txdb.ContainsTx(hash))
                      tx.AcceptToMemoryPool(txdb, fCheckInputs);
              }
          }
      return false;
  }
  
- bool CWalletTx::AcceptWalletTransaction() 
+ bool CWalletTx::AcceptWalletTransaction()
  {
      CTxDB txdb("r");
      return AcceptWalletTransaction(txdb);
@@@ -668,61 -790,19 +812,61 @@@ uint256 static GetOrphanRoot(const CBlo
      return pblock->GetHash();
  }
  
 -int64 static GetBlockValue(int nHeight, int64 nFees)
 +// ppcoin: find block wanted by given orphan block
 +uint256 WantedByOrphan(const CBlock* pblockOrphan)
 +{
 +    // Work back to the first block in the orphan chain
 +    while (mapOrphanBlocks.count(pblockOrphan->hashPrevBlock))
 +        pblockOrphan = mapOrphanBlocks[pblockOrphan->hashPrevBlock];
 +    return pblockOrphan->hashPrevBlock;
 +}
 +
 +int64 static GetProofOfWorkReward(unsigned int nBits)
  {
 -    int64 nSubsidy = 50 * COIN;
 +    CBigNum bnSubsidyLimit = 9999 * COIN; // subsidy amount for difficulty 1
 +    CBigNum bnTarget;
 +    bnTarget.SetCompact(nBits);
 +    CBigNum bnTargetLimit = bnProofOfWorkLimit;
 +    bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
 +
 +    // ppcoin: subsidy is cut in half every 16x multiply of difficulty
 +    // A reasonably continuous curve is used to avoid shock to market
 +    // (nSubsidyLimit / nSubsidy) ** 4 == bnProofOfWorkLimit / bnTarget
 +    CBigNum bnLowerBound = CENT;
 +    CBigNum bnUpperBound = bnSubsidyLimit;
 +    while (bnLowerBound + CENT <= bnUpperBound)
 +    {
 +        CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
 +        if (fDebug && GetBoolArg("-printcreation"))
 +            printf("GetProofOfWorkReward() : lower=%"PRI64d" upper=%"PRI64d" mid=%"PRI64d"\n", bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64());
 +        if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnTarget)
 +            bnUpperBound = bnMidValue;
 +        else
 +            bnLowerBound = bnMidValue;
 +    }
 +
 +    int64 nSubsidy = bnUpperBound.getuint64();
 +    nSubsidy = (nSubsidy / CENT) * CENT;
 +    if (fDebug && GetBoolArg("-printcreation"))
 +        printf("GetProofOfWorkReward() : create=%s nBits=0x%08x nSubsidy=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nBits, nSubsidy);
  
 -    // Subsidy is cut in half every 4 years
 -    nSubsidy >>= (nHeight / 210000);
 +    return nSubsidy;
 +}
  
 -    return nSubsidy + nFees;
 +// ppcoin: miner's coin stake is rewarded based on coin age spent (coin-days)
 +int64 GetProofOfStakeReward(int64 nCoinAge)
 +{
 +    static int64 nRewardCoinYear = CENT;  // creation amount per coin-year
 +    int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear;
 +    if (fDebug && GetBoolArg("-printcreation"))
 +        printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nCoinAge);
 +    return nSubsidy;
  }
  
 -static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
 -static const int64 nTargetSpacing = 10 * 60;
 -static const int64 nInterval = nTargetTimespan / nTargetSpacing;
 +static const int64 nTargetTimespan = 7 * 24 * 60 * 60;  // one week
 +static const int64 nTargetSpacingStake = 10 * 60;       // ten minutes
 +static const int64 nTargetSpacingWorkMax = 2 * 60 * 60; // two hours
 +static const int64 nMaxClockDrift = 2 * 60 * 60;        // two hours
  
  //
  // minimum amount of work that could possibly be required nTime after
  //
  unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
  {
 -    // Testnet has min-difficulty blocks
 -    // after nTargetSpacing*2 time between blocks:
 -    if (fTestNet && nTime > nTargetSpacing*2)
 -        return bnProofOfWorkLimit.GetCompact();
 -
      CBigNum bnResult;
      bnResult.SetCompact(nBase);
 +    bnResult *= 2;
      while (nTime > 0 && bnResult < bnProofOfWorkLimit)
      {
 -        // Maximum 400% adjustment...
 -        bnResult *= 4;
 -        // ... in best-case exactly 4-times-normal target time
 -        nTime -= nTargetTimespan*4;
 +        // Maximum 200% adjustment per day...
 +        bnResult *= 2;
 +        nTime -= 24 * 60 * 60;
      }
      if (bnResult > bnProofOfWorkLimit)
          bnResult = bnProofOfWorkLimit;
      return bnResult.GetCompact();
  }
  
 -unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock *pblock)
 +// ppcoin: find last block index up to pindex
 +const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake)
  {
 -    unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact();
 -
 -    // Genesis block
 -    if (pindexLast == NULL)
 -        return nProofOfWorkLimit;
 -
 -    // Only change once per interval
 -    if ((pindexLast->nHeight+1) % nInterval != 0)
 -    {
 -        // Special rules for testnet after 15 Feb 2012:
 -        if (fTestNet && pblock->nTime > 1329264000)
 -        {
 -            // If the new block's timestamp is more than 2* 10 minutes
 -            // then allow mining of a min-difficulty block.
 -            if (pblock->nTime - pindexLast->nTime > nTargetSpacing*2)
 -                return nProofOfWorkLimit;
 -            else
 -            {
 -                // Return the last non-special-min-difficulty-rules-block
 -                const CBlockIndex* pindex = pindexLast;
 -                while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit)
 -                    pindex = pindex->pprev;
 -                return pindex->nBits;
 -            }
 -        }
 -
 -        return pindexLast->nBits;
 -    }
 +    while (pindex && (pindex->IsProofOfStake() != fProofOfStake))
 +        pindex = pindex->pprev;
 +    return pindex;
 +}
  
 -    // Go back by what we want to be 14 days worth of blocks
 -    const CBlockIndex* pindexFirst = pindexLast;
 -    for (int i = 0; pindexFirst && i < nInterval-1; i++)
 -        pindexFirst = pindexFirst->pprev;
 -    assert(pindexFirst);
 +unsigned int static GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake)
 +{
 +    // Genesis block and first block
 +    if (pindexLast == NULL || pindexLast->pprev == NULL)
 +        return bnProofOfWorkLimit.GetCompact();
  
 -    // Limit adjustment step
 -    int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
 -    printf("  nActualTimespan = %"PRI64d"  before bounds\n", nActualTimespan);
 -    if (nActualTimespan < nTargetTimespan/4)
 -        nActualTimespan = nTargetTimespan/4;
 -    if (nActualTimespan > nTargetTimespan*4)
 -        nActualTimespan = nTargetTimespan*4;
 +    const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake);
 +    if (pindexPrev == NULL) 
 +        return bnProofOfWorkLimit.GetCompact();
 +    const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, fProofOfStake);
 +    if (pindexPrevPrev == NULL)
 +        return bnProofOfWorkLimit.GetCompact();
 +    int64 nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime();
  
 -    // Retarget
 +    // ppcoin: target change every block
 +    // ppcoin: retarget with exponential moving toward target spacing
      CBigNum bnNew;
 -    bnNew.SetCompact(pindexLast->nBits);
 -    bnNew *= nActualTimespan;
 -    bnNew /= nTargetTimespan;
 +    bnNew.SetCompact(pindexPrev->nBits);
 +    int64 nTargetSpacing = fProofOfStake? nTargetSpacingStake : min(nTargetSpacingWorkMax, nTargetSpacingStake * (1 + pindexLast->nHeight - pindexPrev->nHeight));
 +    int64 nInterval = nTargetTimespan / nTargetSpacing;
 +    bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
 +    bnNew /= ((nInterval + 1) * nTargetSpacing);
  
      if (bnNew > bnProofOfWorkLimit)
          bnNew = bnProofOfWorkLimit;
  
 -    /// debug print
 -    printf("GetNextWorkRequired RETARGET\n");
 -    printf("nTargetTimespan = %"PRI64d"    nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
 -    printf("Before: %08x  %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
 -    printf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
 -
      return bnNew.GetCompact();
  }
  
@@@ -805,7 -916,7 +949,7 @@@ int GetNumBlocksOfPeers(
  
  bool IsInitialBlockDownload()
  {
-     if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
+     if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
          return true;
      static int64 nLastUpdate;
      static CBlockIndex* pindexLastBest;
  
  void static InvalidChainFound(CBlockIndex* pindexNew)
  {
 -    if (pindexNew->bnChainWork > bnBestInvalidWork)
 +    if (pindexNew->nChainTrust > nBestInvalidTrust)
      {
 -        bnBestInvalidWork = pindexNew->bnChainWork;
 -        CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
 +        nBestInvalidTrust = pindexNew->nChainTrust;
 +        CTxDB().WriteBestInvalidTrust(nBestInvalidTrust);
          MainFrameRepaint();
      }
 -    printf("InvalidChainFound: invalid block=%s  height=%d  work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str());
 -    printf("InvalidChainFound:  current best=%s  height=%d  work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
 -    if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
 +    printf("InvalidChainFound: invalid block=%s  height=%d  trust=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, CBigNum(pindexNew->nChainTrust).ToString().c_str());
 +    printf("InvalidChainFound:  current best=%s  height=%d  trust=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str());
 +    if (pindexBest && nBestInvalidTrust > nBestChainTrust + pindexBest->GetBlockTrust() * 6)
          printf("InvalidChainFound: WARNING: Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade.\n");
  }
  
+ void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
+ {
 -    nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
 -
 -    // Updating time can change work required on testnet:
 -    if (fTestNet)
 -        nBits = GetNextWorkRequired(pindexPrev, this);
++    nTime = max(GetBlockTime(), GetAdjustedTime());
+ }
  
  
  
@@@ -869,15 -989,135 +1018,135 @@@ bool CTransaction::DisconnectInputs(CTx
      }
  
      // Remove transaction from index
-     if (!txdb.EraseTxIndex(*this))
-         return error("DisconnectInputs() : EraseTxPos failed");
+     // This can fail if a duplicate of this transaction was in a chain that got
+     // reorganized away. This is only possible if this transaction was completely
+     // spent, so erasing it would be a no-op anway.
+     txdb.EraseTxIndex(*this);
  
      return true;
  }
  
  
- bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
-                                  CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee)
+ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool,
+                                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.
+     for (unsigned int i = 0; i < vin.size(); i++)
+     {
+         COutPoint prevout = vin[i].prevout;
+         if (inputsRet.count(prevout.hash))
+             continue; // Got it already
+         // Read txindex
+         CTxIndex& txindex = inputsRet[prevout.hash].first;
+         bool fFound = true;
+         if ((fBlock || fMiner) && mapTestPool.count(prevout.hash))
+         {
+             // Get txindex from current proposed changes
+             txindex = mapTestPool.find(prevout.hash)->second;
+         }
+         else
+         {
+             // Read txindex from txdb
+             fFound = txdb.ReadTxIndex(prevout.hash, txindex);
+         }
+         if (!fFound && (fBlock || fMiner))
+             return fMiner ? false : error("FetchInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
+         // Read txPrev
+         CTransaction& txPrev = inputsRet[prevout.hash].second;
+         if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
+         {
+             // Get prev tx from single transactions in memory
+             {
+                 LOCK(mempool.cs);
+                 if (!mempool.exists(prevout.hash))
+                     return error("FetchInputs() : %s mempool Tx prev not found %s", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
+                 txPrev = mempool.lookup(prevout.hash);
+             }
+             if (!fFound)
+                 txindex.vSpent.resize(txPrev.vout.size());
+         }
+         else
+         {
+             // Get prev tx from disk
+             if (!txPrev.ReadFromDisk(txindex.pos))
+                 return error("FetchInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
+         }
+     }
+     // Make sure all prevout.n's are valid:
+     for (unsigned int i = 0; i < vin.size(); i++)
+     {
+         const COutPoint prevout = vin[i].prevout;
+         assert(inputsRet.count(prevout.hash) != 0);
+         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;
+ }
+ const CTxOut& CTransaction::GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const
+ {
+     MapPrevTx::const_iterator mi = inputs.find(input.prevout.hash);
+     if (mi == inputs.end())
+         throw std::runtime_error("CTransaction::GetOutputFor() : prevout.hash not found");
+     const CTransaction& txPrev = (mi->second).second;
+     if (input.prevout.n >= txPrev.vout.size())
+         throw std::runtime_error("CTransaction::GetOutputFor() : prevout.n out of range");
+     return txPrev.vout[input.prevout.n];
+ }
+ int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const
+ {
+     if (IsCoinBase())
+         return 0;
+     int64 nResult = 0;
+     for (unsigned int i = 0; i < vin.size(); i++)
+     {
+         nResult += GetOutputFor(vin[i], inputs).nValue;
+     }
+     return nResult;
+ }
+ unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
+ {
+     if (IsCoinBase())
+         return 0;
+     unsigned int nSigOps = 0;
+     for (unsigned int i = 0; i < vin.size(); i++)
+     {
+         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,
++bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs,
+                                  map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
+                                  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
      if (!IsCoinBase())
      {
          int64 nValueIn = 0;
-         for (int i = 0; i < vin.size(); i++)
+         int64 nFees = 0;
+         for (unsigned int i = 0; i < vin.size(); i++)
          {
              COutPoint prevout = vin[i].prevout;
-             // Read txindex
-             CTxIndex txindex;
-             bool fFound = true;
-             if ((fBlock || fMiner) && mapTestPool.count(prevout.hash))
-             {
-                 // Get txindex from current proposed changes
-                 txindex = mapTestPool[prevout.hash];
-             }
-             else
-             {
-                 // Read txindex from txdb
-                 fFound = txdb.ReadTxIndex(prevout.hash, txindex);
-             }
-             if (!fFound && (fBlock || fMiner))
-                 return fMiner ? false : error("ConnectInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
-             // Read txPrev
-             CTransaction txPrev;
-             if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
-             {
-                 // Get prev tx from single transactions in memory
-                 CRITICAL_BLOCK(cs_mapTransactions)
-                 {
-                     if (!mapTransactions.count(prevout.hash))
-                         return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
-                     txPrev = mapTransactions[prevout.hash];
-                 }
-                 if (!fFound)
-                     txindex.vSpent.resize(txPrev.vout.size());
-             }
-             else
-             {
-                 // Get prev tx from disk
-                 if (!txPrev.ReadFromDisk(txindex.pos))
-                     return error("ConnectInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
-             }
+             assert(inputs.count(prevout.hash) > 0);
+             CTxIndex& txindex = inputs[prevout.hash].first;
+             CTransaction& txPrev = inputs[prevout.hash].second;
  
              if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
                  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 (txPrev.IsCoinBase())
 +            // If prev is coinbase/coinstake, check that it's matured
 +            if (txPrev.IsCoinBase() || txPrev.IsCoinStake())
-                 for (CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < COINBASE_MATURITY; pindex = pindex->pprev)
+                 for (const CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < COINBASE_MATURITY; pindex = pindex->pprev)
                      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);
 +                        return error("ConnectInputs() : tried to spend coinbase/coinstake at depth %d", pindexBlock->nHeight - pindex->nHeight);
 +
 +            // ppcoin: check transaction timestamp
 +            if (txPrev.nTime > nTime)
 +                return DoS(100, error("ConnectInputs() : transaction timestamp earlier than input transaction"));
  
-             // Skip ECDSA signature verification when connecting blocks (fBlock=true) during initial download
-             // (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 && IsInitialBlockDownload()))
-                 // Verify signature
-                 if (!VerifySignature(txPrev, *this, i))
-                     return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).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 DoS(100, error("ConnectInputs() : txin values out of range"));
+         }
+         // The first loop above does all the inexpensive checks.
+         // Only if ALL inputs pass do we perform expensive ECDSA signature checks.
+         // Helps prevent CPU exhaustion attacks.
+         for (unsigned int i = 0; i < vin.size(); i++)
+         {
+             COutPoint prevout = vin[i].prevout;
+             assert(inputs.count(prevout.hash) > 0);
+             CTxIndex& txindex = inputs[prevout.hash].first;
+             CTransaction& txPrev = inputs[prevout.hash].second;
  
              // Check for conflicts (double-spend)
              // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
              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 DoS(100, error("ConnectInputs() : txin values out of range"));
+             // 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, fStrictPayToScriptHash, 0))
+                 {
+                     // only during transition phase for P2SH: do not invoke anti-DoS code for
+                     // potentially old clients relaying bad P2SH transactions
+                     if (fStrictPayToScriptHash && VerifySignature(txPrev, *this, i, false, 0))
+                         return error("ConnectInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
+                     return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
+                 }
+             }
  
              // Mark outpoints as spent
              txindex.vSpent[prevout.n] = posThisTx;
              }
          }
  
 -        if (nValueIn < GetValueOut())
 -            return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
 +        if (IsCoinStake())
 +        {
 +            // ppcoin: coin stake tx earns reward instead of paying fee
 +            uint64 nCoinAge;
 +            if (!GetCoinAge(txdb, nCoinAge))
 +                return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
 +            int64 nStakeReward = GetValueOut() - nValueIn;
 +            if (nStakeReward > GetProofOfStakeReward(nCoinAge))
 +                return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str()));
 +        }
 +        else
 +        {
 +            if (nValueIn < GetValueOut())
 +                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 DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
 -        nFees += nTxFee;
 -        if (!MoneyRange(nFees))
 -            return DoS(100, error("ConnectInputs() : nFees out of range"));
 +            // Tally transaction fees
 +            int64 nTxFee = nValueIn - GetValueOut();
 +            if (nTxFee < 0)
 +                return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
 +            // ppcoin: enforce transaction fees for every block
-             if (nTxFee < nMinFee)
-                 return fBlock? DoS(100, error("ConnectInputs() : %s not paying required fee=%s, paid=%s", GetHash().ToString().substr(0,10).c_str(), FormatMoney(nMinFee).c_str(), FormatMoney(nTxFee).c_str())) : false;
++            if (nTxFee < GetMinFee())
++                return fBlock? DoS(100, error("ConnectInputs() : %s not paying required fee=%s, paid=%s", GetHash().ToString().substr(0,10).c_str(), FormatMoney(GetMinFee()).c_str(), FormatMoney(nTxFee).c_str())) : false;
 +            nFees += nTxFee;
 +            if (!MoneyRange(nFees))
 +                return DoS(100, error("ConnectInputs() : nFees out of range"));
 +        }
      }
  
-     if (fBlock)
-     {
-         // Add transaction to changes
-         mapTestPool[GetHash()] = CTxIndex(posThisTx, vout.size());
-     }
-     else if (fMiner)
-     {
-         // Add transaction to test pool
-         mapTestPool[GetHash()] = CTxIndex(CDiskTxPos(1,1,1), vout.size());
-     }
      return true;
  }
  
@@@ -1018,25 -1214,26 +1263,26 @@@ bool CTransaction::ClientConnectInputs(
          return false;
  
      // Take over previous transactions' spent pointers
-     CRITICAL_BLOCK(cs_mapTransactions)
      {
+         LOCK(mempool.cs);
          int64 nValueIn = 0;
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
          {
              // Get prev tx from single transactions in memory
              COutPoint prevout = vin[i].prevout;
-             if (!mapTransactions.count(prevout.hash))
+             if (!mempool.exists(prevout.hash))
                  return false;
-             CTransaction& txPrev = mapTransactions[prevout.hash];
+             CTransaction& txPrev = mempool.lookup(prevout.hash);
  
              if (prevout.n >= txPrev.vout.size())
                  return false;
  
              // Verify signature
-             if (!VerifySignature(txPrev, *this, i))
+             if (!VerifySignature(txPrev, *this, i, true, 0))
                  return error("ConnectInputs() : VerifySignature failed");
  
-             ///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of
+             ///// this is redundant with the mempool.mapNextTx stuff,
+             ///// not sure which I want to get rid of
              ///// this has to go away now that posNext is gone
              // // Check for conflicts
              // if (!txPrev.vout[prevout.n].posNext.IsNull())
@@@ -1077,10 -1274,6 +1323,10 @@@ bool CBlock::DisconnectBlock(CTxDB& txd
              return error("DisconnectBlock() : WriteBlockIndex failed");
      }
  
 +    // ppcoin: clean up wallet after disconnecting coinstake
 +    BOOST_FOREACH(CTransaction& tx, vtx)
 +        SyncWithWallets(tx, this, false, false);
 +
      return true;
  }
  
@@@ -1090,19 -1283,75 +1336,75 @@@ bool CBlock::ConnectBlock(CTxDB& txdb, 
      if (!CheckBlock())
          return false;
  
+     // Do not allow blocks that contain transactions which 'overwrite' older transactions,
+     // unless those are already completely spent.
+     // If such overwrites are allowed, coinbases and transactions depending upon those
+     // can be duplicated to remove the ability to spend the first instance -- even after
+     // being sent to another address.
+     // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information.
+     // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
+     // already refuses previously-known transaction id's entirely.
+     // This rule applies to all blocks whose timestamp is after March 15, 2012, 0:00 UTC.
+     // On testnet it is enabled as of februari 20, 2012, 0:00 UTC.
+     if (pindex->nTime > 1331769600 || (fTestNet && pindex->nTime > 1329696000))
+     {
+         BOOST_FOREACH(CTransaction& tx, vtx)
+         {
+             CTxIndex txindexOld;
+             if (txdb.ReadTxIndex(tx.GetHash(), txindexOld))
+             {
+                 BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent)
+                     if (pos.IsNull())
+                         return false;
+             }
+         }
+     }
+     // BIP16 didn't become active until Apr 1 2012 (Feb 15 on testnet)
+     int64 nBIP16SwitchTime = fTestNet ? 1329264000 : 1333238400;
+     bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
      //// issue here: it doesn't know the version
-     unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - (2 * GetSizeOfCompactSize(0)) + GetSizeOfCompactSize(vtx.size());
 -    unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size());
++    unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - (2 * GetSizeOfCompactSize(0)) + GetSizeOfCompactSize(vtx.size());
  
      map<uint256, CTxIndex> mapQueuedChanges;
      int64 nFees = 0;
+     unsigned 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);
+         nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
  
-         if (!tx.ConnectInputs(txdb, mapQueuedChanges, posThisTx, pindex, nFees, true, false, tx.GetMinFee()))
-             return false;
+         MapPrevTx mapInputs;
 -        if (!tx.IsCoinBase())
++        if (!(tx.IsCoinBase() || tx.IsCoinStake()))
+         {
+             bool fInvalid;
+             if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid))
+                 return false;
+             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, fStrictPayToScriptHash))
++            if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fStrictPayToScriptHash))
+                 return false;
+         }
+         mapQueuedChanges[tx.GetHash()] = CTxIndex(posThisTx, tx.vout.size());
      }
      // Write queued txindex changes
      for (map<uint256, CTxIndex>::iterator mi = mapQueuedChanges.begin(); mi != mapQueuedChanges.end(); ++mi)
      {
              return error("ConnectBlock() : UpdateTxIndex failed");
      }
  
 -    if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
 +    // ppcoin: fees are not collected by miners as in bitcoin
 +    // ppcoin: fees are destroyed to compensate the entire network
 +    if (IsProofOfWork() && vtx[0].GetValueOut() > GetProofOfWorkReward(nBits))
          return false;
 +    if (fDebug && GetBoolArg("-printcreation"))
 +        printf("ConnectBlock() : destroy=%s nFees=%"PRI64d"\n", FormatMoney(nFees).c_str(), nFees);
  
      // Update block index on disk without changing it in memory.
      // The memory index structure will be changed after the db commits.
      return true;
  }
  
 -bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
 +bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
  {
      printf("REORGANIZE\n");
  
          vConnect.push_back(pindex);
      reverse(vConnect.begin(), vConnect.end());
  
+     printf("REORGANIZE: Disconnect %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
+     printf("REORGANIZE: Connect %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
      // Disconnect shorter branch
      vector<CTransaction> vResurrect;
      BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
          if (!block.ReadFromDisk(pindex))
              return error("Reorganize() : ReadFromDisk for disconnect failed");
          if (!block.DisconnectBlock(txdb, pindex))
-             return error("Reorganize() : DisconnectBlock failed");
+             return error("Reorganize() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
  
          // Queue memory transactions to resurrect
          BOOST_FOREACH(const CTransaction& tx, block.vtx)
 -            if (!tx.IsCoinBase())
 +            if (!(tx.IsCoinBase() || tx.IsCoinStake()))
                  vResurrect.push_back(tx);
      }
  
      // Connect longer branch
      vector<CTransaction> vDelete;
-     for (int i = 0; i < vConnect.size(); i++)
+     for (unsigned int i = 0; i < vConnect.size(); i++)
      {
          CBlockIndex* pindex = vConnect[i];
          CBlock block;
          {
              // Invalid block
              txdb.TxnAbort();
-             return error("Reorganize() : ConnectBlock failed");
+             return error("Reorganize() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
          }
  
          // Queue memory transactions to delete
  
      // Delete redundant memory transactions that are in the connected branch
      BOOST_FOREACH(CTransaction& tx, vDelete)
-         tx.RemoveFromMemoryPool();
+         mempool.remove(tx);
+     printf("REORGANIZE: done\n");
  
      return true;
  }
  
  
+ static void
+ runCommand(std::string strCommand)
+ {
+     int nErr = ::system(strCommand.c_str());
+     if (nErr)
+         printf("runCommand error: system(%s) returned %d\n", strCommand.c_str(), nErr);
+ }
+ // Called from inside SetBestChain: attaches a block to the new best chain being built
+ bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew)
+ {
+     uint256 hash = GetHash();
+     // Adding to current best branch
+     if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
+     {
+         txdb.TxnAbort();
+         InvalidChainFound(pindexNew);
+         return false;
+     }
+     if (!txdb.TxnCommit())
+         return error("SetBestChain() : TxnCommit failed");
+     // Add to current best branch
+     pindexNew->pprev->pnext = pindexNew;
+     // Delete redundant memory transactions
+     BOOST_FOREACH(CTransaction& tx, vtx)
+         mempool.remove(tx);
+     return true;
+ }
  bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
  {
      uint256 hash = GetHash();
  
-     txdb.TxnBegin();
+     if (!txdb.TxnBegin())
+         return error("SetBestChain() : TxnBegin failed");
      if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
      {
          txdb.WriteHashBestChain(hash);
      }
      else if (hashPrevBlock == hashBestChain)
      {
-         // Adding to current best branch
-         if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
+         if (!SetBestChainInner(txdb, pindexNew))
+             return error("SetBestChain() : SetBestChainInner failed");
+     }
+     else
+     {
+         // the first block in the new chain that will cause it to become the new best chain
+         CBlockIndex *pindexIntermediate = pindexNew;
+         // list of blocks that need to be connected afterwards
+         std::vector<CBlockIndex*> vpindexSecondary;
+         // Reorganize is costly in terms of db load, as it works in a single db transaction.
+         // Try to limit how much needs to be done inside
 -        while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainWork > pindexBest->bnChainWork)
++        while (pindexIntermediate->pprev && pindexIntermediate->pprev->nChainTrust > pindexBest->nChainTrust)
          {
-             txdb.TxnAbort();
-             InvalidChainFound(pindexNew);
-             return error("SetBestChain() : ConnectBlock failed");
+             vpindexSecondary.push_back(pindexIntermediate);
+             pindexIntermediate = pindexIntermediate->pprev;
          }
-         if (!txdb.TxnCommit())
-             return error("SetBestChain() : TxnCommit failed");
  
-         // Add to current best branch
-         pindexNew->pprev->pnext = pindexNew;
+         if (!vpindexSecondary.empty())
+             printf("Postponing %i reconnects\n", vpindexSecondary.size());
  
-         // Delete redundant memory transactions
-         BOOST_FOREACH(CTransaction& tx, vtx)
-             tx.RemoveFromMemoryPool();
-     }
-     else
-     {
-         // New best branch
-         if (!Reorganize(txdb, pindexNew))
+         // Switch to new best branch
+         if (!Reorganize(txdb, pindexIntermediate))
          {
              txdb.TxnAbort();
              InvalidChainFound(pindexNew);
              return error("SetBestChain() : Reorganize failed");
          }
+         // Connect futher blocks
+         BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary)
+         {
+             CBlock block;
+             if (!block.ReadFromDisk(pindex))
+             {
+                 printf("SetBestChain() : ReadFromDisk failed\n");
+                 break;
+             }
+             if (!txdb.TxnBegin()) {
+                 printf("SetBestChain() : TxnBegin 2 failed\n");
+                 break;
+             }
+             // errors now are not fatal, we still did a reorganisation to a new chain in a valid way
+             if (!block.SetBestChainInner(txdb, pindex))
+                 break;
+         }
      }
  
      // Update best block in wallet (so we can detect restored wallets)
-     if (!IsInitialBlockDownload())
+     bool fIsInitialDownload = IsInitialBlockDownload();
+     if (!fIsInitialDownload)
      {
          const CBlockLocator locator(pindexNew);
          ::SetBestChain(locator);
      hashBestChain = hash;
      pindexBest = pindexNew;
      nBestHeight = pindexBest->nHeight;
 -    bnBestChainWork = pindexNew->bnChainWork;
 +    nBestChainTrust = pindexNew->nChainTrust;
      nTimeBestReceived = GetTime();
      nTransactionsUpdated++;
 -    printf("SetBestChain: new best=%s  height=%d  work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
 +    printf("SetBestChain: new best=%s  height=%d  trust=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str());
  
+     std::string strCmd = GetArg("-blocknotify", "");
+     if (!fIsInitialDownload && !strCmd.empty())
+     {
+         boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
+         boost::thread t(runCommand, strCmd); // thread runs free
+     }
      return true;
  }
  
  
 +// ppcoin: coinstake must meet hash target according to the protocol:
 +// input 0 must meet the formula
 +//     hash(nBits + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime) < bnTarget * nCoinDay
 +// this ensures that the chance of getting a coinstake is proportional to the
 +// amount of coin age one owns.
 +// The reason this hash is chosen is the following:
 +//   nBits: encodes all past block timestamps, making computing hash in advance
 +//          more difficult
 +//   txPrev.block.nTime: prevent nodes from guessing a good timestamp to
 +//                       generate transaction for future advantage
 +//   txPrev.offset: offset of txPrev inside block, to reduce the chance of 
 +//                  nodes generating coinstake at the same time
 +//   txPrev.nTime: reduce the chance of nodes generating coinstake at the same
 +//                 time
 +//   txPrev.vout.n: output number of txPrev, to reduce the chance of nodes
 +//                  generating coinstake at the same time
 +//   block/tx hash should not be used here as they can be generated in vast
 +//   quantities so as to generate blocks faster, degrading the system back into
 +//   a proof-of-work situation.
 +//
 +bool CTransaction::CheckProofOfStake(unsigned int nBits) const
 +{
 +    CBigNum bnTargetPerCoinDay;
 +    bnTargetPerCoinDay.SetCompact(nBits);
 + 
 +    if (!IsCoinStake())
 +        return true;
 +
 +    // Input 0 must match the stake hash target per coin age (nBits)
 +    const CTxIn& txin = vin[0];
 +
 +    // First try finding the previous transaction in database
 +    CTxDB txdb("r");
 +    CTransaction txPrev;
 +    CTxIndex txindex;
 +    if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
 +        return false;  // previous transaction not in main chain
 +    txdb.Close();
 +    if (nTime < txPrev.nTime)
 +        return false;  // Transaction timestamp violation
 +
 +    // Verify signature
-     if (!VerifySignature(txPrev, *this, 0))
++    if (!VerifySignature(txPrev, *this, 0, true, 0))
 +        return DoS(100, error("CheckProofOfStake() : VerifySignature failed on coinstake %s", GetHash().ToString().c_str()));
 +
 +    // Read block header
 +    CBlock block;
 +    if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
 +        return false; // unable to read block of previous transaction
 +    if (block.GetBlockTime() + STAKE_MIN_AGE > nTime)
 +        return false; // only count coins meeting min age requirement
 +
 +    int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
 +    CBigNum bnCoinDay = CBigNum(nValueIn) * (nTime-txPrev.nTime) / COIN / (24 * 60 * 60);
 +    // Calculate hash
-     CDataStream ss(SER_GETHASH, VERSION);
++    CDataStream ss(SER_GETHASH, 0);
 +    ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << txPrev.nTime << txin.prevout.n << nTime;
 +    if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay)
 +        return true;
 +    else
 +        return DoS(100, error("CheckProofOfStake() : check target failed on coinstake %s", GetHash().ToString().c_str()));
 +}
 +
 +// ppcoin: total coin age spent in transaction, in the unit of coin-days.
 +// Only those coins meeting minimum age requirement counts. As those
 +// transactions not in main chain are not currently indexed so we
 +// might not find out about their coin age. Older transactions are 
 +// guaranteed to be in main chain by sync-checkpoint. This rule is
 +// introduced to help nodes establish a consistent view of the coin
 +// age (trust score) of competing branches.
 +bool CTransaction::GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const
 +{
 +    CBigNum bnCentSecond = 0;  // coin age in the unit of cent-seconds
 +    nCoinAge = 0;
 +
 +    if (IsCoinBase())
 +        return true;
 +
 +    BOOST_FOREACH(const CTxIn& txin, vin)
 +    {
 +        // First try finding the previous transaction in database
 +        CTransaction txPrev;
 +        CTxIndex txindex;
 +        if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
 +            continue;  // previous transaction not in main chain
 +        if (nTime < txPrev.nTime)
 +            return false;  // Transaction timestamp violation
 +
 +        // Read block header
 +        CBlock block;
 +        if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
 +            return false; // unable to read block of previous transaction
 +        if (block.GetBlockTime() + STAKE_MIN_AGE > nTime)
 +            continue; // only count coins meeting min age requirement
 +
 +        int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
 +        bnCentSecond += CBigNum(nValueIn) * (nTime-txPrev.nTime) / CENT;
 +
 +        if (fDebug && GetBoolArg("-printcoinage"))
 +            printf("coin age nValueIn=%-12I64d nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString().c_str());
 +    }
 +
 +    CBigNum bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
 +    if (fDebug && GetBoolArg("-printcoinage"))
 +        printf("coin age bnCoinDay=%s\n", bnCoinDay.ToString().c_str());
 +    nCoinAge = bnCoinDay.getuint64();
 +    return true;
 +}
 +
 +// ppcoin: total coin age spent in block, in the unit of coin-days.
 +bool CBlock::GetCoinAge(uint64& nCoinAge) const
 +{
 +    nCoinAge = 0;
 +
 +    CTxDB txdb("r");
 +    BOOST_FOREACH(const CTransaction& tx, vtx)
 +    {
 +        uint64 nTxCoinAge;
 +        if (tx.GetCoinAge(txdb, nTxCoinAge))
 +            nCoinAge += nTxCoinAge;
 +        else
 +            return false;
 +    }
 +
 +    if (nCoinAge == 0) // block coin age minimum 1 coin-day
 +        nCoinAge = 1;
 +    if (fDebug && GetBoolArg("-printcoinage"))
 +        printf("block coin age total nCoinDays=%"PRI64d"\n", nCoinAge);
 +    return true;
 +}
 +
 +
  bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
  {
      // Check for duplicate
      if (!pindexNew)
          return error("AddToBlockIndex() : new CBlockIndex failed");
      map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
 +    if (pindexNew->fProofOfStake) 
 +        setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
 +
      pindexNew->phashBlock = &((*mi).first);
      map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
      if (miPrev != mapBlockIndex.end())
          pindexNew->pprev = (*miPrev).second;
          pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
      }
 -    pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
 +
 +    // ppcoin: compute chain trust score
 +    uint64 nCoinAge;
 +    if (!GetCoinAge(nCoinAge))
 +        return error("AddToBlockIndex() : invalid transaction in block");
 +    pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + nCoinAge;
  
      CTxDB txdb;
-     txdb.TxnBegin();
+     if (!txdb.TxnBegin())
+         return false;
      txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
      if (!txdb.TxnCommit())
          return false;
  
      // New best
 -    if (pindexNew->bnChainWork > bnBestChainWork)
 +    if (pindexNew->nChainTrust > nBestChainTrust)
          if (!SetBestChain(txdb, pindexNew))
              return false;
  
@@@ -1484,63 -1660,51 +1857,77 @@@ bool CBlock::CheckBlock() cons
      // that can be verified before saving an orphan block.
  
      // Size limits
-     if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
+     if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
          return DoS(100, error("CheckBlock() : size limits failed"));
  
      // Check proof of work matches claimed amount
 -    if (!CheckProofOfWork(GetHash(), nBits))
 +    if (IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits))
          return DoS(50, error("CheckBlock() : proof of work failed"));
  
      // Check timestamp
 -    if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
 +    if (GetBlockTime() > GetAdjustedTime() + nMaxClockDrift)
          return error("CheckBlock() : block timestamp too far in the future");
  
      // First transaction must be coinbase, the rest must not be
      if (vtx.empty() || !vtx[0].IsCoinBase())
          return DoS(100, error("CheckBlock() : first tx is not coinbase"));
-     for (int i = 1; i < vtx.size(); i++)
+     for (unsigned int i = 1; i < vtx.size(); i++)
          if (vtx[i].IsCoinBase())
              return DoS(100, error("CheckBlock() : more than one coinbase"));
  
 +    // ppcoin: only the second transaction can be the optional coinstake
 +    for (int i = 2; i < vtx.size(); i++)
 +        if (vtx[i].IsCoinStake())
 +            return DoS(100, error("CheckBlock() : coinstake in wrong position"));
 +
 +    // ppcoin: coinbase output should be empty if proof-of-stake block
 +    if (IsProofOfStake() && !vtx[0].vout[0].IsEmpty())
 +        return error("CheckBlock() : coinbase output not empty for proof-of-stake block");
 +
 +    // Check coinbase timestamp
 +    if (GetBlockTime() > (int64)vtx[0].nTime + nMaxClockDrift)
 +        return DoS(50, error("CheckBlock() : coinbase timestamp is too early"));
 +
 +    // Check coinstake timestamp
 +    if (IsProofOfStake() && GetBlockTime() > (int64)vtx[1].nTime + nMaxClockDrift)
 +        return DoS(50, error("CheckBlock() : coinstake timestamp is too early"));
 +
      // Check transactions
      BOOST_FOREACH(const CTransaction& tx, vtx)
 +    {
          if (!tx.CheckTransaction())
              return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
 +        // ppcoin: check transaction timestamp
 +        if (GetBlockTime() < (int64)tx.nTime)
 +            return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp"));
 +    }
  
-     // Check that it's not full of nonstandard transactions
-     if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
+     // Check for duplicate txids. This is caught by ConnectInputs(),
+     // but catching it earlier avoids a potential DoS attack:
+     set<uint256> uniqueTx;
+     BOOST_FOREACH(const CTransaction& tx, vtx)
+     {
+         uniqueTx.insert(tx.GetHash());
+     }
+     if (uniqueTx.size() != vtx.size())
+         return DoS(100, error("CheckBlock() : duplicate transaction"));
+     unsigned int nSigOps = 0;
+     BOOST_FOREACH(const CTransaction& tx, vtx)
+     {
+         nSigOps += tx.GetLegacySigOpCount();
+     }
+     if (nSigOps > MAX_BLOCK_SIGOPS)
          return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
  
      // Check merkleroot
      if (hashMerkleRoot != BuildMerkleTree())
          return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
  
 +    // ppcoin: check block signature
 +    if (!CheckBlockSignature())
 +        return DoS(100, error("CheckBlock() : bad block signature"));
 +
      return true;
  }
  
@@@ -1558,12 -1722,12 +1945,12 @@@ bool CBlock::AcceptBlock(
      CBlockIndex* pindexPrev = (*mi).second;
      int nHeight = pindexPrev->nHeight+1;
  
 -    // Check proof of work
 -    if (nBits != GetNextWorkRequired(pindexPrev, this))
 -        return DoS(100, error("AcceptBlock() : incorrect proof of work"));
 +    // Check proof-of-work or proof-of-stake
 +    if (nBits != GetNextTargetRequired(pindexPrev, IsProofOfStake()))
 +        return DoS(100, error("AcceptBlock() : incorrect proof-of-work/proof-of-stake"));
  
      // Check timestamp against prev
 -    if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
 +    if (GetBlockTime() <= pindexPrev->GetMedianTimePast() || GetBlockTime() + nMaxClockDrift < pindexPrev->GetBlockTime())
          return error("AcceptBlock() : block's timestamp is too early");
  
      // Check that all transactions are finalized
          if (!tx.IsFinal(nHeight, GetBlockTime()))
              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 DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
 +    // Check that the block chain matches the known block chain up to a hardened checkpoint
 +    if (!Checkpoints::CheckHardened(nHeight, hash))
 +        return DoS(100, error("AcceptBlock() : rejected by hardened checkpoint lockin at %d", nHeight));
 +
 +    // ppcoin: check that the block satisfies synchronized checkpoint
 +    if (!Checkpoints::CheckSync(hash, pindexPrev))
 +        return error("AcceptBlock() : rejected by synchronized checkpoint");
  
      // Write block to history file
-     if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
+     if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
          return error("AcceptBlock() : out of disk space");
      unsigned int nFile = -1;
      unsigned int nBlockPos = 0;
          return error("AcceptBlock() : AddToBlockIndex failed");
  
      // Relay inventory, but don't relay old inventory during initial block download
+     int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
      if (hashBestChain == hash)
-         CRITICAL_BLOCK(cs_vNodes)
-             BOOST_FOREACH(CNode* pnode, vNodes)
-                 if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 140700))
-                     pnode->PushInventory(CInv(MSG_BLOCK, hash));
+     {
+         LOCK(cs_vNodes);
+         BOOST_FOREACH(CNode* pnode, vNodes)
+             if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
+                 pnode->PushInventory(CInv(MSG_BLOCK, hash));
+     }
  
 +    // ppcoin: check pending sync-checkpoint
 +    Checkpoints::AcceptPendingSyncCheckpoint();
 +
      return true;
  }
  
@@@ -1611,67 -1771,45 +2001,68 @@@ bool ProcessBlock(CNode* pfrom, CBlock
      if (mapOrphanBlocks.count(hash))
          return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str());
  
 +    // ppcoin: check proof-of-stake
 +    // Limited duplicity on stake: prevents block flood attack
 +    // Duplicate stake allowed only when there is orphan child block
 +    if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
 +        return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str());
 +
      // Preliminary checks
      if (!pblock->CheckBlock())
          return error("ProcessBlock() : CheckBlock FAILED");
  
 -    CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
 -    if (pcheckpoint && pblock->hashPrevBlock != hashBestChain)
 +    // ppcoin: verify hash target and signature of coinstake tx
 +    if (pblock->IsProofOfStake() && !pblock->vtx[1].CheckProofOfStake(pblock->nBits))
 +        return error("ProcessBlock() : check proof-of-stake failed for block %s", hash.ToString().c_str());
 +
 +    CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint();
 +    if (pcheckpoint && pblock->hashPrevBlock != hashBestChain && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
      {
          // Extra checks to prevent "fill up memory by spamming with bogus blocks"
          int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
          CBigNum bnNewBlock;
          bnNewBlock.SetCompact(pblock->nBits);
          CBigNum bnRequired;
 -        bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
 +        bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, pblock->IsProofOfStake())->nBits, deltaTime));
 +
          if (bnNewBlock > bnRequired)
          {
-             pfrom->Misbehaving(100);
+             if (pfrom)
+                 pfrom->Misbehaving(100);
 -            return error("ProcessBlock() : block with too little proof-of-work");
 +            return error("ProcessBlock() : block with too little %s", pblock->IsProofOfStake()? "proof-of-stake" : "proof-of-work");
          }
      }
  
 +    // ppcoin: ask for pending sync-checkpoint if any
 +    if (!IsInitialBlockDownload())
 +        Checkpoints::AskForPendingSyncCheckpoint(pfrom);
  
      // If don't already have its previous block, shunt it off to holding area until we get it
      if (!mapBlockIndex.count(pblock->hashPrevBlock))
      {
          printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str());
          CBlock* pblock2 = new CBlock(*pblock);
 +        // ppcoin: check proof-of-stake
 +        if (pblock2->IsProofOfStake())
 +        {
 +            // Limited duplicity on stake: prevents block flood attack
 +            // Duplicate stake allowed only when there is orphan child block
 +            if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
 +                return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for orphan block %s", pblock2->GetProofOfStake().first.ToString().c_str(), pblock2->GetProofOfStake().second, hash.ToString().c_str());
 +            else
 +                setStakeSeenOrphan.insert(pblock2->GetProofOfStake());
 +        }
          mapOrphanBlocks.insert(make_pair(hash, pblock2));
          mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
  
          // Ask this guy to fill in what we're missing
          if (pfrom)
 +        {
              pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
 +            // ppcoin: getblocks may not obtain the ancestor block rejected
 +            // earlier by duplicate-stake check so we ask for it again directly
 +            pfrom->AskFor(CInv(MSG_BLOCK, WantedByOrphan(pblock2)));
 +        }
          return true;
      }
  
      // Recursively process any orphan blocks that depended on this one
      vector<uint256> vWorkQueue;
      vWorkQueue.push_back(hash);
-     for (int i = 0; i < vWorkQueue.size(); i++)
+     for (unsigned int i = 0; i < vWorkQueue.size(); i++)
      {
          uint256 hashPrev = vWorkQueue[i];
          for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
              if (pblockOrphan->AcceptBlock())
                  vWorkQueue.push_back(pblockOrphan->GetHash());
              mapOrphanBlocks.erase(pblockOrphan->GetHash());
 +            setStakeSeenOrphan.erase(pblockOrphan->GetProofOfStake());
              delete pblockOrphan;
          }
          mapOrphanBlocksByPrev.erase(hashPrev);
      return true;
  }
  
++// ppcoin: sign block
++bool CBlock::SignBlock(const CKeyStore& keystore)
++{
++    vector<valtype> vSolutions;
++    txnouttype whichType;
++    const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0];
  
++    if (!Solver(txout.scriptPubKey, whichType, vSolutions))
++        return false;
++    if (whichType == TX_PUBKEY)
++    {
++        // Sign
++        const valtype& vchPubKey = vSolutions[0];
++        CKey key;
++        if (!keystore.GetKey(Hash160(vchPubKey), key))
++            return false;
++        if (key.GetPubKey() != vchPubKey)
++            return false;
++        return key.Sign(GetHash(), vchBlockSig);
++    }
++    return false;
++}
++
++// ppcoin: check block signature
++bool CBlock::CheckBlockSignature() const
++{
++    if (GetHash() == hashGenesisBlock)
++        return vchBlockSig.empty();
++
++    vector<valtype> vSolutions;
++    txnouttype whichType;
++    const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0];
++
++    if (!Solver(txout.scriptPubKey, whichType, vSolutions))
++        return false;
++    if (whichType == TX_PUBKEY)
++    {
++        const valtype& vchPubKey = vSolutions[0];
++        CKey key;
++        if (!key.SetPubKey(vchPubKey))
++            return false;
++        if (vchBlockSig.empty())
++            return false;
++        return key.Verify(GetHash(), vchBlockSig);
++    }
++    return false;
++}
  
  
  
@@@ -1718,11 -1855,11 +2155,11 @@@ bool CheckDiskSpace(uint64 nAdditionalB
      if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes)
      {
          fShutdown = true;
-         string strMessage = _("Warning: Disk space is low  ");
+         string strMessage = _("Warning: Disk space is low");
          strMiscWarning = strMessage;
          printf("*** %s\n", strMessage.c_str());
-         ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
-         CreateThread(Shutdown, NULL);
+         ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL);
+         StartShutdown();
          return false;
      }
      return true;
@@@ -1732,7 -1869,7 +2169,7 @@@ FILE* OpenBlockFile(unsigned int nFile
  {
      if (nFile == -1)
          return NULL;
-     FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
+     FILE* file = fopen((GetDataDir() / strprintf("blk%04d.dat", nFile)).string().c_str(), pszMode);
      if (!file)
          return NULL;
      if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
@@@ -1773,7 -1910,7 +2210,7 @@@ bool LoadBlockIndex(bool fAllowNew
  {
      if (fTestNet)
      {
 -        hashGenesisBlock = uint256("0x00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
 +        hashGenesisBlock = hashGenesisBlockTestNet;
          bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28);
          pchMessageStart[0] = 0xfa;
          pchMessageStart[1] = 0xbf;
          //   vMerkleTree: 4a5e1e
  
          // Genesis block
 -        const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
 +        const char* pszTimestamp = "MarketWatch 07/Nov/2011 Gold tops $1,790 to end at over six-week high";
          CTransaction txNew;
 +        txNew.nTime = 1339538219;
          txNew.vin.resize(1);
          txNew.vout.resize(1);
          txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
 -        txNew.vout[0].nValue = 50 * COIN;
 -        txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
 +        txNew.vout[0].SetEmpty();
          CBlock block;
          block.vtx.push_back(txNew);
          block.hashPrevBlock = 0;
          block.hashMerkleRoot = block.BuildMerkleTree();
          block.nVersion = 1;
 -        block.nTime    = 1231006505;
 -        block.nBits    = 0x1d00ffff;
 -        block.nNonce   = 2083236893;
 +        block.nTime    = 1339540307;
 +        block.nBits    = bnProofOfWorkLimit.GetCompact();
 +        block.nNonce   = 1281822831;
  
          if (fTestNet)
          {
          printf("%s\n", block.GetHash().ToString().c_str());
          printf("%s\n", hashGenesisBlock.ToString().c_str());
          printf("%s\n", block.hashMerkleRoot.ToString().c_str());
 -        assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
 +        assert(block.hashMerkleRoot == uint256("0x1557f46a17fcf8843dbe4c0c0edfd1d17eeff2c3c48d73a59d11f5d176e4b54d"));
          block.print();
          assert(block.GetHash() == hashGenesisBlock);
 +        assert(block.CheckBlock());
  
          // Start new block file
          unsigned int nFile;
              return error("LoadBlockIndex() : writing genesis block to disk failed");
          if (!block.AddToBlockIndex(nFile, nBlockPos))
              return error("LoadBlockIndex() : genesis block not accepted");
 +
 +        // ppcoin: initialize synchronized checkpoint
 +        if (!Checkpoints::WriteSyncCheckpoint(hashGenesisBlock))
 +            return error("LoadBlockIndex() : failed to init sync checkpoint");
 +    }
 +
 +    // ppcoin: if checkpoint master key changed must reset sync-checkpoint
 +    {
 +        CTxDB txdb;
 +        string strPubKey = "";
 +        if (!txdb.ReadCheckpointPubKey(strPubKey) || strPubKey != CSyncCheckpoint::strMasterPubKey)
 +        {
 +            // write checkpoint master key to db
 +            txdb.TxnBegin();
 +            if (!txdb.WriteCheckpointPubKey(CSyncCheckpoint::strMasterPubKey))
 +                return error("LoadBlockIndex() : failed to write new checkpoint master key to db");
 +            if (!txdb.TxnCommit())
 +                return error("LoadBlockIndex() : failed to commit new checkpoint master key to db");
 +            if (!Checkpoints::ResetSyncCheckpoint())
 +                return error("LoadBlockIndex() : failed to reset sync-checkpoint");
 +        }
 +        txdb.Close();
      }
  
      return true;
@@@ -1918,12 -2032,11 +2355,12 @@@ void PrintBlockTree(
          // print item
          CBlock block;
          block.ReadFromDisk(pindex);
 -        printf("%d (%u,%u) %s  %s  tx %d",
 +        printf("%d (%u,%u) %s  %08lx  %s  tx %d",
              pindex->nHeight,
              pindex->nFile,
              pindex->nBlockPos,
              block.GetHash().ToString().substr(0,20).c_str(),
 +            block.nBits,
              DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
              block.vtx.size());
  
  
          // put the main timechain first
          vector<CBlockIndex*>& vNext = mapNext[pindex];
-         for (int i = 0; i < vNext.size(); i++)
+         for (unsigned int i = 0; i < vNext.size(); i++)
          {
              if (vNext[i]->pnext)
              {
          }
  
          // iterate children
-         for (int i = 0; i < vNext.size(); i++)
+         for (unsigned int i = 0; i < vNext.size(); i++)
              vStack.push_back(make_pair(nCol+i, vNext[i]));
      }
  }
@@@ -1979,21 -2092,15 +2416,21 @@@ string GetWarnings(string strFor
      }
  
      // Longer invalid proof-of-work chain
 -    if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
 +    if (pindexBest && nBestInvalidTrust > nBestChainTrust + pindexBest->GetBlockTrust() * 6)
      {
          nPriority = 2000;
          strStatusBar = strRPC = "WARNING: Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade.";
      }
  
 +    if (Checkpoints::hashInvalidCheckpoint != 0)
 +    {
 +        nPriority = 3000;
 +        strStatusBar = strRPC = "WARNING: Invalid checkpoint found!  Displayed transactions may not be correct!  You may need to upgrade, or other nodes may need to upgrade.";
 +    }
 +
      // Alerts
-     CRITICAL_BLOCK(cs_mapAlerts)
      {
+         LOCK(cs_mapAlerts);
          BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
          {
              const CAlert& alert = item.second;
@@@ -2020,8 -2127,8 +2457,8 @@@ bool CAlert::ProcessAlert(
      if (!IsInEffect())
          return false;
  
-     CRITICAL_BLOCK(cs_mapAlerts)
      {
+         LOCK(cs_mapAlerts);
          // Cancel previous alerts
          for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
          {
@@@ -2077,8 -2184,21 +2514,21 @@@ bool static AlreadyHave(CTxDB& txdb, co
  {
      switch (inv.type)
      {
-     case MSG_TX:    return mapTransactions.count(inv.hash) || mapOrphanTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
-     case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
+     case MSG_TX:
+         {
+         bool txInMap = false;
+             {
+             LOCK(mempool.cs);
+             txInMap = (mempool.exists(inv.hash));
+             }
+         return txInMap ||
+                mapOrphanTransactions.count(inv.hash) ||
+                txdb.ContainsTx(inv.hash);
+         }
+     case MSG_BLOCK:
+         return mapBlockIndex.count(inv.hash) ||
+                mapOrphanBlocks.count(inv.hash);
      }
      // Don't know what it is, just say we already got one
      return true;
@@@ -2095,7 -2215,7 +2545,7 @@@ unsigned char pchMessageStart[4] = { 0x
  
  bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
  {
-     static map<unsigned int, vector<unsigned char> > mapReuseKey;
+     static map<CService, vector<unsigned char> > mapReuseKey;
      RandAddSeedPerfmon();
      if (fDebug) {
          printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
          CAddress addrFrom;
          uint64 nNonce = 1;
          vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
+         if (pfrom->nVersion < MIN_PROTO_VERSION)
+         {
+             // Since February 20, 2012, the protocol is initiated at version 209,
+             // and earlier versions are no longer supported
+             printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
+             pfrom->fDisconnect = true;
+             return false;
+         }
          if (pfrom->nVersion == 10300)
              pfrom->nVersion = 300;
-         if (pfrom->nVersion >= 106 && !vRecv.empty())
+         if (!vRecv.empty())
              vRecv >> addrFrom >> nNonce;
-         if (pfrom->nVersion >= 106 && !vRecv.empty())
+         if (!vRecv.empty())
              vRecv >> pfrom->strSubVer;
-         if (pfrom->nVersion >= 209 && !vRecv.empty())
+         if (!vRecv.empty())
              vRecv >> pfrom->nStartingHeight;
  
-         if (pfrom->nVersion == 0)
-             return false;
          // Disconnect if we connected to ourself
          if (nNonce == nLocalHostNonce && nNonce > 1)
          {
              return true;
          }
  
 +        // ppcoin: record my external IP reported by peer
 +        if (addrFrom.IsRoutable() && addrMe.IsRoutable())
 +            addrSeenByPeer = addrMe;
 +
          // Be shy and don't send version until we hear
          if (pfrom->fInbound)
              pfrom->PushVersion();
  
          pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
  
-         AddTimeData(pfrom->addr.ip, nTime);
+         AddTimeData(pfrom->addr, nTime);
  
          // Change version
-         if (pfrom->nVersion >= 209)
-             pfrom->PushMessage("verack");
-         pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
-         if (pfrom->nVersion < 209)
-             pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
+         pfrom->PushMessage("verack");
+         pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
  
          if (!pfrom->fInbound)
          {
              // Advertise our address
-             if (addrLocalHost.IsRoutable() && !fUseProxy)
+             if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable() &&
+                 !IsInitialBlockDownload())
              {
                  CAddress addr(addrLocalHost);
                  addr.nTime = GetAdjustedTime();
              }
  
              // Get recent addresses
-             if (pfrom->nVersion >= 31402 || mapAddresses.size() < 1000)
+             if (pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
              {
                  pfrom->PushMessage("getaddr");
                  pfrom->fGetAddr = true;
              }
+             addrman.Good(pfrom->addr);
+         } else {
+             if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
+             {
+                 addrman.Add(addrFrom, addrFrom);
+                 addrman.Good(addrFrom);
+             }
          }
  
          // Ask the first connected node for block updates
-         static int nAskedForBlocks;
+         static int nAskedForBlocks = 0;
          if (!pfrom->fClient &&
-             (pfrom->nVersion < 32000 || pfrom->nVersion >= 32400) &&
+             (pfrom->nVersion < NOBLKS_VERSION_START ||
+              pfrom->nVersion >= NOBLKS_VERSION_END) &&
               (nAskedForBlocks < 1 || vNodes.size() <= 1))
          {
              nAskedForBlocks++;
          }
  
          // Relay alerts
-         CRITICAL_BLOCK(cs_mapAlerts)
+         {
+             LOCK(cs_mapAlerts);
              BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
                  item.second.RelayTo(pfrom);
+         }
  
 +        // ppcoin: relay sync-checkpoint
-         CRITICAL_BLOCK(Checkpoints::cs_hashSyncCheckpoint)
++        {
++            LOCK(Checkpoints::cs_hashSyncCheckpoint);
 +            if (!Checkpoints::checkpointMessage.IsNull())
 +                Checkpoints::checkpointMessage.RelayTo(pfrom);
++        }
 +
          pfrom->fSuccessfullyConnected = true;
  
          printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
  
          cPeerBlockCounts.input(pfrom->nStartingHeight);
 +
 +        // ppcoin: ask for pending sync-checkpoint if any
 +        if (!IsInitialBlockDownload())
 +            Checkpoints::AskForPendingSyncCheckpoint(pfrom);
      }
  
  
  
      else if (strCommand == "verack")
      {
-         pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
+         pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
      }
  
  
          vRecv >> vAddr;
  
          // Don't want addr from older versions unless seeding
-         if (pfrom->nVersion < 209)
-             return true;
-         if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
+         if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000)
              return true;
          if (vAddr.size() > 1000)
          {
          }
  
          // Store the new addresses
-         CAddrDB addrDB;
-         addrDB.TxnBegin();
          int64 nNow = GetAdjustedTime();
          int64 nSince = nNow - 10 * 60;
          BOOST_FOREACH(CAddress& addr, vAddr)
                  continue;
              if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
                  addr.nTime = nNow - 5 * 24 * 60 * 60;
-             AddAddress(addr, 2 * 60 * 60, &addrDB);
              pfrom->AddAddressKnown(addr);
              if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
              {
                  // Relay to a limited number of other nodes
-                 CRITICAL_BLOCK(cs_vNodes)
                  {
+                     LOCK(cs_vNodes);
                      // Use deterministic randomness to send to the same nodes for 24 hours
                      // at a time so the setAddrKnowns of the chosen nodes prevent repeats
                      static uint256 hashSalt;
                      if (hashSalt == 0)
-                         RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
-                     uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
+                         hashSalt = GetRandHash();
+                     int64 hashAddr = addr.GetHash();
+                     uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
                      hashRand = Hash(BEGIN(hashRand), END(hashRand));
                      multimap<uint256, CNode*> mapMix;
                      BOOST_FOREACH(CNode* pnode, vNodes)
                      {
-                         if (pnode->nVersion < 31402)
+                         if (pnode->nVersion < CADDR_TIME_VERSION)
                              continue;
                          unsigned int nPointer;
                          memcpy(&nPointer, &pnode, sizeof(nPointer));
                  }
              }
          }
-         addrDB.TxnCommit();  // Save addresses (it's ok if this fails)
+         addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60);
          if (vAddr.size() < 1000)
              pfrom->fGetAddr = false;
      }
              return error("message inv size() = %d", vInv.size());
          }
  
+         // find last block in inv vector
+         unsigned int nLastBlock = (unsigned int)(-1);
+         for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
+             if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) {
+                 nLastBlock = vInv.size() - 1 - nInv;
+                 break;
+             }
+         }
          CTxDB txdb("r");
-         BOOST_FOREACH(const CInv& inv, vInv)
+         for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
          {
+             const CInv &inv = vInv[nInv];
              if (fShutdown)
                  return true;
              pfrom->AddInventoryKnown(inv);
  
              if (!fAlreadyHave)
                  pfrom->AskFor(inv);
-             else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
+             else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
                  pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
+             } else if (nInv == nLastBlock) {
+                 // In case we are on a very long side-chain, it is possible that we already have
+                 // the last block in an inv bundle sent in response to getblocks. Try to detect
+                 // this situation and push another getblocks to continue.
+                 std::vector<CInv> vGetData(1,inv);
+                 pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0));
+                 if (fDebug)
+                     printf("force request: %s\n", inv.ToString().c_str());
+             }
  
              // Track requests for our stuff
              Inventory(inv.hash);
              else if (inv.IsKnownType())
              {
                  // Send stream from relay memory
-                 CRITICAL_BLOCK(cs_mapRelay)
                  {
+                     LOCK(cs_mapRelay);
                      map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
                      if (mi != mapRelay.end())
                          pfrom->PushMessage(inv.GetCommand(), (*mi).second);
              pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
              CBlock block;
              block.ReadFromDisk(pindex, true);
-             nBytes += block.GetSerializeSize(SER_NETWORK);
+             nBytes += block.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION);
              if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
              {
                  // When this block is requested, we'll send an inv that'll make them
          }
  
          vector<CBlock> vHeaders;
-         int nLimit = 2000 + locator.GetDistanceBack();
-         printf("getheaders %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
+         int nLimit = 2000;
+         printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str());
          for (; pindex; pindex = pindex->pnext)
          {
              vHeaders.push_back(pindex->GetBlockHeader());
      else if (strCommand == "tx")
      {
          vector<uint256> vWorkQueue;
+         vector<uint256> vEraseQueue;
          CDataStream vMsg(vRecv);
+         CTxDB txdb("r");
          CTransaction tx;
          vRecv >> tx;
  
          pfrom->AddInventoryKnown(inv);
  
          bool fMissingInputs = false;
-         if (tx.AcceptToMemoryPool(true, &fMissingInputs))
+         if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs))
          {
              SyncWithWallets(tx, NULL, true);
              RelayMessage(inv, vMsg);
              mapAlreadyAskedFor.erase(inv);
              vWorkQueue.push_back(inv.hash);
+             vEraseQueue.push_back(inv.hash);
  
              // Recursively process any orphan transactions that depended on this one
-             for (int i = 0; i < vWorkQueue.size(); i++)
+             for (unsigned int i = 0; i < vWorkQueue.size(); i++)
              {
                  uint256 hashPrev = vWorkQueue[i];
-                 for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);
-                      mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev);
+                 for (map<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();
+                      mi != mapOrphanTransactionsByPrev[hashPrev].end();
                       ++mi)
                  {
                      const CDataStream& vMsg = *((*mi).second);
                      CTransaction tx;
                      CDataStream(vMsg) >> tx;
                      CInv inv(MSG_TX, tx.GetHash());
+                     bool fMissingInputs2 = false;
  
-                     if (tx.AcceptToMemoryPool(true))
+                     if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs2))
                      {
                          printf("   accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
                          SyncWithWallets(tx, NULL, true);
                          RelayMessage(inv, vMsg);
                          mapAlreadyAskedFor.erase(inv);
                          vWorkQueue.push_back(inv.hash);
+                         vEraseQueue.push_back(inv.hash);
+                     }
+                     else if (!fMissingInputs2)
+                     {
+                         // invalid orphan
+                         vEraseQueue.push_back(inv.hash);
+                         printf("   removed invalid orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
                      }
                  }
              }
  
-             BOOST_FOREACH(uint256 hash, vWorkQueue)
+             BOOST_FOREACH(uint256 hash, vEraseQueue)
                  EraseOrphanTx(hash);
          }
          else if (fMissingInputs)
          {
-             printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
              AddOrphanTx(vMsg);
+             // DoS prevention: do not allow mapOrphanTransactions to grow unbounded
+             unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
+             if (nEvicted > 0)
+                 printf("mapOrphan overflow, removed %u tx\n", nEvicted);
          }
          if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
      }
  
      else if (strCommand == "getaddr")
      {
-         // Nodes rebroadcast an addr every 24 hours
          pfrom->vAddrToSend.clear();
-         int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
-         CRITICAL_BLOCK(cs_mapAddresses)
-         {
-             unsigned int nCount = 0;
-             BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
-             {
-                 const CAddress& addr = item.second;
-                 if (addr.nTime > nSince)
-                     nCount++;
-             }
-             BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
-             {
-                 const CAddress& addr = item.second;
-                 if (addr.nTime > nSince && GetRand(nCount) < 2500)
-                     pfrom->PushAddress(addr);
-             }
-         }
+         vector<CAddress> vAddr = addrman.GetAddr();
+         BOOST_FOREACH(const CAddress &addr, vAddr)
+             pfrom->PushAddress(addr);
      }
  
  
          /// we have a chance to check the order here
  
          // Keep giving the same key to the same ip until they use it
-         if (!mapReuseKey.count(pfrom->addr.ip))
-             pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true);
+         if (!mapReuseKey.count(pfrom->addr))
+             pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);
  
          // Send back approval of order and pubkey to use
          CScript scriptPubKey;
-         scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
+         scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
          pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
      }
  
          vRecv >> hashReply;
  
          CRequestTracker tracker;
-         CRITICAL_BLOCK(pfrom->cs_mapRequests)
          {
+             LOCK(pfrom->cs_mapRequests);
              map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
              if (mi != pfrom->mapRequests.end())
              {
  
      else if (strCommand == "ping")
      {
+         if (pfrom->nVersion > BIP0031_VERSION)
+         {
+             uint64 nonce = 0;
+             vRecv >> nonce;
+             // Echo the message back with the nonce. This allows for two useful features:
+             //
+             // 1) A remote node can quickly check if the connection is operational
+             // 2) Remote nodes can measure the latency of the network thread. If this node
+             //    is overloaded it won't respond to pings quickly and the remote node can
+             //    avoid sending us more work, like chain download requests.
+             //
+             // The nonce stops the remote getting confused between different pings: without
+             // it, if the remote node sends a ping once per second and this node takes 5
+             // seconds to respond to each, the 5th ping the remote sends would appear to
+             // return very quickly.
+             pfrom->PushMessage("pong", nonce);
+         }
      }
  
  
          {
              // Relay
              pfrom->setKnown.insert(alert.GetHash());
-             CRITICAL_BLOCK(cs_vNodes)
+             {
+                 LOCK(cs_vNodes);
                  BOOST_FOREACH(CNode* pnode, vNodes)
                      alert.RelayTo(pnode);
+             }
          }
      }
  
 +    else if (strCommand == "checkpoint")
 +    {
 +        CSyncCheckpoint checkpoint;
 +        vRecv >> checkpoint;
 +
 +        if (checkpoint.ProcessSyncCheckpoint(pfrom))
 +        {
 +            // Relay
 +            pfrom->hashCheckpointKnown = checkpoint.hashCheckpoint;
-             CRITICAL_BLOCK(cs_vNodes)
-                 BOOST_FOREACH(CNode* pnode, vNodes)
-                     checkpoint.RelayTo(pnode);
++            LOCK(cs_vNodes);
++            BOOST_FOREACH(CNode* pnode, vNodes)
++                checkpoint.RelayTo(pnode);
 +        }
 +    }
  
      else
      {
@@@ -2673,7 -2814,7 +3173,7 @@@ bool ProcessMessages(CNode* pfrom
          int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
          if (vRecv.end() - pstart < nHeaderSize)
          {
-             if (vRecv.size() > nHeaderSize)
+             if ((int)vRecv.size() > nHeaderSize)
              {
                  printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
                  vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
          unsigned int nMessageSize = hdr.nMessageSize;
          if (nMessageSize > MAX_SIZE)
          {
-             printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
+             printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
              continue;
          }
          if (nMessageSize > vRecv.size())
          }
  
          // Checksum
-         if (vRecv.GetVersion() >= 209)
+         uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
+         unsigned int nChecksum = 0;
+         memcpy(&nChecksum, &hash, sizeof(nChecksum));
+         if (nChecksum != hdr.nChecksum)
          {
-             uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
-             unsigned int nChecksum = 0;
-             memcpy(&nChecksum, &hash, sizeof(nChecksum));
-             if (nChecksum != hdr.nChecksum)
-             {
-                 printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
-                        strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
-                 continue;
-             }
+             printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+                strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
+             continue;
          }
  
          // Copy message to its own buffer
          bool fRet = false;
          try
          {
-             CRITICAL_BLOCK(cs_main)
+             {
+                 LOCK(cs_main);
                  fRet = ProcessMessage(pfrom, strCommand, vMsg);
+             }
              if (fShutdown)
                  return true;
          }
              if (strstr(e.what(), "end of data"))
              {
                  // Allow exceptions from underlength message on vRecv
-                 printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+                 printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
              }
              else if (strstr(e.what(), "size too large"))
              {
                  // Allow exceptions from overlong size
-                 printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+                 printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
              }
              else
              {
-                 PrintExceptionContinue(&e, "ProcessMessage()");
+                 PrintExceptionContinue(&e, "ProcessMessages()");
              }
          }
          catch (std::exception& e) {
-             PrintExceptionContinue(&e, "ProcessMessage()");
+             PrintExceptionContinue(&e, "ProcessMessages()");
          } catch (...) {
-             PrintExceptionContinue(NULL, "ProcessMessage()");
+             PrintExceptionContinue(NULL, "ProcessMessages()");
          }
  
          if (!fRet)
  
  bool SendMessages(CNode* pto, bool fSendTrickle)
  {
-     CRITICAL_BLOCK(cs_main)
-     {
+     TRY_LOCK(cs_main, lockMain);
+     if (lockMain) {
          // Don't send anything until we get their version message
          if (pto->nVersion == 0)
              return true;
  
-         // Keep-alive ping
-         if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
-             pto->PushMessage("ping");
+         // Keep-alive ping. We send a nonce of zero because we don't use it anywhere
+         // right now.
+         if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) {
+             uint64 nonce = 0;
+             if (pto->nVersion > BIP0031_VERSION)
+                 pto->PushMessage("ping", nonce);
+             else
+                 pto->PushMessage("ping");
+         }
  
          // Resend wallet transactions that haven't gotten in a block yet
          ResendWalletTransactions();
  
          // Address refresh broadcast
          static int64 nLastRebroadcast;
-         if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
+         if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
          {
-             nLastRebroadcast = GetTime();
-             CRITICAL_BLOCK(cs_vNodes)
              {
+                 LOCK(cs_vNodes);
                  BOOST_FOREACH(CNode* pnode, vNodes)
                  {
                      // Periodically clear setAddrKnown to allow refresh broadcasts
-                     pnode->setAddrKnown.clear();
+                     if (nLastRebroadcast)
+                         pnode->setAddrKnown.clear();
  
                      // Rebroadcast our address
-                     if (addrLocalHost.IsRoutable() && !fUseProxy)
+                     if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable())
                      {
                          CAddress addr(addrLocalHost);
                          addr.nTime = GetAdjustedTime();
                      }
                  }
              }
+             nLastRebroadcast = GetTime();
          }
  
-         // Clear out old addresses periodically so it's not too much work at once
-         static int64 nLastClear;
-         if (nLastClear == 0)
-             nLastClear = GetTime();
-         if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3)
-         {
-             nLastClear = GetTime();
-             CRITICAL_BLOCK(cs_mapAddresses)
-             {
-                 CAddrDB addrdb;
-                 int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
-                 for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.begin();
-                      mi != mapAddresses.end();)
-                 {
-                     const CAddress& addr = (*mi).second;
-                     if (addr.nTime < nSince)
-                     {
-                         if (mapAddresses.size() < 1000 || GetTime() > nLastClear + 20)
-                             break;
-                         addrdb.EraseAddress(addr);
-                         mapAddresses.erase(mi++);
-                     }
-                     else
-                         mi++;
-                 }
-             }
-         }
          //
          // Message: addr
          //
          //
          vector<CInv> vInv;
          vector<CInv> vInvWait;
-         CRITICAL_BLOCK(pto->cs_inventory)
          {
+             LOCK(pto->cs_inventory);
              vInv.reserve(pto->vInventoryToSend.size());
              vInvWait.reserve(pto->vInventoryToSend.size());
              BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
                      // 1/4 of tx invs blast to all immediately
                      static uint256 hashSalt;
                      if (hashSalt == 0)
-                         RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
+                         hashSalt = GetRandHash();
                      uint256 hashRand = inv.hash ^ hashSalt;
                      hashRand = Hash(BEGIN(hashRand), END(hashRand));
                      bool fTrickleWait = ((hashRand & 3) != 0);
@@@ -2999,7 -3117,7 +3476,7 @@@ void SHA256Transform(void* pstate, void
          ctx.h[i] = ((uint32_t*)pinit)[i];
  
      SHA256_Update(&ctx, data, sizeof(data));
-     for (int i = 0; i < 8; i++) 
+     for (int i = 0; i < 8; i++)
          ((uint32_t*)pstate)[i] = ctx.h[i];
  }
  
@@@ -3031,7 -3149,7 +3508,7 @@@ unsigned int static ScanHash_CryptoPP(c
          if ((nNonce & 0xffff) == 0)
          {
              nHashesDone = 0xffff+1;
-             return -1;
+             return (unsigned int) -1;
          }
      }
  }
@@@ -3059,9 -3177,12 +3536,12 @@@ public
  };
  
  
+ uint64 nLastBlockTx = 0;
+ uint64 nLastBlockSize = 0;
 -CBlock* CreateNewBlock(CReserveKey& reservekey)
 +CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfWorkOnly)
  {
 -    CBlockIndex* pindexPrev = pindexBest;
 +    CReserveKey reservekey(pwallet);
  
      // Create new block
      auto_ptr<CBlock> pblock(new CBlock());
      // Add our coinbase tx as first transaction
      pblock->vtx.push_back(txNew);
  
 +    // ppcoin: if coinstake available add coinstake tx
 +    static unsigned int nLastCoinStakeCheckTime = GetAdjustedTime() - nMaxClockDrift + 60;  // only initialized at startup
 +    CBlockIndex* pindexPrev = pindexBest;
 +
 +    if (!fProofOfWorkOnly)
 +    {
 +        while (nLastCoinStakeCheckTime < GetAdjustedTime())
 +        {
 +            pindexPrev = pindexBest;  // get best block again to avoid getting stale
 +            pblock->nBits = GetNextTargetRequired(pindexPrev, true);
-             static CCriticalSection cs;
 +            CTransaction txCoinStake;
-             CRITICAL_BLOCK(cs)
 +            {
++                static CCriticalSection cs;
++                LOCK(cs);
 +                // mining may have been suspended for a while so 
 +                // need to take max to satisfy the timestamp protocol
-                 nLastCoinStakeCheckTime = max(++nLastCoinStakeCheckTime, (unsigned int) (GetAdjustedTime() - nMaxClockDrift + 60));
++                nLastCoinStakeCheckTime++;
++                nLastCoinStakeCheckTime = max(nLastCoinStakeCheckTime, (unsigned int) (GetAdjustedTime() - nMaxClockDrift + 60));
 +                txCoinStake.nTime = nLastCoinStakeCheckTime;
 +            }
 +            if (pwallet->CreateCoinStake(pblock->nBits, txCoinStake))
 +            {
 +                pblock->vtx.push_back(txCoinStake);
 +                pblock->vtx[0].vout[0].SetEmpty();
 +                break;
 +            }
 +        }
 +    }
 +
 +    pblock->nBits = GetNextTargetRequired(pindexPrev, pblock->IsProofOfStake());
 +
      // Collect memory pool transactions into the block
      int64 nFees = 0;
-     CRITICAL_BLOCK(cs_main)
-     CRITICAL_BLOCK(cs_mapTransactions)
      {
+         LOCK2(cs_main, mempool.cs);
          CTxDB txdb("r");
  
          // Priority order to process transactions
          list<COrphan> vOrphan; // list memory doesn't move
          map<uint256, vector<COrphan*> > mapDependers;
          multimap<double, CTransaction*> mapPriority;
-         for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi)
+         for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
          {
              CTransaction& tx = (*mi).second;
 -            if (tx.IsCoinBase() || !tx.IsFinal())
 +            if (tx.IsCoinBase() || tx.IsCoinStake() || !tx.IsFinal())
                  continue;
  
              COrphan* porphan = NULL;
                  dPriority += (double)nValueIn * nConf;
  
                  if (fDebug && GetBoolArg("-printpriority"))
-                     printf("priority     nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
+                     printf("priority     nValueIn=%-12"PRI64d" nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
              }
  
              // Priority is sum(valuein * age) / txsize
-             dPriority /= ::GetSerializeSize(tx, SER_NETWORK);
+             dPriority /= ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
  
              if (porphan)
                  porphan->dPriority = dPriority;
          // Collect transactions into block
          map<uint256, CTxIndex> mapTestPool;
          uint64 nBlockSize = 1000;
+         uint64 nBlockTx = 0;
          int nBlockSigOps = 100;
          while (!mapPriority.empty())
          {
              // Take highest priority transaction off priority queue
--            double dPriority = -(*mapPriority.begin()).first;
              CTransaction& tx = *(*mapPriority.begin()).second;
              mapPriority.erase(mapPriority.begin());
  
              // Size limits
-             unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
+             unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
              if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
                  continue;
-             int nTxSigOps = tx.GetSigOpCount();
+             // Legacy limits on sigOps:
+             unsigned int nTxSigOps = tx.GetLegacySigOpCount();
              if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
                  continue;
  
 -            // Transaction fee required depends on block size
 -            bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority));
 -            int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK);
 +            // Timestamp limit
 +            if (tx.nTime > GetAdjustedTime())
 +                continue;
 +
 +            // ppcoin: simplify transaction fee - allow free = false
-             int64 nMinFee = tx.GetMinFee(nBlockSize, false, true);
++            int64 nMinFee = tx.GetMinFee(nBlockSize, false, GMF_BLOCK);
  
              // Connecting shouldn't fail due to dependency on other memory pool transactions
              // because we're already processing them in order of dependency
              map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
-             if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee))
+             MapPrevTx mapInputs;
+             bool fInvalid;
+             if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid))
+                 continue;
+             int64 nTxFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
+             if (nTxFees < nMinFee)
+                 continue;
+             nTxSigOps += tx.GetP2SHSigOpCount(mapInputs);
+             if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
+                 continue;
 -            if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, false, true))
++            if (!tx.ConnectInputs(txdb, mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, false, true))
                  continue;
+             mapTestPoolTmp[tx.GetHash()] = CTxIndex(CDiskTxPos(1,1,1), tx.vout.size());
              swap(mapTestPool, mapTestPoolTmp);
  
              // Added
              pblock->vtx.push_back(tx);
              nBlockSize += nTxSize;
+             ++nBlockTx;
              nBlockSigOps += nTxSigOps;
+             nFees += nTxFees;
  
              // Add transactions that depend on this one to the priority queue
              uint256 hash = tx.GetHash();
                  }
              }
          }
+         nLastBlockTx = nBlockTx;
+         nLastBlockSize = nBlockSize;
+         printf("CreateNewBlock(): total size %lu\n", nBlockSize);
      }
 -    pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
 +    if (pblock->IsProofOfWork())
 +        pblock->vtx[0].vout[0].nValue = GetProofOfWorkReward(pblock->nBits);
  
      // Fill in header
      pblock->hashPrevBlock  = pindexPrev->GetBlockHash();
      pblock->hashMerkleRoot = pblock->BuildMerkleTree();
 +    pblock->nTime          = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
 +    pblock->nTime          = max(pblock->GetBlockTime(), pblock->GetMaxTransactionTime());
 +    pblock->nTime          = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift);
+     pblock->UpdateTime(pindexPrev);
 -    pblock->nBits          = GetNextWorkRequired(pindexPrev, pblock.get());
      pblock->nNonce         = 0;
  
      return pblock.release();
@@@ -3252,7 -3361,9 +3756,9 @@@ void IncrementExtraNonce(CBlock* pblock
          hashPrevBlock = pblock->hashPrevBlock;
      }
      ++nExtraNonce;
-     pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nTime << CBigNum(nExtraNonce);
+     pblock->vtx[0].vin[0].scriptSig = (CScript() << pblock->nTime << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
+     assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
      pblock->hashMerkleRoot = pblock->BuildMerkleTree();
  }
  
@@@ -3292,7 -3403,7 +3798,7 @@@ void FormatHashBuffers(CBlock* pblock, 
      FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
  
      // Byte swap all the input buffer
-     for (int i = 0; i < sizeof(tmp)/4; i++)
+     for (unsigned int i = 0; i < sizeof(tmp)/4; i++)
          ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
  
      // Precalc the first half of the first hash, which stays constant
@@@ -3308,19 -3419,19 +3814,19 @@@ bool CheckWork(CBlock* pblock, CWallet
      uint256 hash = pblock->GetHash();
      uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
  
 -    if (hash > hashTarget)
 -        return false;
 +    if (hash > hashTarget && pblock->IsProofOfWork())
 +        return error("BitcoinMiner : proof-of-work not meeting target");
  
      //// debug print
      printf("BitcoinMiner:\n");
 -    printf("proof-of-work found  \n  hash: %s  \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
 +    printf("new block found  \n  hash: %s  \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
      pblock->print();
      printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
      printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
  
      // Found a solution
-     CRITICAL_BLOCK(cs_main)
      {
+         LOCK(cs_main);
          if (pblock->hashPrevBlock != hashBestChain)
              return error("BitcoinMiner : generated block is stale");
  
          reservekey.KeepKey();
  
          // Track how many getdata requests this block gets
-         CRITICAL_BLOCK(wallet.cs_wallet)
+         {
+             LOCK(wallet.cs_wallet);
              wallet.mapRequestCount[pblock->GetHash()] = 0;
+         }
  
          // Process this block the same as if we had received it from another node
          if (!ProcessBlock(NULL, pblock))
  
  void static ThreadBitcoinMiner(void* parg);
  
+ static bool fGenerateBitcoins = false;
+ static bool fLimitProcessors = false;
+ static int nLimitProcessors = -1;
  void static BitcoinMiner(CWallet *pwallet)
  {
      printf("BitcoinMiner started\n");
  
      while (fGenerateBitcoins)
      {
-         if (AffinityBugWorkaround(ThreadBitcoinMiner))
-             return;
          if (fShutdown)
              return;
          while (vNodes.empty() || IsInitialBlockDownload())
          unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
          CBlockIndex* pindexPrev = pindexBest;
  
 -        auto_ptr<CBlock> pblock(CreateNewBlock(reservekey));
 +        auto_ptr<CBlock> pblock(CreateNewBlock(pwallet));
          if (!pblock.get())
              return;
 +
          IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce);
  
 +        // ppcoin: if proof-of-stake block found then process block
 +        if (pblock->IsProofOfStake())
 +        {
 +            if (!pblock->SignBlock(*pwalletMain))
 +            {
 +                error("BitcoinMiner: Unable to sign new proof-of-stake block");
 +                return;
 +            }
 +            printf("BitcoinMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString().c_str()); 
 +            SetThreadPriority(THREAD_PRIORITY_NORMAL);
 +            CheckWork(pblock.get(), *pwalletMain, reservekey);
 +            SetThreadPriority(THREAD_PRIORITY_LOWEST);
 +            continue;
 +        }
 +
          printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());
  
  
          FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1);
  
          unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
 -        unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8);
          unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
  
  
                                              (char*)&hash, nHashesDone);
  
              // Check if something found
-             if (nNonceFound != -1)
+             if (nNonceFound != (unsigned int) -1)
              {
-                 for (int i = 0; i < sizeof(hash)/4; i++)
+                 for (unsigned int i = 0; i < sizeof(hash)/4; i++)
                      ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
  
                  if (hash <= hashTarget)
                      // Found a solution
                      pblock->nNonce = ByteReverse(nNonceFound);
                      assert(hash == pblock->GetHash());
 +                    if (!pblock->SignBlock(*pwalletMain))
 +                    {
 +                        error("BitcoinMiner: Unable to sign new proof-of-work block");
 +                        return;
 +                    }
  
                      SetThreadPriority(THREAD_PRIORITY_NORMAL);
                      CheckWork(pblock.get(), *pwalletMain, reservekey);
              if (GetTimeMillis() - nHPSTimerStart > 4000)
              {
                  static CCriticalSection cs;
-                 CRITICAL_BLOCK(cs)
                  {
+                     LOCK(cs);
                      if (GetTimeMillis() - nHPSTimerStart > 4000)
                      {
                          dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
                          nHPSTimerStart = GetTimeMillis();
                          nHashCounter = 0;
-                         string strStatus = strprintf("    %.0f khash/s", dHashesPerSec/1000.0);
-                         UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
                          static int64 nLogTime;
                          if (GetTime() - nLogTime > 30 * 60)
                          {
                              nLogTime = GetTime();
                              printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
-                             printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
+                             printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0);
                          }
                      }
                  }
                  return;
              if (!fGenerateBitcoins)
                  return;
-             if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
+             if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors)
                  return;
              if (vNodes.empty())
                  break;
                  break;
  
              // Update nTime every few seconds
 +            pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
 +            pblock->nTime = max(pblock->GetBlockTime(), pblock->GetMaxTransactionTime()); 
 +            pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift);
+             pblock->UpdateTime(pindexPrev);
              nBlockTime = ByteReverse(pblock->nTime);
 -            if (fTestNet)
 -            {
 -                // Changing pblock->nTime can change work required on testnet:
 -                nBlockBits = ByteReverse(pblock->nBits);
 -                hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
 -            }
 +            if (pblock->GetBlockTime() >= (int64)pblock->vtx[0].nTime + nMaxClockDrift)
 +                break;  // need to update coinbase timestamp
          }
      }
  }
@@@ -3513,34 -3608,33 +4022,33 @@@ void static ThreadBitcoinMiner(void* pa
      CWallet* pwallet = (CWallet*)parg;
      try
      {
-         vnThreadsRunning[3]++;
+         vnThreadsRunning[THREAD_MINER]++;
          BitcoinMiner(pwallet);
-         vnThreadsRunning[3]--;
+         vnThreadsRunning[THREAD_MINER]--;
      }
      catch (std::exception& e) {
-         vnThreadsRunning[3]--;
+         vnThreadsRunning[THREAD_MINER]--;
          PrintException(&e, "ThreadBitcoinMiner()");
      } catch (...) {
-         vnThreadsRunning[3]--;
+         vnThreadsRunning[THREAD_MINER]--;
          PrintException(NULL, "ThreadBitcoinMiner()");
      }
-     UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
      nHPSTimerStart = 0;
-     if (vnThreadsRunning[3] == 0)
+     if (vnThreadsRunning[THREAD_MINER] == 0)
          dHashesPerSec = 0;
-     printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
+     printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]);
  }
  
  
  void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
  {
-     if (fGenerateBitcoins != fGenerate)
-     {
-         fGenerateBitcoins = fGenerate;
-         WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
-         MainFrameRepaint();
-     }
-     if (fGenerateBitcoins)
+     fGenerateBitcoins = fGenerate;
+     nLimitProcessors = GetArg("-genproclimit", -1);
+     if (nLimitProcessors == 0)
+         fGenerateBitcoins = false;
+     fLimitProcessors = (nLimitProcessors != -1);
+     if (fGenerate)
      {
          int nProcessors = boost::thread::hardware_concurrency();
          printf("%d processors\n", nProcessors);
              nProcessors = 1;
          if (fLimitProcessors && nProcessors > nLimitProcessors)
              nProcessors = nLimitProcessors;
-         int nAddThreads = nProcessors - vnThreadsRunning[3];
+         int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER];
          printf("Starting %d BitcoinMiner threads\n", nAddThreads);
          for (int i = 0; i < nAddThreads; i++)
          {
diff --combined src/main.h
@@@ -1,41 -1,38 +1,40 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_MAIN_H
  #define BITCOIN_MAIN_H
  
  #include "bignum.h"
  #include "net.h"
- #include "key.h"
  #include "script.h"
- #include "db.h"
+ #ifdef WIN32
+ #include <io.h> /* for _commit */
+ #endif
  
  #include <list>
  
+ class CWallet;
  class CBlock;
  class CBlockIndex;
- class CWalletTx;
- class CWallet;
  class CKeyItem;
  class CReserveKey;
- class CWalletDB;
++class COutPoint;
  
  class CAddress;
  class CInv;
  class CRequestTracker;
  class CNode;
  
  static const unsigned int MAX_BLOCK_SIZE = 1000000;
  static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
- static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
- static const int64 COIN = 1000000;
- static const int64 CENT = 10000;
+ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
+ static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
 -static const int64 MIN_TX_FEE = 50000;
 +static const int64 MIN_TX_FEE = 10000;
  static const int64 MIN_RELAY_TX_FEE = 10000;
 -static const int64 MAX_MONEY = 21000000 * COIN;
 +static const int64 MAX_MONEY = 2000000000 * COIN;
  inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
  static const int COINBASE_MATURITY = 100;
  // Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
@@@ -46,40 -43,35 +45,40 @@@ static const int fHaveUPnP = true
  static const int fHaveUPnP = false;
  #endif
  
 +static const uint256 hashGenesisBlockOfficial("0x000000007c82d1f0aa2896b01bf533a8cc26a1f44790be4ceb4ecde7bee24add");
 +static const uint256 hashGenesisBlockTestNet("0x00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
  
+ extern CScript COINBASE_FLAGS;
  
  
  
  
  extern CCriticalSection cs_main;
  extern std::map<uint256, CBlockIndex*> mapBlockIndex;
 +extern std::set<std::pair<COutPoint, unsigned int> > setStakeSeen;
  extern uint256 hashGenesisBlock;
  extern CBlockIndex* pindexGenesisBlock;
  extern int nBestHeight;
 -extern CBigNum bnBestChainWork;
 -extern CBigNum bnBestInvalidWork;
 +extern uint64 nBestChainTrust;
 +extern uint64 nBestInvalidTrust;
  extern uint256 hashBestChain;
  extern CBlockIndex* pindexBest;
  extern unsigned int nTransactionsUpdated;
+ extern uint64 nLastBlockTx;
+ extern uint64 nLastBlockSize;
+ extern const std::string strMessageMagic;
  extern double dHashesPerSec;
  extern int64 nHPSTimerStart;
  extern int64 nTimeBestReceived;
  extern CCriticalSection cs_setpwalletRegistered;
  extern std::set<CWallet*> setpwalletRegistered;
 +extern std::map<uint256, CBlock*> mapOrphanBlocks;
  
  // Settings
- extern int fGenerateBitcoins;
  extern int64 nTransactionFee;
- extern int fLimitProcessors;
- extern int nLimitProcessors;
- extern int fMinimizeToTray;
- extern int fMinimizeOnClose;
- extern int fUseUPnP;
 +extern int64 nBalanceReserve;
  
  
  
@@@ -100,19 -92,16 +99,19 @@@ void PrintBlockTree()
  bool ProcessMessages(CNode* pfrom);
  bool SendMessages(CNode* pto, bool fSendTrickle);
  void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
 -CBlock* CreateNewBlock(CReserveKey& reservekey);
 +CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfWorkOnly=false);
  void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
  void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
  bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
  bool CheckProofOfWork(uint256 hash, unsigned int nBits);
 +int64 GetProofOfStakeReward(int64 nCoinAge);
  unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
  int GetNumBlocksOfPeers();
  bool IsInitialBlockDownload();
  std::string GetWarnings(std::string strFor);
 -
 +bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew);
 +uint256 WantedByOrphan(const CBlock* pblockOrphan);
 +const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
  
  
  
  
  bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
  
- template<typename T>
- bool WriteSetting(const std::string& strKey, const T& value)
- {
-     bool fOk = false;
-     BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
-     {
-         std::string strWalletFile;
-         if (!GetWalletFile(pwallet, strWalletFile))
-             continue;
-         fOk |= CWalletDB(strWalletFile).WriteSetting(strKey, value);
-     }
-     return fOk;
- }
+ /** Position on disk for a particular transaction. */
  class CDiskTxPos
  {
  public:
      std::string ToString() const
      {
          if (IsNull())
-             return strprintf("null");
+             return "null";
          else
              return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);
      }
  
  
  
+ /** An inpoint - a combination of a transaction and an index n into its vin */
  class CInPoint
  {
  public:
  
  
  
+ /** An outpoint - a combination of a transaction hash and an index n into its vout */
  class COutPoint
  {
  public:
  
  
  
- //
- // An input of a transaction.  It contains the location of the previous
- // transaction's output that it claims and a signature that matches the
- // output's public key.
- //
+ /** An input of a transaction.  It contains the location of the previous
+  * transaction's output that it claims and a signature that matches the
+  * output's public key.
+  */
  class CTxIn
  {
  public:
  
      CTxIn()
      {
-         nSequence = UINT_MAX;
+         nSequence = std::numeric_limits<unsigned int>::max();
      }
  
-     explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX)
+     explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
      {
          prevout = prevoutIn;
          scriptSig = scriptSigIn;
          nSequence = nSequenceIn;
      }
  
-     CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX)
+     CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
      {
          prevout = COutPoint(hashPrevTx, nOut);
          scriptSig = scriptSigIn;
  
      bool IsFinal() const
      {
-         return (nSequence == UINT_MAX);
+         return (nSequence == std::numeric_limits<unsigned int>::max());
      }
  
      friend bool operator==(const CTxIn& a, const CTxIn& b)
      std::string ToString() const
      {
          std::string str;
-         str += strprintf("CTxIn(");
+         str += "CTxIn(";
          str += prevout.ToString();
          if (prevout.IsNull())
              str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
          else
              str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
-         if (nSequence != UINT_MAX)
+         if (nSequence != std::numeric_limits<unsigned int>::max())
              str += strprintf(", nSequence=%u", nSequence);
          str += ")";
          return str;
  
  
  
- //
- // An output of a transaction.  It contains the public key that the next input
- // must be able to sign with to claim it.
- //
+ /** An output of a transaction.  It contains the public key that the next input
+  * must be able to sign with to claim it.
+  */
  class CTxOut
  {
  public:
          return (nValue == -1);
      }
  
-     bool SetEmpty()
++    void SetEmpty()
 +    {
 +        nValue = 0;
 +        scriptPubKey.clear();
 +    }
 +
 +    bool IsEmpty() const
 +    {
 +        return (nValue == 0 && scriptPubKey.empty());
 +    }
 +
      uint256 GetHash() const
      {
          return SerializeHash(*this);
  
      std::string ToString() const
      {
 +        if (IsEmpty()) return "CTxOut(empty)";
          if (scriptPubKey.size() < 6)
              return "CTxOut(error)";
 -        return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
 +        return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().substr(0,30).c_str());
      }
  
      void print() const
  
  
  
- //
- // The basic transaction that is broadcasted on the network and contained in
- // blocks.  A transaction can contain multiple inputs and outputs.
- //
+ enum GetMinFee_mode
+ {
+     GMF_BLOCK,
+     GMF_RELAY,
+     GMF_SEND,
+ };
+ typedef std::map<uint256, std::pair<CTxIndex, CTransaction> > MapPrevTx;
+ /** The basic transaction that is broadcasted on the network and contained in
+  * blocks.  A transaction can contain multiple inputs and outputs.
+  */
  class CTransaction
  {
  public:
      int nVersion;
 +    unsigned int nTime;
      std::vector<CTxIn> vin;
      std::vector<CTxOut> vout;
      unsigned int nLockTime;
      (
          READWRITE(this->nVersion);
          nVersion = this->nVersion;
 +        READWRITE(nTime);
          READWRITE(vin);
          READWRITE(vout);
          READWRITE(nLockTime);
      void SetNull()
      {
          nVersion = 1;
 +        nTime = GetAdjustedTime();
          vin.clear();
          vout.clear();
          nLockTime = 0;
              nBlockHeight = nBestHeight;
          if (nBlockTime == 0)
              nBlockTime = GetAdjustedTime();
-         if ((int64)nLockTime < (nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
+         if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
              return true;
          BOOST_FOREACH(const CTxIn& txin, vin)
              if (!txin.IsFinal())
      {
          if (vin.size() != old.vin.size())
              return false;
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
              if (vin[i].prevout != old.vin[i].prevout)
                  return false;
  
          bool fNewer = false;
-         unsigned int nLowest = UINT_MAX;
-         for (int i = 0; i < vin.size(); i++)
+         unsigned int nLowest = std::numeric_limits<unsigned int>::max();
+         for (unsigned int i = 0; i < vin.size(); i++)
          {
              if (vin[i].nSequence != old.vin[i].nSequence)
              {
  
      bool IsCoinBase() const
      {
 -        return (vin.size() == 1 && vin[0].prevout.IsNull());
 +        return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() == 1);
 +    }
 +
 +    bool IsCoinStake() const
 +    {
 +        // ppcoin: the coin stake transaction is marked with the first output empty
 +        return (vin.size() > 0 && vout.size() == 2 && vout[0].IsEmpty());
      }
  
-     int GetSigOpCount() const
-     {
-         int n = 0;
-         BOOST_FOREACH(const CTxIn& txin, vin)
-             n += txin.scriptSig.GetSigOpCount();
-         BOOST_FOREACH(const CTxOut& txout, vout)
-             n += txout.scriptPubKey.GetSigOpCount();
-         return n;
-     }
+     /** Check for standard transaction types
+         @return True if all outputs (scriptPubKeys) use only standard transaction forms
+     */
+     bool IsStandard() const;
  
-     bool IsStandard() const
-     {
-         BOOST_FOREACH(const CTxIn& txin, vin)
-             if (!txin.scriptSig.IsPushOnly())
-                 return error("nonstandard txin: %s", txin.scriptSig.ToString().c_str());
-         BOOST_FOREACH(const CTxOut& txout, vout)
-             if (!::IsStandard(txout.scriptPubKey))
-                 return error("nonstandard txout: %s", txout.scriptPubKey.ToString().c_str());
-         return true;
-     }
+     /** Check for standard transaction types
+         @param[in] mapInputs  Map of previous transactions that have outputs we're spending
+         @return True if all inputs (scriptSigs) use only standard transaction forms
+         @see CTransaction::FetchInputs
+     */
+     bool AreInputsStandard(const MapPrevTx& mapInputs) const;
+     /** Count ECDSA signature operations the old-fashioned (pre-0.6) way
+         @return number of sigops this transaction's outputs will produce when spent
+         @see CTransaction::FetchInputs
+     */
+     unsigned int GetLegacySigOpCount() const;
  
+     /** 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
+      */
+     unsigned int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const;
+     /** Amount of bitcoins spent by this transaction.
+         @return sum of all outputs (note: does not include fees)
+      */
      int64 GetValueOut() const
      {
          int64 nValueOut = 0;
          return nValueOut;
      }
  
+     /** Amount of bitcoins coming in to this transaction
+         Note that lightweight clients may not know anything besides the hash of previous transactions,
+         so may not be able to calculate this.
+         @param[in] mapInputs  Map of previous transactions that have outputs we're spending
+         @return       Sum of value of all inputs (scriptSigs)
+         @see CTransaction::FetchInputs
+      */
+     int64 GetValueIn(const MapPrevTx& mapInputs) const;
      static bool AllowFree(double dPriority)
      {
          // Large (in bytes) low-priority (new, small-coin) transactions
          return dPriority > COIN * 144 / 250;
      }
  
-     int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, bool fForRelay=false) const
 -    int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const
++    int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, enum GetMinFee_mode mode=GMF_BLOCK) const
      {
          // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
-         int64 nBaseFee = fForRelay ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
+         int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
  
-         unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
+         unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
          unsigned int nNewBlockSize = nBlockSize + nBytes;
          int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
  
  
          // To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01
          if (nMinFee < nBaseFee)
+         {
              BOOST_FOREACH(const CTxOut& txout, vout)
                  if (txout.nValue < CENT)
                      nMinFee = nBaseFee;
+         }
  
          // Raise the price as the block approaches full
          if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2)
  
      bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)
      {
-         CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb");
+         CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION);
          if (!filein)
              return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");
  
          // Read transaction
          if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
              return error("CTransaction::ReadFromDisk() : fseek failed");
-         filein >> *this;
+         try {
+             filein >> *this;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+         }
  
          // Return file pointer
          if (pfileRet)
      friend bool operator==(const CTransaction& a, const CTransaction& b)
      {
          return (a.nVersion  == b.nVersion &&
 +                a.nTime     == b.nTime &&
                  a.vin       == b.vin &&
                  a.vout      == b.vout &&
                  a.nLockTime == b.nLockTime);
      std::string ToString() const
      {
          std::string str;
 -        str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
 +        str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
 +        str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
              GetHash().ToString().substr(0,10).c_str(),
 +            nTime,
              nVersion,
              vin.size(),
              vout.size(),
              nLockTime);
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
              str += "    " + vin[i].ToString() + "\n";
-         for (int i = 0; i < vout.size(); i++)
+         for (unsigned int i = 0; i < vout.size(); i++)
              str += "    " + vout[i].ToString() + "\n";
          return str;
      }
      bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
      bool ReadFromDisk(COutPoint prevout);
      bool DisconnectInputs(CTxDB& txdb);
-     bool ConnectInputs(CTxDB& txdb, std::map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
-                        CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
+     /** Fetch from memory and/or disk. inputsRet keys are transaction hashes.
+      @param[in] txdb  Transaction database
+      @param[in] mapTestPool   List of pending changes to the transaction index database
+      @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& fInvalid);
+     /** Sanity check previous transactions, then, if all checks succeed,
+         mark them as spent by this transaction.
+         @param[in] inputs     Previous transactions (from FetchInputs)
+         @param[out] mapTestPool       Keeps track of inputs that need to be updated on disk
+         @param[in] posThisTx  Position of this transaction on disk
+         @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,
++    bool ConnectInputs(CTxDB& txdb, MapPrevTx inputs,
+                        std::map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
+                        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);
-     bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
- protected:
-     bool AddToMemoryPoolUnchecked();
- public:
-     bool RemoveFromMemoryPool();
 +    bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const;  // ppcoin: get transaction coin age
 +    bool CheckProofOfStake(unsigned int nBits) const;
+ protected:
+     const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const;
  };
  
  
  
  
  
- //
- // A transaction with a merkle branch linking it to the block chain
- //
+ /** A transaction with a merkle branch linking it to the block chain. */
  class CMerkleTx : public CTransaction
  {
  public:
      int nIndex;
  
      // memory only
-     mutable char fMerkleVerified;
+     mutable bool fMerkleVerified;
  
  
      CMerkleTx()
  
  
      int SetMerkleBranch(const CBlock* pblock=NULL);
-     int GetDepthInMainChain(int& nHeightRet) const;
-     int GetDepthInMainChain() const { int nHeight; return GetDepthInMainChain(nHeight); }
+     int GetDepthInMainChain(CBlockIndex* &pindexRet) const;
+     int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
      bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
      int GetBlocksToMaturity() const;
      bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true);
  
  
  
- //
- // A txdb record that contains the disk location of a transaction and the
- // locations of transactions that spend its outputs.  vSpent is really only
- // used as a flag, but having the location is very helpful for debugging.
- //
+ /**  A txdb record that contains the disk location of a transaction and the
+  * locations of transactions that spend its outputs.  vSpent is really only
+  * used as a flag, but having the location is very helpful for debugging.
+  */
  class CTxIndex
  {
  public:
          return !(a == b);
      }
      int GetDepthInMainChain() const;
+  
  };
  
  
  
  
  
- //
- // Nodes collect new transactions into a block, hash them into a hash tree,
- // and scan through nonce values to make the block's hash satisfy proof-of-work
- // requirements.  When they solve the proof-of-work, they broadcast the block
- // to everyone and the block is added to the block chain.  The first transaction
- // in the block is a special one that creates a new coin owned by the creator
- // of the block.
- //
- // Blocks are appended to blk0001.dat files on disk.  Their location on disk
- // is indexed by CBlockIndex objects in memory.
- //
+ /** Nodes collect new transactions into a block, hash them into a hash tree,
+  * and scan through nonce values to make the block's hash satisfy proof-of-work
+  * requirements.  When they solve the proof-of-work, they broadcast the block
+  * to everyone and the block is added to the block chain.  The first transaction
+  * in the block is a special one that creates a new coin owned by the creator
+  * of the block.
+  *
+  * Blocks are appended to blk0001.dat files on disk.  Their location on disk
+  * is indexed by CBlockIndex objects in memory.
+  */
  class CBlock
  {
  public:
      // network and disk
      std::vector<CTransaction> vtx;
  
 +    // ppcoin: block signature - signed by coin base txout[0]'s owner
 +    std::vector<unsigned char> vchBlockSig;
 +
      // memory only
      mutable std::vector<uint256> vMerkleTree;
  
          READWRITE(nBits);
          READWRITE(nNonce);
  
 -        // ConnectBlock depends on vtx being last so it can calculate offset
 +        // ConnectBlock depends on vtx following header to generate CDiskTxPos
          if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))
 +        {
              READWRITE(vtx);
 +            READWRITE(vchBlockSig);
 +        }
          else if (fRead)
 +        {
              const_cast<CBlock*>(this)->vtx.clear();
 +            const_cast<CBlock*>(this)->vchBlockSig.clear();
 +        }
      )
  
      void SetNull()
          nBits = 0;
          nNonce = 0;
          vtx.clear();
 +        vchBlockSig.clear();
          vMerkleTree.clear();
          nDoS = 0;
      }
          return (int64)nTime;
      }
  
+     void UpdateTime(const CBlockIndex* pindexPrev);
 +    // ppcoin: two types of block: proof-of-work or proof-of-stake
 +    bool IsProofOfStake() const
 +    {
 +        return (vtx.size() > 1 && vtx[1].IsCoinStake());
 +    }
 +
 +    bool IsProofOfWork() const
 +    {
 +        return !IsProofOfStake();
 +    }
 +
 +    std::pair<COutPoint, unsigned int> GetProofOfStake() const
 +    {
 +        return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0);
 +    }
 +
 +    // ppcoin: get max transaction timestamp
 +    int64 GetMaxTransactionTime() const
 +    {
 +        int64 maxTransactionTime = 0;
 +        BOOST_FOREACH(const CTransaction& tx, vtx)
 +            maxTransactionTime = std::max(maxTransactionTime, (int64)tx.nTime);
 +        return maxTransactionTime;
 +    }
  
-     int GetSigOpCount() const
-     {
-         int n = 0;
-         BOOST_FOREACH(const CTransaction& tx, vtx)
-             n += tx.GetSigOpCount();
-         return n;
-     }
      uint256 BuildMerkleTree() const
      {
          vMerkleTree.clear();
      bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet)
      {
          // Open history file to append
-         CAutoFile fileout = AppendBlockFile(nFileRet);
+         CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION);
          if (!fileout)
              return error("CBlock::WriteToDisk() : AppendBlockFile failed");
  
          fileout << FLATDATA(pchMessageStart) << nSize;
  
          // Write block
-         nBlockPosRet = ftell(fileout);
-         if (nBlockPosRet == -1)
+         long fileOutPos = ftell(fileout);
+         if (fileOutPos < 0)
              return error("CBlock::WriteToDisk() : ftell failed");
+         nBlockPosRet = fileOutPos;
          fileout << *this;
  
          // Flush stdio buffers and commit to disk before returning
          SetNull();
  
          // Open history file to read
-         CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb");
+         CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION);
          if (!filein)
              return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
          if (!fReadTransactions)
              filein.nType |= SER_BLOCKHEADERONLY;
  
          // Read block
-         filein >> *this;
+         try {
+             filein >> *this;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+         }
  
          // Check the header
 -        if (!CheckProofOfWork(GetHash(), nBits))
 +        if (fReadTransactions && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits))
              return error("CBlock::ReadFromDisk() : errors in block header");
  
          return true;
  
      void print() const
      {
 -        printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n",
 +        printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d, vchBlockSig=%s)\n",
              GetHash().ToString().substr(0,20).c_str(),
              nVersion,
              hashPrevBlock.ToString().substr(0,20).c_str(),
              hashMerkleRoot.ToString().substr(0,10).c_str(),
              nTime, nBits, nNonce,
 -            vtx.size());
 +            vtx.size(),
 +            HexStr(vchBlockSig.begin(), vchBlockSig.end()).c_str());
-         for (int i = 0; i < vtx.size(); i++)
+         for (unsigned int i = 0; i < vtx.size(); i++)
          {
              printf("  ");
              vtx[i].print();
          }
          printf("  vMerkleTree: ");
-         for (int i = 0; i < vMerkleTree.size(); i++)
+         for (unsigned int i = 0; i < vMerkleTree.size(); i++)
              printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str());
          printf("\n");
      }
  
  
-     bool SignBlock(const CKeyStore& keystore)
-     {
-         std::vector<std::pair<opcodetype, valtype> > vSolution;
-         const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0];
-         if (!Solver(txout.scriptPubKey, vSolution))
-             return false;
-         BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
-         {
-             if (item.first == OP_PUBKEY)
-             {
-                 // Sign
-                 const valtype& vchPubKey = item.second;
-                 CKey key;
-                 if (!keystore.GetKey(Hash160(vchPubKey), key))
-                     return false;
-                 if (key.GetPubKey() != vchPubKey)
-                     return false;
-                 return key.Sign(GetHash(), vchBlockSig);
-             }
-         }
-         return false;
-     }
-     bool CheckBlockSignature() const
-     {
-         if (GetHash() == hashGenesisBlock)
-             return vchBlockSig.empty();
-         std::vector<std::pair<opcodetype, valtype> > vSolution;
-         const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0];
-         if (!Solver(txout.scriptPubKey, vSolution))
-             return false;
-         BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
-         {
-             if (item.first == OP_PUBKEY)
-             {
-                 const valtype& vchPubKey = item.second;
-                 CKey key;
-                 if (!key.SetPubKey(vchPubKey))
-                     return false;
-                 if (vchBlockSig.empty())
-                     return false;
-                 return key.Verify(GetHash(), vchBlockSig);
-             }
-         }
-         return false;
-     }
      bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
      bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
      bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
      bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
      bool CheckBlock() const;
      bool AcceptBlock();
 +    bool GetCoinAge(uint64& nCoinAge) const; // ppcoin: calculate total coin age spent in block
++    bool SignBlock(const CKeyStore& keystore);
++    bool CheckBlockSignature() const;
+ private:
+     bool SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew);
  };
  
  
  
  
  
- //
- // The block chain is a tree shaped structure starting with the
- // genesis block at the root, with each block potentially having multiple
- // candidates to be the next block.  pprev and pnext link a path through the
- // main/longest chain.  A blockindex may have multiple pprev pointing back
- // to it, but pnext will only point forward to the longest branch, or will
- // be null if the block is not part of the longest chain.
- //
+ /** The block chain is a tree shaped structure starting with the
+  * genesis block at the root, with each block potentially having multiple
+  * candidates to be the next block.  pprev and pnext link a path through the
+  * main/longest chain.  A blockindex may have multiple pprev pointing back
+  * to it, but pnext will only point forward to the longest branch, or will
+  * be null if the block is not part of the longest chain.
+  */
  class CBlockIndex
  {
  public:
      CBlockIndex* pnext;
      unsigned int nFile;
      unsigned int nBlockPos;
 +    uint64 nChainTrust;// ppcoin: trust score of chain, in the unit of coin-days
      int nHeight;
 -    CBigNum bnChainWork;
 +    bool fProofOfStake; // ppcoin: is the block of proof-of-stake type
 +    COutPoint prevoutStake;
 +    unsigned int nStakeTime;
  
      // block header
      int nVersion;
          nFile = 0;
          nBlockPos = 0;
          nHeight = 0;
 -        bnChainWork = 0;
 +        nChainTrust = 0;
 +        fProofOfStake = true;
 +        prevoutStake.SetNull();
 +        nStakeTime = 0;
  
          nVersion       = 0;
          hashMerkleRoot = 0;
          nFile = nFileIn;
          nBlockPos = nBlockPosIn;
          nHeight = 0;
 -        bnChainWork = 0;
 +        nChainTrust = 0;
 +        fProofOfStake = block.IsProofOfStake();
 +        if (fProofOfStake)
 +        {
 +            prevoutStake = block.vtx[1].vin[0].prevout;
 +            nStakeTime = block.vtx[1].nTime;
 +        }
 +        else
 +        {
 +            prevoutStake.SetNull();
 +            nStakeTime = 0;
 +        }
  
          nVersion       = block.nVersion;
          hashMerkleRoot = block.hashMerkleRoot;
          return (int64)nTime;
      }
  
 -    CBigNum GetBlockWork() const
 +    int64 GetBlockTrust() const
      {
 -        CBigNum bnTarget;
 -        bnTarget.SetCompact(nBits);
 -        if (bnTarget <= 0)
 -            return 0;
 -        return (CBigNum(1)<<256) / (bnTarget+1);
 +        return (nChainTrust - (pprev? pprev->nChainTrust : 0));
      }
  
      bool IsInMainChain() const
  
      bool CheckIndex() const
      {
 -        return CheckProofOfWork(GetBlockHash(), nBits);
 +        return IsProofOfWork() ? CheckProofOfWork(GetBlockHash(), nBits) : true;
      }
  
      bool EraseBlockFromDisk()
      {
          // Open history file
-         CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+");
+         CAutoFile fileout = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb+"), SER_DISK, CLIENT_VERSION);
          if (!fileout)
              return false;
  
          return pindex->GetMedianTimePast();
      }
  
 +    bool IsProofOfWork() const
 +    {
 +        return !fProofOfStake;
 +    }
  
 +    bool IsProofOfStake() const
 +    {
 +        return fProofOfStake;
 +    }
  
      std::string ToString() const
      {
 -        return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",
 -            pprev, pnext, nFile, nBlockPos, nHeight,
 +        return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nChainTrust=%"PRI64d" nHeight=%d, fProofOfStake=%d prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)",
 +            pprev, pnext, nFile, nBlockPos, nChainTrust, nHeight,
 +            fProofOfStake, prevoutStake.ToString().c_str(), nStakeTime,
              hashMerkleRoot.ToString().substr(0,10).c_str(),
              GetBlockHash().ToString().substr(0,20).c_str());
      }
  
  
  
- //
- // Used to marshal pointers into hashes for db storage.
- //
+ /** Used to marshal pointers into hashes for db storage. */
  class CDiskBlockIndex : public CBlockIndex
  {
  public:
          READWRITE(hashNext);
          READWRITE(nFile);
          READWRITE(nBlockPos);
 +        READWRITE(nChainTrust);
          READWRITE(nHeight);
 +        READWRITE(fProofOfStake);
 +        if (fProofOfStake)
 +        {
 +            READWRITE(prevoutStake);
 +            READWRITE(nStakeTime);
 +        }
 +        else if (fRead)
 +        {
 +            const_cast<CDiskBlockIndex*>(this)->prevoutStake.SetNull();
 +            const_cast<CDiskBlockIndex*>(this)->nStakeTime = 0;
 +        }
  
          // block header
          READWRITE(this->nVersion);
  
  
  
- //
- // Describes a place in the block chain to another node such that if the
- // other node doesn't have the same branch, it can find a recent common trunk.
- // The further back it is, the further before the fork it may be.
- //
+ /** Describes a place in the block chain to another node such that if the
+  * other node doesn't have the same branch, it can find a recent common trunk.
+  * The further back it is, the further before the fork it may be.
+  */
  class CBlockLocator
  {
  protected:
@@@ -1419,6 -1300,11 +1408,11 @@@ public
              Set((*mi).second);
      }
  
+     CBlockLocator(const std::vector<uint256>& vHaveIn)
+     {
+         vHave = vHaveIn;
+     }
      IMPLEMENT_SERIALIZE
      (
          if (!(nType & SER_GETHASH))
  
  
  
- //
- // Alerts are for notifying old versions if they become too obsolete and
- // need to upgrade.  The message is displayed in the status bar.
- // Alert messages are broadcast as a vector of signed data.  Unserializing may
- // not read the entire buffer if the alert is for a newer version, but older
- // versions can still relay the original data.
- //
+ /** Alerts are for notifying old versions if they become too obsolete and
+  * need to upgrade.  The message is displayed in the status bar.
+  * Alert messages are broadcast as a vector of signed data.  Unserializing may
+  * not read the entire buffer if the alert is for a newer version, but older
+  * versions can still relay the original data.
+  */
  class CUnsignedAlert
  {
  public:
      }
  };
  
+ /** An alert is a combination of a serialized CUnsignedAlert and a signature. */
  class CAlert : public CUnsignedAlert
  {
  public:
  
      bool AppliesTo(int nVersion, std::string strSubVerIn) const
      {
+         // TODO: rework for client-version-embedded-in-strSubVer ?
          return (IsInEffect() &&
                  nMinVer <= nVersion && nVersion <= nMaxVer &&
                  (setSubVer.empty() || setSubVer.count(strSubVerIn)));
  
      bool AppliesToMe() const
      {
-         return AppliesTo(VERSION, ::pszSubVer);
+         return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
      }
  
      bool RelayTo(CNode* pnode) const
      bool CheckSignature()
      {
          CKey key;
 -        if (!key.SetPubKey(ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284")))
 +        if (!key.SetPubKey(ParseHex("0487ca85b6ae9d311f996c7616d20d0c88a5b4f07d25e78f419019f35cce6522acf978b2d99f0e7a58db1f120439e5c1889266927854aa57c93956c2569188a539")))
              return error("CAlert::CheckSignature() : SetPubKey failed");
          if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
              return error("CAlert::CheckSignature() : verify signature failed");
  
          // Now unserialize the data
-         CDataStream sMsg(vchMsg);
+         CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
          sMsg >> *(CUnsignedAlert*)this;
          return true;
      }
      bool ProcessAlert();
  };
  
+ class CTxMemPool
+ {
+ public:
+     mutable CCriticalSection cs;
+     std::map<uint256, CTransaction> mapTx;
+     std::map<COutPoint, CInPoint> mapNextTx;
+     bool accept(CTxDB& txdb, CTransaction &tx,
+                 bool fCheckInputs, bool* pfMissingInputs);
+     bool addUnchecked(CTransaction &tx);
+     bool remove(CTransaction &tx);
+     unsigned long size()
+     {
+         LOCK(cs);
+         return mapTx.size();
+     }
+     bool exists(uint256 hash)
+     {
+         return (mapTx.count(hash) != 0);
+     }
+     CTransaction& lookup(uint256 hash)
+     {
+         return mapTx[hash];
+     }
+ };
+ extern CTxMemPool mempool;
  #endif
diff --combined src/makefile.mingw
  # Copyright (c) 2009-2010 Satoshi Nakamoto
 +# Copyright (c) 2012 The PPCoin developers
  # Distributed under the MIT/X11 software license, see the accompanying
  # file license.txt or http://www.opensource.org/licenses/mit-license.php.
  
 +# Windows commandline build procedure:
 +# - Install MinGW following http://www.mingw.org/wiki/Getting_Started.
 +#   Install with the C++ and MSYS options checked
 +#
 +# - Add/edit 'MAKE' environment variable with value '/c/MinGW32/bin/mingw32-make.exe'
 +#
 +# - Build openssl library version: 1.0.1b
 +#   download from  http://www.openssl.org/source/
 +#   Extract to c:\openssl-1.0.1b-mgw
 +#   In MinGW MSYS:
 +#     ./config
 +#     make
 +#
 +# - Build Berkeley DB library version: 4.8.30.NC
 +#   download from  http://www.oracle.com/technology/software/products/berkeley-db/index.html
 +#   Extract to c:\db-4.8.30.NC-mgw
 +#   In MinGW MSYS:
 +#     cd build_unix
 +#     sh ../dist/configure --disable-replication --enable-mingw --enable-cxx --prefix=/usr/local
 +#   Edit db.h@113 in build_unix
 +#   from
 +#     typedef pthread_t db_threadid_t;
 +#   to 
 +#     typedef u_int32_t db_threadid_t;
 +#   Then
 +#     make
 +#
 +# - Build Boost C++ library version: 1.47.0
 +#   download from http://www.boost.org/users/download/
 +#   Extract to c:\boost-1.47.0-mgw
 +#   Install Boost.Build:
 +#     cd tools\build\v2
 +#     bootstrap.bat
 +#     b2 install --prefix=BOOST_BUILD_INSTALL_DIR
 +#   Add BOOST_BUILD_INSTALL_DIR to your PATH system environment variable
 +#   Build boost library in MSDOS:
 +#     cd c:\boost-1.47.0-mgw
 +#     bjam toolset=gcc --build-type=complete stage
 +#
 +# - Build ppcoind.exe
 +#   in MinGW MSYS
 +#     cd ppcoin/src
 +#     make ppcoind.exe -f makefile.mingw USE_UPNP=
 +#
 +#
 +
  USE_UPNP:=0
  
  INCLUDEPATHS= \
   -I"C:\boost-1.47.0-mgw" \
   -I"C:\db-4.8.30.NC-mgw\build_unix" \
-  -I"C:\openssl-1.0.0d-mgw\include"
+  -I"C:\openssl-1.0.1b-mgw\include"
  
  LIBPATHS= \
   -L"C:\boost-1.47.0-mgw\stage\lib" \
   -L"C:\db-4.8.30.NC-mgw\build_unix" \
-  -L"C:\openssl-1.0.0d-mgw"
+  -L"C:\openssl-1.0.1b-mgw"
  
  LIBS= \
 - -l boost_system-mgw45-mt-s-1_47 \
 - -l boost_filesystem-mgw45-mt-s-1_47 \
 - -l boost_program_options-mgw45-mt-s-1_47 \
 - -l boost_thread-mgw45-mt-s-1_47 \
 + -l boost_system-mgw46-mt-s-1_47 \
 + -l boost_filesystem-mgw46-mt-s-1_47 \
 + -l boost_program_options-mgw46-mt-s-1_47 \
 + -l boost_thread-mgw46-mt-s-1_47 \
   -l db_cxx \
   -l ssl \
   -l crypto
  
- DEFS=-DWIN32 -D_WINDOWS -DNOPCH -DUSE_SSL -DBOOST_THREAD_USE_LIB
+ DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE
  DEBUGFLAGS=-g
  CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
- HEADERS = \
-     base58.h \
-     bignum.h \
-     checkpoints.h \
-     crypter.h \
-     db.h \
-     headers.h \
-     init.h \
-     irc.h \
-     key.h \
-     keystore.h \
-     main.h \
-     net.h \
-     noui.h \
-     protocol.h \
-     bitcoinrpc.h \
-     script.h \
-     serialize.h \
-     strlcpy.h \
-     uint256.h \
-     util.h \
-     wallet.h
+ TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
  
  ifdef USE_UPNP
   INCLUDEPATHS += -I"C:\miniupnpc-1.6-mgw"
@@@ -105,9 -38,16 +85,16 @@@ endi
  
  LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi
  
+ # TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are
+ HEADERS = $(wildcard *.h)
  OBJS= \
+     obj/version.o \
      obj/checkpoints.o \
+     obj/netbase.o \
+     obj/addrman.o \
      obj/crypter.o \
+     obj/key.o \
      obj/db.o \
      obj/init.o \
      obj/irc.o \
      obj/net.o \
      obj/protocol.o \
      obj/bitcoinrpc.o \
+     obj/rpcdump.o \
      obj/script.o \
      obj/util.o \
-     obj/wallet.o
+     obj/wallet.o \
+     obj/walletdb.o \
+     obj/noui.o
  
  
 -all: bitcoind.exe
 +all: ppcoind.exe
  
- obj/nogui/%.o: %.cpp $(HEADERS)
+ obj/%.o: %.cpp $(HEADERS)
        g++ -c $(CFLAGS) -o $@ $<
  
- ppcoind.exe: $(OBJS:obj/%=obj/nogui/%)
 -bitcoind.exe: $(OBJS:obj/%=obj/%)
++ppcoind.exe: $(OBJS:obj/%=obj/%)
        g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
  
- obj/test/test_bitcoin.o: $(wildcard test/*.cpp) $(HEADERS)
-       g++ -c $(CFLAGS) -o $@ test/test_bitcoin.cpp
+ TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
  
- test_bitcoin.exe: obj/test/test_bitcoin.o $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%))
-       g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
+ obj-test/%.o: test/%.cpp $(HEADERS)
+       g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
+ test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
+       g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS)
  
  clean:
 -      -del /Q bitcoind test_bitcoin
 +      -del /Q ppcoind test_bitcoin
        -del /Q obj\*
-       -del /Q obj\nogui\*
-       -del /Q obj\test\*
-       -del /Q test\*.o
-       -del /Q headers.h.gch
+       -del /Q obj-test\*
+       -del /Q build.h
diff --combined src/makefile.unix
@@@ -1,14 -1,15 +1,16 @@@
  # Copyright (c) 2009-2010 Satoshi Nakamoto
 +# Copyright (c) 2011 The PPCoin developers
  # Distributed under the MIT/X11 software license, see the accompanying
  # file license.txt or http://www.opensource.org/licenses/mit-license.php.
  
  USE_UPNP:=0
  
- DEFS=-DNOPCH
+ DEFS=-DBOOST_SPIRIT_THREADSAFE
  
- DEFS += $(addprefix -I,$(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
- LIBS += $(addprefix -l,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
+ DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
+ LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
+ TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
  
  LMODE = dynamic
  LMODE2 = dynamic
@@@ -17,10 -18,12 +19,12 @@@ ifdef STATI
        ifeq (${STATIC}, all)
                LMODE2 = static
        endif
+ else
+       TESTDEFS += -DBOOST_TEST_DYN_LINK
  endif
  
  # for boost 1.37, add -mt to the boost libraries
- LIBS= \
+ LIBS += \
   -Wl,-B$(LMODE) \
     -l boost_system$(BOOST_LIB_SUFFIX) \
     -l boost_filesystem$(BOOST_LIB_SUFFIX) \
@@@ -38,10 -41,6 +42,6 @@@ ifneq (${USE_UPNP}, -
        DEFS += -DUSE_UPNP=$(USE_UPNP)
  endif
  
- ifneq (${USE_SSL}, 0)
-       DEFS += -DUSE_SSL
- endif
  LIBS+= \
   -Wl,-B$(LMODE2) \
     -l z \
  
  DEBUGFLAGS=-g
  CXXFLAGS=-O2
- xCXXFLAGS=-pthread -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
- HEADERS = \
-     base58.h \
-     bignum.h \
-     checkpoints.h \
-     crypter.h \
-     db.h \
-     headers.h \
-     init.h \
-     irc.h \
-     key.h \
-     keystore.h \
-     main.h \
-     net.h \
-     noui.h \
-     protocol.h \
-     bitcoinrpc.h \
-     script.h \
-     serialize.h \
-     strlcpy.h \
-     uint256.h \
-     util.h \
-     wallet.h
+ xCXXFLAGS=-pthread -Wall -Wextra -Wno-sign-compare -Wno-invalid-offsetof -Wno-unused-parameter -Wformat -Wformat-security \
+     $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
  
  OBJS= \
+     obj/version.o \
      obj/checkpoints.o \
+     obj/netbase.o \
+     obj/addrman.o \
      obj/crypter.o \
+     obj/key.o \
      obj/db.o \
      obj/init.o \
      obj/irc.o \
      obj/net.o \
      obj/protocol.o \
      obj/bitcoinrpc.o \
+     obj/rpcdump.o \
      obj/script.o \
      obj/util.o \
-     obj/wallet.o
+     obj/wallet.o \
+     obj/walletdb.o \
+     obj/noui.o
  
  
 -all: bitcoind
 +all: ppcoind
  
  # auto-generated dependencies:
- -include obj/nogui/*.P
- -include obj/test/*.P
+ -include obj/*.P
+ -include obj-test/*.P
+ obj/build.h: FORCE
+       /bin/sh ../share/genbuild.sh obj/build.h
+ version.cpp: obj/build.h
+ DEFS += -DHAVE_BUILD_INFO
  
- obj/nogui/%.o: %.cpp
+ obj/%.o: %.cpp
        $(CXX) -c $(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)
  
- ppcoind: $(OBJS:obj/%=obj/nogui/%)
 -bitcoind: $(OBJS:obj/%=obj/%)
 -      $(CXX) $(xCXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
++ppcoind: $(OBJS:obj/%=obj/%)
 +      $(CXX) $(xCXXFLAGS) -rdynamic -o $@ $^ $(LDFLAGS) $(LIBS)
  
- obj/test/%.o: test/%.cpp
-       $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
+ TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
+ 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_ppcoin: obj/test/test_ppcoin.o $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%))
-       $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LDFLAGS) $(LIBS)
 -test_bitcoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
++test_ppcoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
+       $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-B$(LMODE) -lboost_unit_test_framework $(LDFLAGS) $(LIBS)
  
  clean:
 -      -rm -f bitcoind test_bitcoin
 +      -rm -f ppcoind test_ppcoin genesis
        -rm -f obj/*.o
-       -rm -f obj/nogui/*.o
-       -rm -f obj/test/*.o
+       -rm -f obj-test/*.o
        -rm -f obj/*.P
-       -rm -f obj/nogui/*.P
-       -rm -f obj/test/*.P
+       -rm -f obj-test/*.P
+       -rm -f src/build.h
 +      -rm -f ppcoin/obj/*
 +
 +ppcoin/obj/genesis.o: ppcoin/genesis.cpp
 +      $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
 +      $(CXX) -c $(xCXXFLAGS) -MMD -DPPCOIN_GENESIS -o obj/nogui/init.o init.cpp
 +
 +genesis: ppcoin/obj/genesis.o $(OBJS:obj/%=obj/nogui/%)
 +      $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS)
-       -rm -f obj/nogui/init.*
++      -rm -f obj/init.*
 +      -rm -f ppcoin/obj/genesis.*
+ FORCE:
diff --combined src/net.cpp
@@@ -1,15 -1,15 +1,16 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
- #include "headers.h"
  #include "irc.h"
  #include "db.h"
  #include "net.h"
  #include "init.h"
  #include "strlcpy.h"
+ #include "addrman.h"
+ #include "ui_interface.h"
  
  #ifdef WIN32
  #include <string.h>
@@@ -30,13 -30,12 +31,12 @@@ static const int MAX_OUTBOUND_CONNECTIO
  void ThreadMessageHandler2(void* parg);
  void ThreadSocketHandler2(void* parg);
  void ThreadOpenConnections2(void* parg);
+ void ThreadOpenAddedConnections2(void* parg);
  #ifdef USE_UPNP
  void ThreadMapPort2(void* parg);
  #endif
  void ThreadDNSAddressSeed2(void* parg);
- bool OpenNetworkConnection(const CAddress& addrConnect);
+ bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant = true);
  
  
  
  //
  bool fClient = false;
  bool fAllowDNS = false;
+ static bool fUseUPnP = false;
  uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
- CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices);
- CAddress addrSeenByPeer("0.0.0.0", 0, false, nLocalServices);
+ CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices);
++CAddress addrSeenByPeer(CService("0.0.0.0", 0), nLocalServices);
  static CNode* pnodeLocalHost = NULL;
  uint64 nLocalHostNonce = 0;
- array<int, 10> vnThreadsRunning;
+ array<int, THREAD_MAX> vnThreadsRunning;
  static SOCKET hListenSocket = INVALID_SOCKET;
+ CAddrMan addrman;
  
  vector<CNode*> vNodes;
  CCriticalSection cs_vNodes;
- map<vector<unsigned char>, CAddress> mapAddresses;
- CCriticalSection cs_mapAddresses;
  map<CInv, CDataStream> mapRelay;
  deque<pair<int64, CInv> > vRelayExpiration;
  CCriticalSection cs_mapRelay;
  map<CInv, int64> mapAlreadyAskedFor;
  
- // Settings
- int fUseProxy = false;
- int nConnectTimeout = 5000;
- CAddress addrProxy("127.0.0.1",9050);
  
+ set<CNetAddr> setservAddNodeAddresses;
+ CCriticalSection cs_setservAddNodeAddresses;
  
+ static CSemaphore *semOutbound = NULL;
  
  unsigned short GetListenPort()
  {
@@@ -88,215 -84,60 +86,60 @@@ void CNode::PushGetBlocks(CBlockIndex* 
  
  
  
- bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout)
+ bool RecvLine(SOCKET hSocket, string& strLine)
  {
-     hSocketRet = INVALID_SOCKET;
-     SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-     if (hSocket == INVALID_SOCKET)
-         return false;
- #ifdef SO_NOSIGPIPE
-     int set = 1;
-     setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
- #endif
-     bool fProxy = (fUseProxy && addrConnect.IsRoutable());
-     struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
- #ifdef WIN32
-     u_long fNonblock = 1;
-     if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
- #else
-     int fFlags = fcntl(hSocket, F_GETFL, 0);
-     if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
- #endif
-     {
-         closesocket(hSocket);
-         return false;
-     }
-     if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
+     strLine = "";
+     loop
      {
-         // WSAEINVAL is here because some legacy version of winsock uses it
-         if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
+         char c;
+         int nBytes = recv(hSocket, &c, 1, 0);
+         if (nBytes > 0)
          {
-             struct timeval timeout;
-             timeout.tv_sec  = nTimeout / 1000;
-             timeout.tv_usec = (nTimeout % 1000) * 1000;
-             fd_set fdset;
-             FD_ZERO(&fdset);
-             FD_SET(hSocket, &fdset);
-             int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
-             if (nRet == 0)
-             {
-                 printf("connection timeout\n");
-                 closesocket(hSocket);
+             if (c == '\n')
+                 continue;
+             if (c == '\r')
+                 return true;
+             strLine += c;
+             if (strLine.size() >= 9000)
+                 return true;
+         }
+         else if (nBytes <= 0)
+         {
+             if (fShutdown)
                  return false;
-             }
-             if (nRet == SOCKET_ERROR)
+             if (nBytes < 0)
              {
-                 printf("select() for connection failed: %i\n",WSAGetLastError());
-                 closesocket(hSocket);
-                 return false;
+                 int nErr = WSAGetLastError();
+                 if (nErr == WSAEMSGSIZE)
+                     continue;
+                 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
+                 {
+                     Sleep(10);
+                     continue;
+                 }
              }
-             socklen_t nRetSize = sizeof(nRet);
- #ifdef WIN32
-             if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
- #else
-             if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
- #endif
+             if (!strLine.empty())
+                 return true;
+             if (nBytes == 0)
              {
-                 printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
-                 closesocket(hSocket);
+                 // socket closed
+                 printf("socket closed\n");
                  return false;
              }
-             if (nRet != 0)
+             else
              {
-                 printf("connect() failed after select(): %s\n",strerror(nRet));
-                 closesocket(hSocket);
+                 // socket error
+                 int nErr = WSAGetLastError();
+                 printf("recv failed: %d\n", nErr);
                  return false;
              }
          }
- #ifdef WIN32
-         else if (WSAGetLastError() != WSAEISCONN)
- #else
-         else
- #endif
-         {
-             printf("connect() failed: %i\n",WSAGetLastError());
-             closesocket(hSocket);
-             return false;
-         }
-     }
-     /*
-     this isn't even strictly necessary
-     CNode::ConnectNode immediately turns the socket back to non-blocking
-     but we'll turn it back to blocking just in case
-     */
- #ifdef WIN32
-     fNonblock = 0;
-     if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
- #else
-     fFlags = fcntl(hSocket, F_GETFL, 0);
-     if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
- #endif
-     {
-         closesocket(hSocket);
-         return false;
-     }
-     if (fProxy)
-     {
-         printf("proxy connecting %s\n", addrConnect.ToString().c_str());
-         char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
-         memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
-         memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
-         char* pszSocks4 = pszSocks4IP;
-         int nSize = sizeof(pszSocks4IP);
-         int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
-         if (ret != nSize)
-         {
-             closesocket(hSocket);
-             return error("Error sending to proxy");
-         }
-         char pchRet[8];
-         if (recv(hSocket, pchRet, 8, 0) != 8)
-         {
-             closesocket(hSocket);
-             return error("Error reading proxy response");
-         }
-         if (pchRet[1] != 0x5a)
-         {
-             closesocket(hSocket);
-             if (pchRet[1] != 0x5b)
-                 printf("ERROR: Proxy returned error %d\n", pchRet[1]);
-             return false;
-         }
-         printf("proxy connected %s\n", addrConnect.ToString().c_str());
      }
-     hSocketRet = hSocket;
-     return true;
  }
  
- // portDefault is in host order
- bool Lookup(const char *pszName, vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup, int portDefault, bool fAllowPort)
- {
-     vaddr.clear();
-     if (pszName[0] == 0)
-         return false;
-     int port = portDefault;
-     char psz[256];
-     char *pszHost = psz;
-     strlcpy(psz, pszName, sizeof(psz));
-     if (fAllowPort)
-     {
-         char* pszColon = strrchr(psz+1,':');
-         char *pszPortEnd = NULL;
-         int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
-         if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
-         {
-             if (psz[0] == '[' && pszColon[-1] == ']')
-             {
-                 // Future: enable IPv6 colon-notation inside []
-                 pszHost = psz+1;
-                 pszColon[-1] = 0;
-             }
-             else
-                 pszColon[0] = 0;
-             port = portParsed;
-             if (port < 0 || port > USHRT_MAX)
-                 port = USHRT_MAX;
-         }
-     }
-     unsigned int addrIP = inet_addr(pszHost);
-     if (addrIP != INADDR_NONE)
-     {
-         // valid IP address passed
-         vaddr.push_back(CAddress(addrIP, port, nServices));
-         return true;
-     }
-     if (!fAllowLookup)
-         return false;
-     struct hostent* phostent = gethostbyname(pszHost);
-     if (!phostent)
-         return false;
-     if (phostent->h_addrtype != AF_INET)
-         return false;
-     char** ppAddr = phostent->h_addr_list;
-     while (*ppAddr != NULL && vaddr.size() != nMaxSolutions)
-     {
-         CAddress addr(((struct in_addr*)ppAddr[0])->s_addr, port, nServices);
-         if (addr.IsValid())
-             vaddr.push_back(addr);
-         ppAddr++;
-     }
-     return (vaddr.size() > 0);
- }
  
- // portDefault is in host order
- bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup, int portDefault, bool fAllowPort)
- {
-     vector<CAddress> vaddr;
-     bool fRet = Lookup(pszName, vaddr, nServices, 1, fAllowLookup, portDefault, fAllowPort);
-     if (fRet)
-         addr = vaddr[0];
-     return fRet;
- }
  
- bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
+ bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
  {
      SOCKET hSocket;
      if (!ConnectSocket(addrConnect, hSocket))
                  }
                  if (pszKeyword == NULL)
                      break;
-                 if (strLine.find(pszKeyword) != -1)
+                 if (strLine.find(pszKeyword) != string::npos)
                  {
                      strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
                      break;
                  }
              }
              closesocket(hSocket);
-             if (strLine.find("<") != -1)
+             if (strLine.find("<") != string::npos)
                  strLine = strLine.substr(0, strLine.find("<"));
              strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
              while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
                  strLine.resize(strLine.size()-1);
-             CAddress addr(strLine,0,true);
+             CService addr(strLine,0,true);
              printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
-             if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
+             if (!addr.IsValid() || !addr.IsRoutable())
                  return false;
-             ipRet = addr.ip;
+             ipRet.SetIP(addr);
              return true;
          }
      }
  }
  
  // We now get our external IP from the IRC server first and only use this as a backup
- bool GetMyExternalIP(unsigned int& ipRet)
+ bool GetMyExternalIP(CNetAddr& ipRet)
  {
-     CAddress addrConnect;
+     CService addrConnect;
      const char* pszGet;
      const char* pszKeyword;
  
-     if (fUseProxy)
+     if (fNoListen||fUseProxy)
          return false;
  
      for (int nLookup = 0; nLookup <= 1; nLookup++)
          //  <?php echo $_SERVER["REMOTE_ADDR"]; ?>
          if (nHost == 1)
          {
-             addrConnect = CAddress("91.198.22.70",80); // checkip.dyndns.org
+             addrConnect = CService("91.198.22.70",80); // checkip.dyndns.org
  
              if (nLookup == 1)
              {
-                 CAddress addrIP("checkip.dyndns.org", 80, true);
+                 CService addrIP("checkip.dyndns.org", 80, true);
                  if (addrIP.IsValid())
                      addrConnect = addrIP;
              }
          }
          else if (nHost == 2)
          {
-             addrConnect = CAddress("74.208.43.192", 80); // www.showmyip.com
+             addrConnect = CService("74.208.43.192", 80); // www.showmyip.com
  
              if (nLookup == 1)
              {
-                 CAddress addrIP("www.showmyip.com", 80, true);
+                 CService addrIP("www.showmyip.com", 80, true);
                  if (addrIP.IsValid())
                      addrConnect = addrIP;
              }
  
  void ThreadGetMyExternalIP(void* parg)
  {
 -    // Wait for IRC to get it first
 -    if (GetBoolArg("-irc", false))
 +    // Wait for IRC to get it first - disabled with ppcoin
-     if (false && !GetBoolArg("-noirc"))
++    if (false && GetBoolArg("-irc", false))
      {
          for (int i = 0; i < 2 * 60; i++)
          {
      }
  
      // Fallback in case IRC fails to get it
-     if (GetMyExternalIP(addrLocalHost.ip))
+     if (GetMyExternalIP(addrLocalHost))
      {
          printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
          if (addrLocalHost.IsRoutable())
              // setAddrKnown automatically filters any duplicate sends.
              CAddress addr(addrLocalHost);
              addr.nTime = GetAdjustedTime();
-             CRITICAL_BLOCK(cs_vNodes)
+             {
+                 LOCK(cs_vNodes);
                  BOOST_FOREACH(CNode* pnode, vNodes)
                      pnode->PushAddress(addr);
-         }
-     }
- }
- bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
- {
-     if (!addr.IsRoutable())
-         return false;
-     if (addr.ip == addrLocalHost.ip)
-         return false;
-     addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
-     bool fUpdated = false;
-     bool fNew = false;
-     CAddress addrFound = addr;
-     CRITICAL_BLOCK(cs_mapAddresses)
-     {
-         map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
-         if (it == mapAddresses.end())
-         {
-             // New address
-             printf("AddAddress(%s)\n", addr.ToString().c_str());
-             mapAddresses.insert(make_pair(addr.GetKey(), addr));
-             fUpdated = true;
-             fNew = true;
-         }
-         else
-         {
-             addrFound = (*it).second;
-             if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
-             {
-                 // Services have been added
-                 addrFound.nServices |= addr.nServices;
-                 fUpdated = true;
-             }
-             bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
-             int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
-             if (addrFound.nTime < addr.nTime - nUpdateInterval)
-             {
-                 // Periodically update most recently seen time
-                 addrFound.nTime = addr.nTime;
-                 fUpdated = true;
-             }
-         }
-     }
-     // There is a nasty deadlock bug if this is done inside the cs_mapAddresses
-     // CRITICAL_BLOCK:
-     // Thread 1:  begin db transaction (locks inside-db-mutex)
-     //            then AddAddress (locks cs_mapAddresses)
-     // Thread 2:  AddAddress (locks cs_mapAddresses)
-     //             ... then db operation hangs waiting for inside-db-mutex
-     if (fUpdated)
-     {
-         if (pAddrDB)
-             pAddrDB->WriteAddress(addrFound);
-         else
-             CAddrDB().WriteAddress(addrFound);
-     }
-     return fNew;
- }
- void AddressCurrentlyConnected(const CAddress& addr)
- {
-     CRITICAL_BLOCK(cs_mapAddresses)
-     {
-         // Only if it's been published already
-         map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
-         if (it != mapAddresses.end())
-         {
-             CAddress& addrFound = (*it).second;
-             int64 nUpdateInterval = 20 * 60;
-             if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
-             {
-                 // Periodically update most recently seen time
-                 addrFound.nTime = GetAdjustedTime();
-                 CAddrDB addrdb;
-                 addrdb.WriteAddress(addrFound);
              }
          }
      }
  
  
  
- void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
+ void AddressCurrentlyConnected(const CService& addr)
  {
-     // If the dialog might get closed before the reply comes back,
-     // call this in the destructor so it doesn't get called after it's deleted.
-     CRITICAL_BLOCK(cs_vNodes)
-     {
-         BOOST_FOREACH(CNode* pnode, vNodes)
-         {
-             CRITICAL_BLOCK(pnode->cs_mapRequests)
-             {
-                 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
-                 {
-                     CRequestTracker& tracker = (*mi).second;
-                     if (tracker.fn == fn && tracker.param1 == param1)
-                         pnode->mapRequests.erase(mi++);
-                     else
-                         mi++;
-                 }
-             }
-         }
-     }
+     addrman.Connected(addr);
  }
  
  
  
  
  
- //
- // Subscription methods for the broadcast and subscription system.
- // Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
- //
- // The subscription system uses a meet-in-the-middle strategy.
- // With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
- // subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
- //
- bool AnySubscribed(unsigned int nChannel)
- {
-     if (pnodeLocalHost->IsSubscribed(nChannel))
-         return true;
-     CRITICAL_BLOCK(cs_vNodes)
-         BOOST_FOREACH(CNode* pnode, vNodes)
-             if (pnode->IsSubscribed(nChannel))
-                 return true;
-     return false;
- }
- bool CNode::IsSubscribed(unsigned int nChannel)
- {
-     if (nChannel >= vfSubscribe.size())
-         return false;
-     return vfSubscribe[nChannel];
- }
- void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
- {
-     if (nChannel >= vfSubscribe.size())
-         return;
-     if (!AnySubscribed(nChannel))
-     {
-         // Relay subscribe
-         CRITICAL_BLOCK(cs_vNodes)
-             BOOST_FOREACH(CNode* pnode, vNodes)
-                 if (pnode != this)
-                     pnode->PushMessage("subscribe", nChannel, nHops);
-     }
-     vfSubscribe[nChannel] = true;
- }
- void CNode::CancelSubscribe(unsigned int nChannel)
+ CNode* FindNode(const CNetAddr& ip)
  {
-     if (nChannel >= vfSubscribe.size())
-         return;
-     // Prevent from relaying cancel if wasn't subscribed
-     if (!vfSubscribe[nChannel])
-         return;
-     vfSubscribe[nChannel] = false;
-     if (!AnySubscribed(nChannel))
-     {
-         // Relay subscription cancel
-         CRITICAL_BLOCK(cs_vNodes)
-             BOOST_FOREACH(CNode* pnode, vNodes)
-                 if (pnode != this)
-                     pnode->PushMessage("sub-cancel", nChannel);
-     }
- }
- CNode* FindNode(unsigned int ip)
- {
-     CRITICAL_BLOCK(cs_vNodes)
      {
+         LOCK(cs_vNodes);
          BOOST_FOREACH(CNode* pnode, vNodes)
-             if (pnode->addr.ip == ip)
+             if ((CNetAddr)pnode->addr == ip)
                  return (pnode);
      }
      return NULL;
  }
  
- CNode* FindNode(CAddress addr)
+ CNode* FindNode(const CService& addr)
  {
-     CRITICAL_BLOCK(cs_vNodes)
      {
+         LOCK(cs_vNodes);
          BOOST_FOREACH(CNode* pnode, vNodes)
-             if (pnode->addr == addr)
+             if ((CService)pnode->addr == addr)
                  return (pnode);
      }
      return NULL;
  
  CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
  {
-     if (addrConnect.ip == addrLocalHost.ip)
+     if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost)
          return NULL;
  
      // Look for an existing connection
-     CNode* pnode = FindNode(addrConnect.ip);
+     CNode* pnode = FindNode((CService)addrConnect);
      if (pnode)
      {
          if (nTimeout != 0)
      }
  
      /// debug print
-     printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
+     printf("trying connection %s lastseen=%.1fhrs\n",
          addrConnect.ToString().c_str(),
-         (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
-         (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
+         (double)(addrConnect.nTime - GetAdjustedTime())/3600.0);
  
-     CRITICAL_BLOCK(cs_mapAddresses)
-         mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
+     addrman.Attempt(addrConnect);
  
      // Connect
      SOCKET hSocket;
              pnode->AddRef(nTimeout);
          else
              pnode->AddRef();
-         CRITICAL_BLOCK(cs_vNodes)
+         {
+             LOCK(cs_vNodes);
              vNodes.push_back(pnode);
+         }
  
          pnode->nTimeConnected = GetTime();
          return pnode;
@@@ -714,22 -385,31 +387,31 @@@ void CNode::CloseSocketDisconnect(
          printf("disconnecting node %s\n", addr.ToString().c_str());
          closesocket(hSocket);
          hSocket = INVALID_SOCKET;
+         vRecv.clear();
      }
  }
  
  void CNode::Cleanup()
  {
-     // All of a nodes broadcasts and subscriptions are automatically torn down
-     // when it goes down, so a node has to stay up to keep its broadcast going.
+ }
  
-     // Cancel subscriptions
-     for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
-         if (vfSubscribe[nChannel])
-             CancelSubscribe(nChannel);
+ void CNode::PushVersion()
+ {
+     /// when NTP implemented, change to just nTime = GetAdjustedTime()
+     int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
+     CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr);
+     CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress(CService("0.0.0.0",0)) : addrLocalHost);
+     RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
+     PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
+                 nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
  }
  
  
- std::map<unsigned int, int64> CNode::setBanned;
+ std::map<CNetAddr, int64> CNode::setBanned;
  CCriticalSection CNode::cs_setBanned;
  
  void CNode::ClearBanned()
      setBanned.clear();
  }
  
- bool CNode::IsBanned(unsigned int ip)
+ bool CNode::IsBanned(CNetAddr ip)
  {
      bool fResult = false;
-     CRITICAL_BLOCK(cs_setBanned)
      {
-         std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
+         LOCK(cs_setBanned);
+         std::map<CNetAddr, int64>::iterator i = setBanned.find(ip);
          if (i != setBanned.end())
          {
              int64 t = (*i).second;
@@@ -765,9 -445,11 +447,11 @@@ bool CNode::Misbehaving(int howmuch
      if (nMisbehavior >= GetArg("-banscore", 100))
      {
          int64 banTime = GetTime()+GetArg("-bantime", 60*60*24);  // Default 24-hour ban
-         CRITICAL_BLOCK(cs_setBanned)
-             if (setBanned[addr.ip] < banTime)
-                 setBanned[addr.ip] = banTime;
+         {
+             LOCK(cs_setBanned);
+             if (setBanned[addr] < banTime)
+                 setBanned[addr] = banTime;
+         }
          CloseSocketDisconnect();
          printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
          return true;
@@@ -791,15 -473,15 +475,15 @@@ void ThreadSocketHandler(void* parg
      IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
      try
      {
-         vnThreadsRunning[0]++;
+         vnThreadsRunning[THREAD_SOCKETHANDLER]++;
          ThreadSocketHandler2(parg);
-         vnThreadsRunning[0]--;
+         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
      }
      catch (std::exception& e) {
-         vnThreadsRunning[0]--;
+         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
          PrintException(&e, "ThreadSocketHandler()");
      } catch (...) {
-         vnThreadsRunning[0]--;
+         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
          throw; // support pthread_cancel()
      }
      printf("ThreadSocketHandler exiting\n");
@@@ -809,15 -491,15 +493,15 @@@ void ThreadSocketHandler2(void* parg
  {
      printf("ThreadSocketHandler started\n");
      list<CNode*> vNodesDisconnected;
-     int nPrevNodeCount = 0;
+     unsigned int nPrevNodeCount = 0;
  
      loop
      {
          //
          // Disconnect nodes
          //
-         CRITICAL_BLOCK(cs_vNodes)
          {
+             LOCK(cs_vNodes);
              // Disconnect unused nodes
              vector<CNode*> vNodesCopy = vNodes;
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                      // remove from vNodes
                      vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
  
+                     if (pnode->fHasGrant)
+                         semOutbound->post();
+                     pnode->fHasGrant = false;
                      // close socket and cleanup
                      pnode->CloseSocketDisconnect();
                      pnode->Cleanup();
                  if (pnode->GetRefCount() <= 0)
                  {
                      bool fDelete = false;
-                     TRY_CRITICAL_BLOCK(pnode->cs_vSend)
-                      TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
-                       TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
-                        TRY_CRITICAL_BLOCK(pnode->cs_inventory)
-                         fDelete = true;
+                     {
+                         TRY_LOCK(pnode->cs_vSend, lockSend);
+                         if (lockSend)
+                         {
+                             TRY_LOCK(pnode->cs_vRecv, lockRecv);
+                             if (lockRecv)
+                             {
+                                 TRY_LOCK(pnode->cs_mapRequests, lockReq);
+                                 if (lockReq)
+                                 {
+                                     TRY_LOCK(pnode->cs_inventory, lockInv);
+                                     if (lockInv)
+                                         fDelete = true;
+                                 }
+                             }
+                         }
+                     }
                      if (fDelete)
                      {
                          vNodesDisconnected.remove(pnode);
          if(hListenSocket != INVALID_SOCKET)
              FD_SET(hListenSocket, &fdsetRecv);
          hSocketMax = max(hSocketMax, hListenSocket);
-         CRITICAL_BLOCK(cs_vNodes)
          {
+             LOCK(cs_vNodes);
              BOOST_FOREACH(CNode* pnode, vNodes)
              {
                  if (pnode->hSocket == INVALID_SOCKET)
                  FD_SET(pnode->hSocket, &fdsetRecv);
                  FD_SET(pnode->hSocket, &fdsetError);
                  hSocketMax = max(hSocketMax, pnode->hSocket);
-                 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
-                     if (!pnode->vSend.empty())
+                 {
+                     TRY_LOCK(pnode->cs_vSend, lockSend);
+                     if (lockSend && !pnode->vSend.empty())
                          FD_SET(pnode->hSocket, &fdsetSend);
+                 }
              }
          }
  
-         vnThreadsRunning[0]--;
+         vnThreadsRunning[THREAD_SOCKETHANDLER]--;
          int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
-         vnThreadsRunning[0]++;
+         vnThreadsRunning[THREAD_SOCKETHANDLER]++;
          if (fShutdown)
              return;
          if (nSelect == SOCKET_ERROR)
          {
              int nErr = WSAGetLastError();
-             if (hSocketMax > -1)
+             if (hSocketMax != INVALID_SOCKET)
              {
                  printf("socket select error %d\n", nErr);
-                 for (int i = 0; i <= hSocketMax; i++)
+                 for (unsigned int i = 0; i <= hSocketMax; i++)
                      FD_SET(i, &fdsetRecv);
              }
              FD_ZERO(&fdsetSend);
              struct sockaddr_in sockaddr;
              socklen_t len = sizeof(sockaddr);
              SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
-             CAddress addr(sockaddr);
+             CAddress addr;
              int nInbound = 0;
  
-             CRITICAL_BLOCK(cs_vNodes)
+             if (hSocket != INVALID_SOCKET)
+                 addr = CAddress(sockaddr);
+             {
+                 LOCK(cs_vNodes);
                  BOOST_FOREACH(CNode* pnode, vNodes)
-                 if (pnode->fInbound)
-                     nInbound++;
+                     if (pnode->fInbound)
+                         nInbound++;
+             }
              if (hSocket == INVALID_SOCKET)
              {
                  if (WSAGetLastError() != WSAEWOULDBLOCK)
              }
              else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
              {
-                 closesocket(hSocket);
+                 {
+                     LOCK(cs_setservAddNodeAddresses);
+                     if (!setservAddNodeAddresses.count(addr))
+                         closesocket(hSocket);
+                 }
              }
-             else if (CNode::IsBanned(addr.ip))
+             else if (CNode::IsBanned(addr))
              {
-                 printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
+                 printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
                  closesocket(hSocket);
              }
              else
                  printf("accepted connection %s\n", addr.ToString().c_str());
                  CNode* pnode = new CNode(hSocket, addr, true);
                  pnode->AddRef();
-                 CRITICAL_BLOCK(cs_vNodes)
+                 {
+                     LOCK(cs_vNodes);
                      vNodes.push_back(pnode);
+                 }
              }
          }
  
          // Service each socket
          //
          vector<CNode*> vNodesCopy;
-         CRITICAL_BLOCK(cs_vNodes)
          {
+             LOCK(cs_vNodes);
              vNodesCopy = vNodes;
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                  pnode->AddRef();
                  continue;
              if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
              {
-                 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
+                 TRY_LOCK(pnode->cs_vRecv, lockRecv);
+                 if (lockRecv)
                  {
                      CDataStream& vRecv = pnode->vRecv;
                      unsigned int nPos = vRecv.size();
                  continue;
              if (FD_ISSET(pnode->hSocket, &fdsetSend))
              {
-                 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
+                 TRY_LOCK(pnode->cs_vSend, lockSend);
+                 if (lockSend)
                  {
                      CDataStream& vSend = pnode->vSend;
                      if (!vSend.empty())
                  }
              }
          }
-         CRITICAL_BLOCK(cs_vNodes)
          {
+             LOCK(cs_vNodes);
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                  pnode->Release();
          }
@@@ -1110,15 -824,15 +826,15 @@@ void ThreadMapPort(void* parg
      IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg));
      try
      {
-         vnThreadsRunning[5]++;
+         vnThreadsRunning[THREAD_UPNP]++;
          ThreadMapPort2(parg);
-         vnThreadsRunning[5]--;
+         vnThreadsRunning[THREAD_UPNP]--;
      }
      catch (std::exception& e) {
-         vnThreadsRunning[5]--;
+         vnThreadsRunning[THREAD_UPNP]--;
          PrintException(&e, "ThreadMapPort()");
      } catch (...) {
-         vnThreadsRunning[5]--;
+         vnThreadsRunning[THREAD_UPNP]--;
          PrintException(NULL, "ThreadMapPort()");
      }
      printf("ThreadMapPort exiting\n");
@@@ -1131,7 -845,6 +847,6 @@@ void ThreadMapPort2(void* parg
      char port[6];
      sprintf(port, "%d", GetListenPort());
  
-     const char * rootdescurl = 0;
      const char * multicastif = 0;
      const char * minissdpdpath = 0;
      struct UPNPDev * devlist = 0;
      r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
      if (r == 1)
      {
-         char intClient[16];
-         char intPort[6];
+         if (!addrLocalHost.IsRoutable())
+         {
+             char externalIPAddress[40];
+             r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
+             if(r != UPNPCOMMAND_SUCCESS)
+                 printf("UPnP: GetExternalIPAddress() returned %d\n", r);
+             else
+             {
+                 if(externalIPAddress[0])
+                 {
+                     printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
+                     CAddress addrExternalFromUPnP(CService(externalIPAddress, 0), nLocalServices);
+                     if (addrExternalFromUPnP.IsRoutable())
+                         addrLocalHost = addrExternalFromUPnP;
+                 }
+                 else
+                     printf("UPnP: GetExternalIPAddress failed.\n");
+             }
+         }
          string strDesc = "Bitcoin " + FormatFullVersion();
  #ifndef UPNPDISCOVER_SUCCESS
-     /* miniupnpc 1.5 */
+         /* miniupnpc 1.5 */
          r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
-                               port, port, lanaddr, strDesc.c_str(), "TCP", 0);
+                             port, port, lanaddr, strDesc.c_str(), "TCP", 0);
  #else
-     /* miniupnpc 1.6 */
+         /* miniupnpc 1.6 */
          r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
-                               port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
+                             port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
  #endif
  
          if(r!=UPNPCOMMAND_SUCCESS)
                  port, port, lanaddr, r, strupnperror(r));
          else
              printf("UPnP Port Mapping successful.\n");
+         int i = 1;
          loop {
              if (fShutdown || !fUseUPnP)
              {
                  FreeUPNPUrls(&urls);
                  return;
              }
+             if (i % 600 == 0) // Refresh every 20 minutes
+             {
+ #ifndef UPNPDISCOVER_SUCCESS
+                 /* miniupnpc 1.5 */
+                 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
+                                     port, port, lanaddr, strDesc.c_str(), "TCP", 0);
+ #else
+                 /* miniupnpc 1.6 */
+                 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
+                                     port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
+ #endif
+                 if(r!=UPNPCOMMAND_SUCCESS)
+                     printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
+                         port, port, lanaddr, r, strupnperror(r));
+                 else
+                     printf("UPnP Port Mapping successful.\n");;
+             }
              Sleep(2000);
+             i++;
          }
      } else {
          printf("No valid UPnP IGDs found\n");
@@@ -1200,9 -951,8 +953,8 @@@ void MapPort(bool fMapPort
      if (fUseUPnP != fMapPort)
      {
          fUseUPnP = fMapPort;
-         WriteSetting("fUseUPnP", fUseUPnP);
      }
-     if (fUseUPnP && vnThreadsRunning[5] < 1)
+     if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1)
      {
          if (!CreateThread(ThreadMapPort, NULL))
              printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
@@@ -1223,10 -973,15 +975,14 @@@ void MapPort(bool /* unused fMapPort */
  
  
  
+ // DNS seeds
+ // Each pair gives a source name and a seed name.
+ // The first name is used as information source for addrman.
+ // The second name should resolve to a list of seed addresses.
 +// testnet dns seed begins with 't', all else are ppcoin dns seeds.
- static const char *strDNSSeed[] = {
-     "ppcseed.zapto.org",
-     "tncseed.zapto.org"
+ static const char *strDNSSeed[][2] = {
 -    {"xf2.org", "bitseed.xf2.org"},
 -    {"bluematt.me", "dnsseed.bluematt.me"},
 -    {"bitcoin.sipa.be", "seed.bitcoin.sipa.be"},
 -    {"dashjr.org", "dnsseed.bitcoin.dashjr.org"},
++    {"ppcseed", "ppcseed.zapto.org"},
++    {"tncseed", "tncseed.zapto.org"},
  };
  
  void ThreadDNSAddressSeed(void* parg)
      IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg));
      try
      {
-         vnThreadsRunning[6]++;
+         vnThreadsRunning[THREAD_DNSSEED]++;
          ThreadDNSAddressSeed2(parg);
-         vnThreadsRunning[6]--;
+         vnThreadsRunning[THREAD_DNSSEED]--;
      }
      catch (std::exception& e) {
-         vnThreadsRunning[6]--;
+         vnThreadsRunning[THREAD_DNSSEED]--;
          PrintException(&e, "ThreadDNSAddressSeed()");
      } catch (...) {
-         vnThreadsRunning[6]--;
+         vnThreadsRunning[THREAD_DNSSEED]--;
          throw; // support pthread_cancel()
      }
      printf("ThreadDNSAddressSeed exiting\n");
@@@ -1253,32 -1008,26 +1009,29 @@@ void ThreadDNSAddressSeed2(void* parg
      printf("ThreadDNSAddressSeed started\n");
      int found = 0;
  
 -    if (!fTestNet)
 +    if (true /*!fTestNet*/)  // ppcoin enables dns seeding with testnet too
      {
          printf("Loading addresses from DNS seeds (could take a while)\n");
-         CAddrDB addrDB;
-         addrDB.TxnBegin();
-         for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
-             if (fTestNet && strDNSSeed[seed_idx][0] != 't') continue;
-             if ((!fTestNet) && strDNSSeed[seed_idx][0] == 't') continue;
-  
-             vector<CAddress> vaddr;
-             if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true))
+         for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
++            if (fTestNet && strDNSSeed[seed_idx][1][0] != 't') continue;
++            if ((!fTestNet) && strDNSSeed[seed_idx][1][0] == 't') continue;
++
+             vector<CNetAddr> vaddr;
+             vector<CAddress> vAdd;
+             if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
              {
-                 BOOST_FOREACH (CAddress& addr, vaddr)
+                 BOOST_FOREACH(CNetAddr& ip, vaddr)
                  {
-                     if (addr.GetByte(3) != 127)
-                     {
-                         addr.nTime = 0;
-                         AddAddress(addr, 0, &addrDB);
-                         found++;
-                     }
+                     int nOneDay = 24*3600;
+                     CAddress addr = CAddress(CService(ip, GetDefaultPort()));
+                     addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
+                     vAdd.push_back(addr);
+                     found++;
                  }
              }
+             addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
          }
-         addrDB.TxnCommit();  // Save addresses (it's ok if this fails)
      }
  
      printf("%d addresses found from DNS seeds\n", found);
  
  unsigned int pnSeed[] =
  {
-     0xfc01a8c0
 -    0x959bd347, 0xf8de42b2, 0x73bc0518, 0xea6edc50, 0x21b00a4d, 0xc725b43d, 0xd665464d, 0x1a2a770e,
 -    0x27c93946, 0x65b2fa46, 0xb80ae255, 0x66b3b446, 0xb1877a3e, 0x6ee89e3e, 0xc3175b40, 0x2a01a83c,
 -    0x95b1363a, 0xa079ad3d, 0xe6ca801f, 0x027f4f4a, 0x34f7f03a, 0xf790f04a, 0x16ca801f, 0x2f4d5e40,
 -    0x3a4d5e40, 0xc43a322e, 0xc8159753, 0x14d4724c, 0x7919a118, 0xe0bdb34e, 0x68a16b2e, 0xff64b44d,
 -    0x6099115b, 0x9b57b05b, 0x7bd1b4ad, 0xdf95944f, 0x29d2b73d, 0xafa8db79, 0xe247ba41, 0x24078348,
 -    0xf722f03c, 0x33567ebc, 0xace64ed4, 0x984d3932, 0xb5f34e55, 0x27b7024d, 0x94579247, 0x8894042e,
 -    0x9357d34c, 0x1063c24b, 0xcaa228b1, 0xa3c5a8b2, 0x5dc64857, 0xa2c23643, 0xa8369a54, 0x31203077,
 -    0x00707c5c, 0x09fc0b3a, 0x272e9e2e, 0xf80f043e, 0x9449ca3e, 0x5512c33e, 0xd106b555, 0xe8024157,
 -    0xe288ec29, 0xc79c5461, 0xafb63932, 0xdb02ab4b, 0x0e512777, 0x8a145a4c, 0xb201ff4f, 0x5e09314b,
 -    0xcd9bfbcd, 0x1c023765, 0x4394e75c, 0xa728bd4d, 0x65331552, 0xa98420b1, 0x89ecf559, 0x6e80801f,
 -    0xf404f118, 0xefd62b51, 0x05918346, 0x9b186d5f, 0xacabab46, 0xf912e255, 0xc188ea62, 0xcc55734e,
 -    0xc668064d, 0xd77a4558, 0x46201c55, 0xf17dfc80, 0xf7142f2e, 0x87bfb718, 0x8aa54fb2, 0xc451d518,
 -    0xc4ae8831, 0x8dd44d55, 0x5bbd206c, 0x64536b5d, 0x5c667e60, 0x3b064242, 0xfe963a42, 0xa28e6dc8,
 -    0xe8a9604a, 0xc989464e, 0xd124a659, 0x50065140, 0xa44dfe5e, 0x1079e655, 0x3fb986d5, 0x47895b18,
 -    0x7d3ce4ad, 0x4561ba50, 0x296eec62, 0x255b41ad, 0xaed35ec9, 0x55556f12, 0xc7d3154d, 0x3297b65d,
 -    0x8930121f, 0xabf42e4e, 0x4a29e044, 0x1212685d, 0x676c1e40, 0xce009744, 0x383a8948, 0xa2dbd0ad,
 -    0xecc2564d, 0x07dbc252, 0x887ee24b, 0x5171644c, 0x6bb798c1, 0x847f495d, 0x4cbb7145, 0x3bb81c32,
 -    0x45eb262e, 0xc8015a4e, 0x250a361b, 0xf694f946, 0xd64a183e, 0xd4f1dd59, 0x8f20ffd4, 0x51d9e55c,
 -    0x09521763, 0x5e02002e, 0x32c8074d, 0xe685762e, 0x8290b0bc, 0x762a922e, 0xfc5ee754, 0x83a24829,
 -    0x775b224d, 0x6295bb4d, 0x38ec0555, 0xbffbba50, 0xe5560260, 0x86b16a7c, 0xd372234e, 0x49a3c24b,
 -    0x2f6a171f, 0x4d75ed60, 0xae94115b, 0xcb543744, 0x63080c59, 0x3f9c724c, 0xc977ce18, 0x532efb18,
 -    0x69dc3b2e, 0x5f94d929, 0x1732bb4d, 0x9c814b4d, 0xe6b3762e, 0xc024f662, 0x8face35b, 0x6b5b044d,
 -    0x798c7b57, 0x79a6b44c, 0x067d3057, 0xf9e94e5f, 0x91cbe15b, 0x71405eb2, 0x2662234e, 0xcbcc4a6d,
 -    0xbf69d54b, 0xa79b4e55, 0xec6d3e51, 0x7c0b3c02, 0x60f83653, 0x24c1e15c, 0x1110b62e, 0x10350f59,
 -    0xa56f1d55, 0x3509e7a9, 0xeb128354, 0x14268e2e, 0x934e28bc, 0x8e32692e, 0x8331a21f, 0x3e633932,
 -    0xc812b12e, 0xc684bf2e, 0x80112d2e, 0xe0ddc96c, 0xc630ca4a, 0x5c09b3b2, 0x0b580518, 0xc8e9d54b,
 -    0xd169aa43, 0x17d0d655, 0x1d029963, 0x7ff87559, 0xcb701f1f, 0x6fa3e85d, 0xe45e9a54, 0xf05d1802,
 -    0x44d03b2e, 0x837b692e, 0xccd4354e, 0x3d6da13c, 0x3423084d, 0xf707c34a, 0x55f6db3a, 0xad26e442,
 -    0x6233a21f, 0x09e80e59, 0x8caeb54d, 0xbe870941, 0xb407d20e, 0x20b51018, 0x56fb152e, 0x460d2a4e,
 -    0xbb9a2946, 0x560eb12e, 0xed83dd29, 0xd6724f53, 0xa50aafb8, 0x451346d9, 0x88348e2e, 0x7312fead,
 -    0x8ecaf96f, 0x1bda4e5f, 0xf1671e40, 0x3c8c3e3b, 0x4716324d, 0xdde24ede, 0xf98cd17d, 0xa91d4644,
 -    0x28124eb2, 0x147d5129, 0xd022042e, 0x61733d3b, 0xad0d5e02, 0x8ce2932e, 0xe5c18502, 0x549c1e32,
 -    0x9685801f, 0x86e217ad, 0xd948214b, 0x4110f462, 0x3a2e894e, 0xbd35492e, 0x87e0d558, 0x64b8ef7d,
 -    0x7c3eb962, 0x72a84b3e, 0x7cd667c9, 0x28370a2e, 0x4bc60e7b, 0x6fc1ec60, 0x14a6983f, 0x86739a4b,
 -    0x46954e5f, 0x32e2e15c, 0x2e9326cf, 0xe5801c5e, 0x379607b2, 0x32151145, 0xf0e39744, 0xacb54c55,
 -    0xa37dfb60, 0x83b55cc9, 0x388f7ca5, 0x15034f5f, 0x3e94965b, 0x68e0ffad, 0x35280f59, 0x8fe190cf,
 -    0x7c6ba5b2, 0xa5e9db43, 0x4ee1fc60, 0xd9d94e5f, 0x04040677, 0x0ea9b35e, 0x5961f14f, 0x67fda063,
 -    0xa48a5a31, 0xc6524e55, 0x283d325e, 0x3f37515f, 0x96b94b3e, 0xacce620e, 0x6481cc5b, 0xa4a06d4b,
 -    0x9e95d2d9, 0xe40c03d5, 0xc2f4514b, 0xb79aad44, 0xf64be843, 0xb2064070, 0xfca00455, 0x429dfa4e,
 -    0x2323f173, 0xeda4185e, 0xabd5227d, 0x9efd4d58, 0xb1104758, 0x4811e955, 0xbd9ab355, 0xe921f44b,
 -    0x9f166dce, 0x09e279b2, 0xe0c9ac7b, 0x7901a5ad, 0xa145d4b0, 0x79104671, 0xec31e35a, 0x4fe0b555,
 -    0xc7d9cbad, 0xad057f55, 0xe94cc759, 0x7fe0b043, 0xe4529f2e, 0x0d4dd4b2, 0x9f11a54d, 0x031e2e4e,
 -    0xe6014f5f, 0x11d1ca6c, 0x26bd7f61, 0xeb86854f, 0x4d347b57, 0x116bbe2e, 0xdba7234e, 0x7bcbfd2e,
 -    0x174dd4b2, 0x6686762e, 0xb089ba50, 0xc6258246, 0x087e767b, 0xc4a8cb4a, 0x595dba50, 0x7f0ae502,
 -    0x7b1dbd5a, 0xa0603492, 0x57d1af4b, 0x9e21ffd4, 0x6393064d, 0x7407376e, 0xe484762e, 0x122a4e53,
 -    0x4a37aa43, 0x3888a6be, 0xee77864e, 0x039c8dd5, 0x688d89af, 0x0e988f62, 0x08218246, 0xfc2f8246,
 -    0xd1d97040, 0xd64cd4b2, 0x5ae4a6b8, 0x7d0de9bc, 0x8d304d61, 0x06c5c672, 0xa4c8bd4d, 0xe0fd373b,
 -    0x575ebe4d, 0x72d26277, 0x55570f55, 0x77b154d9, 0xe214293a, 0xfc740f4b, 0xfe3f6a57, 0xa9c55f02,
 -    0xae4054db, 0x2394d918, 0xb511b24a, 0xb8741ab2, 0x0758e65e, 0xc7b5795b, 0xb0a30a4c, 0xaf7f170c,
 -    0xf3b4762e, 0x8179576d, 0x738a1581, 0x4b95b64c, 0x9829b618, 0x1bea932e, 0x7bdeaa4b, 0xcb5e0281,
 -    0x65618f54, 0x0658474b, 0x27066acf, 0x40556d65, 0x7d204d53, 0xf28bc244, 0xdce23455, 0xadc0ff54,
 -    0x3863c948, 0xcee34e5f, 0xdeb85e02, 0x2ed17a61, 0x6a7b094d, 0x7f0cfc40, 0x59603f54, 0x3220afbc,
 -    0xb5dfd962, 0x125d21c0, 0x13f8d243, 0xacfefb4e, 0x86c2c147, 0x3d8bbd59, 0xbd02a21f, 0x2593042e,
 -    0xc6a17a7c, 0x28925861, 0xb487ed44, 0xb5f4fd6d, 0x90c28a45, 0x5a14f74d, 0x43d71b4c, 0x728ebb5d,
 -    0x885bf950, 0x08134dd0, 0x38ec046e, 0xc575684b, 0x50082d2e, 0xa2f47757, 0x270f86ae, 0xf3ff6462,
 -    0x10ed3f4e, 0x4b58d462, 0xe01ce23e, 0x8c5b092e, 0x63e52f4e, 0x22c1e85d, 0xa908f54e, 0x8591624f,
 -    0x2c0fb94e, 0xa280ba3c, 0xb6f41b4c, 0x24f9aa47, 0x27201647, 0x3a3ea6dc, 0xa14fc3be, 0x3c34bdd5,
 -    0x5b8d4f5b, 0xaadeaf4b, 0xc71cab50, 0x15697a4c, 0x9a1a734c, 0x2a037d81, 0x2590bd59, 0x48ec2741,
 -    0x53489c5b, 0x7f00314b, 0x2170d362, 0xf2e92542, 0x42c10b44, 0x98f0f118, 0x883a3456, 0x099a932e,
 -    0xea38f7bc, 0x644e9247, 0xbb61b62e, 0x30e0863d, 0x5f51be54, 0x207215c7, 0x5f306c45, 0xaa7f3932,
 -    0x98da7d45, 0x4e339b59, 0x2e411581, 0xa808f618, 0xad2c0c59, 0x54476741, 0x09e99fd1, 0x5db8f752,
 -    0xc16df8bd, 0x1dd4b44f, 0x106edf2e, 0x9e15c180, 0x2ad6b56f, 0x633a5332, 0xff33787c, 0x077cb545,
 -    0x6610be6d, 0x75aad2c4, 0x72fb4d5b, 0xe81e0f59, 0x576f6332, 0x47333373, 0x351ed783, 0x2d90fb50,
 -    0x8d5e0f6c, 0x5b27a552, 0xdb293ebb, 0xe55ef950, 0x4b133ad8, 0x75df975a, 0x7b6a8740, 0xa899464b,
 -    0xfab15161, 0x10f8b64d, 0xd055ea4d, 0xee8e146b, 0x4b14afb8, 0x4bc1c44a, 0x9b961dcc, 0xd111ff43,
 -    0xfca0b745, 0xc800e412, 0x0afad9d1, 0xf751c350, 0xf9f0cccf, 0xa290a545, 0x8ef13763, 0x7ec70d59,
 -    0x2b066acf, 0x65496c45, 0xade02c1b, 0xae6eb077, 0x92c1e65b, 0xc064e6a9, 0xc649e56d, 0x5287a243,
 -    0x36de4f5b, 0x5b1df6ad, 0x65c39a59, 0xdba805b2, 0x20067aa8, 0x6457e56d, 0x3cee26cf, 0xfd3ff26d,
 -    0x04f86d4a, 0x06b8e048, 0xa93bcd5c, 0x91135852, 0xbe90a643, 0x8fa0094d, 0x06d8215f, 0x2677094d,
 -    0xd735685c, 0x164a00c9, 0x5209ac5f, 0xa9564c5c, 0x3b504f5f, 0xcc826bd0, 0x4615042e, 0x5fe13b4a,
 -    0x8c81b86d, 0x879ab68c, 0x1de564b8, 0x434487d8, 0x2dcb1b63, 0x82ab524a, 0xb0676abb, 0xa13d9c62,
 -    0xdbb5b86d, 0x5b7f4b59, 0xaddfb44d, 0xad773532, 0x3997054c, 0x72cebd89, 0xb194544c, 0xc5b8046e,
 -    0x6e1adeb2, 0xaa5abb51, 0xefb54b44, 0x15efc54f, 0xe9f1bc4d, 0x5f401b6c, 0x97f018ad, 0xc82f9252,
 -    0x2cdc762e, 0x8e52e56d, 0x1827175e, 0x9b7d7d80, 0xb2ad6845, 0x51065140, 0x71180a18, 0x5b27006c,
 -    0x0621e255, 0x721cbe58, 0x670c0cb8, 0xf8bd715d, 0xe0bdc5d9, 0xed843501, 0x4b84554d, 0x7f1a18bc,
 -    0x53bcaf47, 0x5729d35f, 0xf0dda246, 0x22382bd0, 0x4d641fb0, 0x316afcde, 0x50a22f1f, 0x73608046,
 -    0xc461d84a, 0xb2dbe247,
++    0xfc01a8c0,
  };
  
+ void DumpAddresses()
+ {
+     CAddrDB adb;
+     adb.WriteAddrman(addrman);
+ }
+ void ThreadDumpAddress2(void* parg)
+ {
+     vnThreadsRunning[THREAD_DUMPADDRESS]++;
+     while (!fShutdown)
+     {
+         DumpAddresses();
+         vnThreadsRunning[THREAD_DUMPADDRESS]--;
+         Sleep(100000);
+         vnThreadsRunning[THREAD_DUMPADDRESS]++;
+     }
+     vnThreadsRunning[THREAD_DUMPADDRESS]--;
+ }
  
+ void ThreadDumpAddress(void* parg)
+ {
+     IMPLEMENT_RANDOMIZE_STACK(ThreadDumpAddress(parg));
+     try
+     {
+         ThreadDumpAddress2(parg);
+     }
+     catch (std::exception& e) {
+         PrintException(&e, "ThreadDumpAddress()");
+     }
+     printf("ThreadDumpAddress exiting\n");
+ }
  
  void ThreadOpenConnections(void* parg)
  {
      IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
      try
      {
-         vnThreadsRunning[1]++;
+         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
          ThreadOpenConnections2(parg);
-         vnThreadsRunning[1]--;
+         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
      }
      catch (std::exception& e) {
-         vnThreadsRunning[1]--;
+         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
          PrintException(&e, "ThreadOpenConnections()");
      } catch (...) {
-         vnThreadsRunning[1]--;
+         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
          PrintException(NULL, "ThreadOpenConnections()");
      }
      printf("ThreadOpenConnections exiting\n");
@@@ -1332,9 -1187,9 +1115,9 @@@ void ThreadOpenConnections2(void* parg
          {
              BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
              {
-                 CAddress addr(strAddr, fAllowDNS);
+                 CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
                  if (addr.IsValid())
-                     OpenNetworkConnection(addr);
+                     OpenNetworkConnection(addr, false);
                  for (int i = 0; i < 10 && i < nLoop; i++)
                  {
                      Sleep(500);
          }
      }
  
-     // Connect to manually added nodes first
-     if (mapArgs.count("-addnode"))
-     {
-         BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
-         {
-             CAddress addr(strAddr, fAllowDNS);
-             if (addr.IsValid())
-             {
-                 OpenNetworkConnection(addr);
-                 Sleep(500);
-                 if (fShutdown)
-                     return;
-             }
-         }
-     }
      // Initiate network connections
      int64 nStart = GetTime();
      loop
      {
-         // Limit outbound connections
-         vnThreadsRunning[1]--;
+         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
          Sleep(500);
-         loop
-         {
-             int nOutbound = 0;
-             CRITICAL_BLOCK(cs_vNodes)
-                 BOOST_FOREACH(CNode* pnode, vNodes)
-                     if (!pnode->fInbound)
-                         nOutbound++;
-             int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
-             nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125));
-             if (nOutbound < nMaxOutboundConnections)
-                 break;
-             Sleep(2000);
-             if (fShutdown)
-                 return;
-         }
-         vnThreadsRunning[1]++;
+         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
          if (fShutdown)
              return;
  
-         CRITICAL_BLOCK(cs_mapAddresses)
+         vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
+         semOutbound->wait();
+         vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
+         if (fShutdown)
+             return;
+         // Add seed nodes if IRC isn't working
+         bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
+         if (addrman.size()==0 && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
          {
-             // Add seed nodes if IRC isn't working
-             bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
-             if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
+             std::vector<CAddress> vAdd;
+             for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
              {
-                 for (int i = 0; i < ARRAYLEN(pnSeed); i++)
-                 {
-                     // It'll only connect to one or two seed nodes because once it connects,
-                     // it'll get a pile of addresses with newer timestamps.
-                     // Seed nodes are given a random 'last seen time' of between one and two
-                     // weeks ago.
-                     const int64 nOneWeek = 7*24*60*60;
-                     CAddress addr;
-                     addr.ip = pnSeed[i];
-                     addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
-                     AddAddress(addr);
-                 }
+                 // It'll only connect to one or two seed nodes because once it connects,
+                 // it'll get a pile of addresses with newer timestamps.
+                 // Seed nodes are given a random 'last seen time' of between one and two
+                 // weeks ago.
+                 const int64 nOneWeek = 7*24*60*60;
+                 struct in_addr ip;
+                 memcpy(&ip, &pnSeed[i], sizeof(ip));
+                 CAddress addr(CService(ip, GetDefaultPort()));
+                 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
+                 vAdd.push_back(addr);
              }
+             addrman.Add(vAdd, CNetAddr("127.0.0.1"));
          }
  
          //
          // Choose an address to connect to based on most recently seen
          //
          CAddress addrConnect;
  
          // Only connect to one address per a.b.?.? range.
          // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
-         set<unsigned int> setConnected;
-         CRITICAL_BLOCK(cs_vNodes)
-             BOOST_FOREACH(CNode* pnode, vNodes)
-                 setConnected.insert(pnode->addr.ip & 0x0000ffff);
+         int nOutbound = 0;
+         set<vector<unsigned char> > setConnected;
+         {
+             LOCK(cs_vNodes);
+             BOOST_FOREACH(CNode* pnode, vNodes) {
+                 setConnected.insert(pnode->addr.GetGroup());
+                 if (!pnode->fInbound)
+                     nOutbound++;
+             }
+         }
  
          int64 nANow = GetAdjustedTime();
  
-         CRITICAL_BLOCK(cs_mapAddresses)
+         int nTries = 0;
+         loop
          {
-             BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
-             {
-                 const CAddress& addr = item.second;
-                 if (addr.ip == addrLocalHost.ip || !addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
-                     continue;
-                 int64 nSinceLastSeen = nANow - addr.nTime;
-                 int64 nSinceLastTry = nANow - addr.nLastTry;
-                 // Randomize the order in a deterministic way, putting the standard port first
-                 int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
-                 if (addr.port != htons(GetDefaultPort()))
-                     nRandomizer += 2 * 60 * 60;
-                 // Last seen  Base retry frequency
-                 //   <1 hour   10 min
-                 //    1 hour    1 hour
-                 //    4 hours   2 hours
-                 //   24 hours   5 hours
-                 //   48 hours   7 hours
-                 //    7 days   13 hours
-                 //   30 days   27 hours
-                 //   90 days   46 hours
-                 //  365 days   93 hours
-                 int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
-                 // Fast reconnect for one hour after last seen
-                 if (nSinceLastSeen < 60 * 60)
-                     nDelay = 10 * 60;
-                 // Limit retry frequency
-                 if (nSinceLastTry < nDelay)
-                     continue;
+             // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
+             CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
  
-                 // If we have IRC, we'll be notified when they first come online,
-                 // and again every 24 hours by the refresh broadcast.
-                 if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
-                     continue;
+             // if we selected an invalid address, restart
+             if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || addr == addrLocalHost)
+                 break;
  
-                 // Only try the old stuff if we don't have enough connections
-                 if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
-                     continue;
+             nTries++;
  
-                 // If multiple addresses are ready, prioritize by time since
-                 // last seen and time since last tried.
-                 int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
-                 if (nScore > nBest)
-                 {
-                     nBest = nScore;
-                     addrConnect = addr;
-                 }
-             }
+             // only consider very recently tried nodes after 30 failed attempts
+             if (nANow - addr.nLastTry < 600 && nTries < 30)
+                 continue;
+             // do not allow non-default ports, unless after 50 invalid addresses selected already
+             if (addr.GetPort() != GetDefaultPort() && nTries < 50)
+                 continue;
+             addrConnect = addr;
+             break;
          }
  
          if (addrConnect.IsValid())
              OpenNetworkConnection(addrConnect);
+         else
+             semOutbound->post();
+     }
+ }
+ void ThreadOpenAddedConnections(void* parg)
+ {
+     IMPLEMENT_RANDOMIZE_STACK(ThreadOpenAddedConnections(parg));
+     try
+     {
+         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
+         ThreadOpenAddedConnections2(parg);
+         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
+     }
+     catch (std::exception& e) {
+         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
+         PrintException(&e, "ThreadOpenAddedConnections()");
+     } catch (...) {
+         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
+         PrintException(NULL, "ThreadOpenAddedConnections()");
+     }
+     printf("ThreadOpenAddedConnections exiting\n");
+ }
+ void ThreadOpenAddedConnections2(void* parg)
+ {
+     printf("ThreadOpenAddedConnections started\n");
+     if (mapArgs.count("-addnode") == 0)
+         return;
+     vector<vector<CService> > vservAddressesToAdd(0);
+     BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"])
+     {
+         vector<CService> vservNode(0);
+         if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0))
+         {
+             vservAddressesToAdd.push_back(vservNode);
+             {
+                 LOCK(cs_setservAddNodeAddresses);
+                 BOOST_FOREACH(CService& serv, vservNode)
+                     setservAddNodeAddresses.insert(serv);
+             }
+         }
+     }
+     loop
+     {
+         vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd;
+         // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
+         // (keeping in mind that addnode entries can have many IPs if fAllowDNS)
+         {
+             LOCK(cs_vNodes);
+             BOOST_FOREACH(CNode* pnode, vNodes)
+                 for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
+                     BOOST_FOREACH(CService& addrNode, *(it))
+                         if (pnode->addr == addrNode)
+                         {
+                             it = vservConnectAddresses.erase(it);
+                             it--;
+                             break;
+                         }
+         }
+         BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
+         {
+             semOutbound->wait();
+             OpenNetworkConnection(CAddress(*(vserv.begin())));
+             Sleep(500);
+             if (fShutdown)
+                 return;
+         }
+         if (fShutdown)
+             return;
+         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
+         Sleep(120000); // Retry every 2 minutes
+         vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
+         if (fShutdown)
+             return;
      }
  }
  
- bool OpenNetworkConnection(const CAddress& addrConnect)
+ bool static ReleaseGrant(bool fUseGrant) {
+     if (fUseGrant)
+         semOutbound->post();
+     return false;
+ }
+ // only call this function when semOutbound has been waited for
+ bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant)
  {
      //
      // Initiate outbound network connection
      //
      if (fShutdown)
          return false;
-     if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
-         FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
-         return false;
+     if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
+         FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
+         return ReleaseGrant(fUseGrant);
  
-     vnThreadsRunning[1]--;
+     vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
      CNode* pnode = ConnectNode(addrConnect);
-     vnThreadsRunning[1]++;
+     vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
      if (fShutdown)
          return false;
      if (!pnode)
-         return false;
+         return ReleaseGrant(fUseGrant);
+     if (pnode->fHasGrant) {
+         // node already has connection grant, release the one that was passed to us
+         ReleaseGrant(fUseGrant);
+     } else {
+         pnode->fHasGrant = fUseGrant;
+     }
      pnode->fNetworkNode = true;
  
      return true;
@@@ -1519,15 -1412,15 +1340,15 @@@ void ThreadMessageHandler(void* parg
      IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
      try
      {
-         vnThreadsRunning[2]++;
+         vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
          ThreadMessageHandler2(parg);
-         vnThreadsRunning[2]--;
+         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
      }
      catch (std::exception& e) {
-         vnThreadsRunning[2]--;
+         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
          PrintException(&e, "ThreadMessageHandler()");
      } catch (...) {
-         vnThreadsRunning[2]--;
+         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
          PrintException(NULL, "ThreadMessageHandler()");
      }
      printf("ThreadMessageHandler exiting\n");
@@@ -1540,8 -1433,8 +1361,8 @@@ void ThreadMessageHandler2(void* parg
      while (!fShutdown)
      {
          vector<CNode*> vNodesCopy;
-         CRITICAL_BLOCK(cs_vNodes)
          {
+             LOCK(cs_vNodes);
              vNodesCopy = vNodes;
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                  pnode->AddRef();
          BOOST_FOREACH(CNode* pnode, vNodesCopy)
          {
              // Receive messages
-             TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
-                 ProcessMessages(pnode);
+             {
+                 TRY_LOCK(pnode->cs_vRecv, lockRecv);
+                 if (lockRecv)
+                     ProcessMessages(pnode);
+             }
              if (fShutdown)
                  return;
  
              // Send messages
-             TRY_CRITICAL_BLOCK(pnode->cs_vSend)
-                 SendMessages(pnode, pnode == pnodeTrickle);
+             {
+                 TRY_LOCK(pnode->cs_vSend, lockSend);
+                 if (lockSend)
+                     SendMessages(pnode, pnode == pnodeTrickle);
+             }
              if (fShutdown)
                  return;
          }
  
-         CRITICAL_BLOCK(cs_vNodes)
          {
+             LOCK(cs_vNodes);
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                  pnode->Release();
          }
          // Wait and allow messages to bunch up.
          // Reduce vnThreadsRunning so StopNode has permission to exit while
          // we're sleeping, but we must always check fShutdown after doing this.
-         vnThreadsRunning[2]--;
+         vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
          Sleep(100);
          if (fRequestShutdown)
-             Shutdown(NULL);
-         vnThreadsRunning[2]++;
+             StartShutdown();
+         vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
          if (fShutdown)
              return;
      }
@@@ -1594,7 -1493,7 +1421,7 @@@ bool BindListenPort(string& strError
  {
      strError = "";
      int nOne = 1;
-     addrLocalHost.port = htons(GetListenPort());
+     addrLocalHost.SetPort(GetListenPort());
  
  #ifdef WIN32
      // Initialize Windows Sockets
  
  void StartNode(void* parg)
  {
+     if (semOutbound == NULL) {
+         // initialize semaphore
+         int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
+         semOutbound = new CSemaphore(nMaxOutbound);
+     }
+ #ifdef USE_UPNP
+ #if USE_UPNP
+     fUseUPnP = GetBoolArg("-upnp", true);
+ #else
+     fUseUPnP = GetBoolArg("-upnp", false);
+ #endif
+ #endif
      if (pnodeLocalHost == NULL)
-         pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
+         pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
  
  #ifdef WIN32
      // Get local host ip
      char pszHostName[1000] = "";
      if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
      {
-         vector<CAddress> vaddr;
-         if (Lookup(pszHostName, vaddr, nLocalServices, -1, true))
-             BOOST_FOREACH (const CAddress &addr, vaddr)
-                 if (addr.GetByte(3) != 127)
+         vector<CNetAddr> vaddr;
+         if (LookupHost(pszHostName, vaddr))
+         {
+             BOOST_FOREACH (const CNetAddr &addr, vaddr)
+             {
+                 if (!addr.IsLocal())
                  {
-                     addrLocalHost = addr;
+                     addrLocalHost.SetIP(addr);
                      break;
                  }
+             }
+         }
      }
  #else
      // Get local host ip
                      printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
  
                  // Take the first IP that isn't loopback 127.x.x.x
-                 CAddress addr(*(unsigned int*)&s4->sin_addr, GetListenPort(), nLocalServices);
-                 if (addr.IsValid() && addr.GetByte(3) != 127)
+                 CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices);
+                 if (addr.IsValid() && !addr.IsLocal())
                  {
                      addrLocalHost = addr;
                      break;
      if (fUseProxy || mapArgs.count("-connect") || fNoListen)
      {
          // Proxies can't take incoming connections
-         addrLocalHost.ip = CAddress("0.0.0.0").ip;
+         addrLocalHost.SetIP(CNetAddr("0.0.0.0"));
          printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
      }
      else
      // Start threads
      //
  
-     if (GetBoolArg("-nodnsseed"))
+     if (!GetBoolArg("-dnsseed", true))
          printf("DNS seeding disabled\n");
      else
          if (!CreateThread(ThreadDNSAddressSeed, NULL))
          MapPort(fUseUPnP);
  
      // Get addresses from IRC and advertise ours
 -    if (!CreateThread(ThreadIRCSeed, NULL))
 -        printf("Error: CreateThread(ThreadIRCSeed) failed\n");
 +    // if (!CreateThread(ThreadIRCSeed, NULL))
 +    //     printf("Error: CreateThread(ThreadIRCSeed) failed\n");
 +    // IRC disabled with ppcoin
 +    printf("IRC seeding/communication disabled\n");
  
      // Send and receive from sockets, accept connections
      if (!CreateThread(ThreadSocketHandler, NULL))
          printf("Error: CreateThread(ThreadSocketHandler) failed\n");
  
+     // Initiate outbound connections from -addnode
+     if (!CreateThread(ThreadOpenAddedConnections, NULL))
+         printf("Error: CreateThread(ThreadOpenAddedConnections) failed\n");
      // Initiate outbound connections
      if (!CreateThread(ThreadOpenConnections, NULL))
          printf("Error: CreateThread(ThreadOpenConnections) failed\n");
      if (!CreateThread(ThreadMessageHandler, NULL))
          printf("Error: CreateThread(ThreadMessageHandler) failed\n");
  
+     // Dump network addresses
+     if (!CreateThread(ThreadDumpAddress, NULL))
+         printf("Error; CreateThread(ThreadDumpAddress) failed\n");
      // Generate coins in the background
-     GenerateBitcoins(fGenerateBitcoins, pwalletMain);
+     GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain);
  }
  
  bool StopNode()
      fShutdown = true;
      nTransactionsUpdated++;
      int64 nStart = GetTime();
-     while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0
- #ifdef USE_UPNP
-         || vnThreadsRunning[5] > 0
- #endif
-     )
+     if (semOutbound)
+         for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
+             semOutbound->post();
+     do
      {
+         int nThreadsRunning = 0;
+         for (int n = 0; n < THREAD_MAX; n++)
+             nThreadsRunning += vnThreadsRunning[n];
+         if (nThreadsRunning == 0)
+             break;
          if (GetTime() - nStart > 20)
              break;
          Sleep(20);
-     }
-     if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
-     if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
-     if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
-     if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
-     if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
-     if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n");
-     if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n");
-     while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
+     } while(true);
+     if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
+     if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
+     if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
+     if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n");
+     if (vnThreadsRunning[THREAD_RPCSERVER] > 0) printf("ThreadRPCServer still running\n");
+     if (fHaveUPnP && vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
+     if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
+     if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
+     if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
+     while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCSERVER] > 0)
          Sleep(20);
      Sleep(50);
+     DumpAddresses();
      return true;
  }
  
diff --combined src/net.h
+++ b/src/net.h
@@@ -1,8 -1,7 +1,8 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_NET_H
  #define BITCOIN_NET_H
  
  #include <arpa/inet.h>
  #endif
  
+ #include "mruset.h"
+ #include "netbase.h"
  #include "protocol.h"
+ #include "addrman.h"
  
  class CAddrDB;
  class CRequestTracker;
  class CNode;
  class CBlockIndex;
  extern int nBestHeight;
- extern int nConnectTimeout;
  
  
  
  inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
  inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
- static const unsigned int PUBLISH_HOPS = 5;
- bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout);
- bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
- bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
- bool GetMyExternalIP(unsigned int& ipRet);
- bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
- void AddressCurrentlyConnected(const CAddress& addr);
- CNode* FindNode(unsigned int ip);
+ bool RecvLine(SOCKET hSocket, std::string& strLine);
+ bool GetMyExternalIP(CNetAddr& ipRet);
+ void AddressCurrentlyConnected(const CService& addr);
+ CNode* FindNode(const CNetAddr& ip);
+ CNode* FindNode(const CService& ip);
  CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
- void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
- bool AnySubscribed(unsigned int nChannel);
  void MapPort(bool fMapPort);
  bool BindListenPort(std::string& strError=REF(std::string()));
  void StartNode(void* parg);
@@@ -70,35 -66,43 +67,44 @@@ public
  };
  
  
+ /** Thread types */
+ enum threadId
+ {
+     THREAD_SOCKETHANDLER,
+     THREAD_OPENCONNECTIONS,
+     THREAD_MESSAGEHANDLER,
+     THREAD_MINER,
+     THREAD_RPCSERVER,
+     THREAD_UPNP,
+     THREAD_DNSSEED,
+     THREAD_ADDEDCONNECTIONS,
+     THREAD_DUMPADDRESS,
+     THREAD_MAX
+ };
  
  extern bool fClient;
  extern bool fAllowDNS;
  extern uint64 nLocalServices;
  extern CAddress addrLocalHost;
 +extern CAddress addrSeenByPeer;
  extern uint64 nLocalHostNonce;
- extern boost::array<int, 10> vnThreadsRunning;
+ extern boost::array<int, THREAD_MAX> vnThreadsRunning;
+ extern CAddrMan addrman;
  
  extern std::vector<CNode*> vNodes;
  extern CCriticalSection cs_vNodes;
- extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
- extern CCriticalSection cs_mapAddresses;
  extern std::map<CInv, CDataStream> mapRelay;
  extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
  extern CCriticalSection cs_mapRelay;
  extern std::map<CInv, int64> mapAlreadyAskedFor;
  
- // Settings
- extern int fUseProxy;
- extern CAddress addrProxy;
  
  
  
  
  
+ /** Information about a peer */
  class CNode
  {
  public:
      int64 nLastRecv;
      int64 nLastSendEmpty;
      int64 nTimeConnected;
-     unsigned int nHeaderStart;
+     int nHeaderStart;
      unsigned int nMessageStart;
      CAddress addr;
      int nVersion;
      bool fNetworkNode;
      bool fSuccessfullyConnected;
      bool fDisconnect;
+     bool fHasGrant; // whether to call semOutbound.post() at disconnect
  protected:
      int nRefCount;
  
      // Denial-of-service detection/prevention
      // Key is ip address, value is banned-until-time
-     static std::map<unsigned int, int64> setBanned;
+     static std::map<CNetAddr, int64> setBanned;
      static CCriticalSection cs_setBanned;
      int nMisbehavior;
  
@@@ -146,31 -151,17 +153,18 @@@ public
      std::set<CAddress> setAddrKnown;
      bool fGetAddr;
      std::set<uint256> setKnown;
 +    uint256 hashCheckpointKnown; // ppcoin: known sent sync-checkpoint
  
      // inventory based relay
-     std::set<CInv> setInventoryKnown;
+     mruset<CInv> setInventoryKnown;
      std::vector<CInv> vInventoryToSend;
      CCriticalSection cs_inventory;
      std::multimap<int64, CInv> mapAskFor;
  
-     // publish and subscription
-     std::vector<char> vfSubscribe;
-     CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
+     CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION)
      {
          nServices = 0;
          hSocket = hSocketIn;
-         vSend.SetType(SER_NETWORK);
-         vSend.SetVersion(0);
-         vRecv.SetType(SER_NETWORK);
-         vRecv.SetVersion(0);
-         // Version 0.2 obsoletes 20 Feb 2012
-         if (GetTime() > 1329696000)
-         {
-             vSend.SetVersion(209);
-             vRecv.SetVersion(209);
-         }
          nLastSend = 0;
          nLastRecv = 0;
          nLastSendEmpty = GetTime();
          nVersion = 0;
          strSubVer = "";
          fClient = false; // set by version message
+         fHasGrant = false;
          fInbound = fInboundIn;
          fNetworkNode = false;
          fSuccessfullyConnected = false;
          hashLastGetBlocksEnd = 0;
          nStartingHeight = -1;
          fGetAddr = false;
-         vfSubscribe.assign(256, false);
          nMisbehavior = 0;
 +        hashCheckpointKnown = 0;
+         setInventoryKnown.max_size(SendBufferSize() / 1000);
  
          // Be shy and don't send version until we hear
          if (!fInbound)
@@@ -254,15 -245,19 +249,19 @@@ public
  
      void AddInventoryKnown(const CInv& inv)
      {
-         CRITICAL_BLOCK(cs_inventory)
+         {
+             LOCK(cs_inventory);
              setInventoryKnown.insert(inv);
+         }
      }
  
      void PushInventory(const CInv& inv)
      {
-         CRITICAL_BLOCK(cs_inventory)
+         {
+             LOCK(cs_inventory);
              if (!setInventoryKnown.count(inv))
                  vInventoryToSend.push_back(inv);
+         }
      }
  
      void AskFor(const CInv& inv)
          // Make sure not to reuse time indexes to keep things in the same order
          int64 nNow = (GetTime() - 1) * 1000000;
          static int64 nLastTime;
-         nLastTime = nNow = std::max(nNow, ++nLastTime);
+         ++nLastTime;
+         nNow = std::max(nNow, nLastTime);
+         nLastTime = nNow;
  
          // Each retry is 2 minutes after the last
          nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
  
      void BeginMessage(const char* pszCommand)
      {
-         cs_vSend.Enter("cs_vSend", __FILE__, __LINE__);
+         ENTER_CRITICAL_SECTION(cs_vSend);
          if (nHeaderStart != -1)
              AbortMessage();
          nHeaderStart = vSend.size();
  
      void AbortMessage()
      {
-         if (nHeaderStart == -1)
+         if (nHeaderStart < 0)
              return;
          vSend.resize(nHeaderStart);
          nHeaderStart = -1;
          nMessageStart = -1;
-         cs_vSend.Leave();
+         LEAVE_CRITICAL_SECTION(cs_vSend);
  
          if (fDebug)
              printf("(aborted)\n");
              return;
          }
  
-         if (nHeaderStart == -1)
+         if (nHeaderStart < 0)
              return;
  
          // Set the size
          memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
  
          // Set the checksum
-         if (vSend.GetVersion() >= 209)
-         {
-             uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
-             unsigned int nChecksum = 0;
-             memcpy(&nChecksum, &hash, sizeof(nChecksum));
-             assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
-             memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
-         }
+         uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
+         unsigned int nChecksum = 0;
+         memcpy(&nChecksum, &hash, sizeof(nChecksum));
+         assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
+         memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
  
          if (fDebug) {
              printf("(%d bytes)\n", nSize);
  
          nHeaderStart = -1;
          nMessageStart = -1;
-         cs_vSend.Leave();
+         LEAVE_CRITICAL_SECTION(cs_vSend);
      }
  
      void EndMessageAbortIfEmpty()
      {
-         if (nHeaderStart == -1)
+         if (nHeaderStart < 0)
              return;
          int nSize = vSend.size() - nMessageStart;
          if (nSize > 0)
  
  
  
-     void PushVersion()
-     {
-         /// when NTP implemented, change to just nTime = GetAdjustedTime()
-         int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
-         CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
-         CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
-         RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
-         PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
-                     nLocalHostNonce, std::string(pszSubVer), nBestHeight);
-     }
+     void PushVersion();
  
  
      void PushMessage(const char* pszCommand)
          uint256 hashReply;
          RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
  
-         CRITICAL_BLOCK(cs_mapRequests)
+         {
+             LOCK(cs_mapRequests);
              mapRequests[hashReply] = CRequestTracker(fn, param1);
+         }
  
          PushMessage(pszCommand, hashReply);
      }
          uint256 hashReply;
          RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
  
-         CRITICAL_BLOCK(cs_mapRequests)
+         {
+             LOCK(cs_mapRequests);
              mapRequests[hashReply] = CRequestTracker(fn, param1);
+         }
  
          PushMessage(pszCommand, hashReply, a1);
      }
          uint256 hashReply;
          RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
  
-         CRITICAL_BLOCK(cs_mapRequests)
+         {
+             LOCK(cs_mapRequests);
              mapRequests[hashReply] = CRequestTracker(fn, param1);
+         }
  
          PushMessage(pszCommand, hashReply, a1, a2);
      }
      // between nodes running old code and nodes running
      // new code.
      static void ClearBanned(); // needed for unit testing
-     static bool IsBanned(unsigned int ip);
+     static bool IsBanned(CNetAddr ip);
      bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
  };
  
  inline void RelayInventory(const CInv& inv)
  {
      // Put on lists to offer to the other nodes
-     CRITICAL_BLOCK(cs_vNodes)
+     {
+         LOCK(cs_vNodes);
          BOOST_FOREACH(CNode* pnode, vNodes)
              pnode->PushInventory(inv);
+     }
  }
  
  template<typename T>
  void RelayMessage(const CInv& inv, const T& a)
  {
-     CDataStream ss(SER_NETWORK);
+     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
      ss.reserve(10000);
      ss << a;
      RelayMessage(inv, ss);
  template<>
  inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
  {
-     CRITICAL_BLOCK(cs_mapRelay)
      {
+         LOCK(cs_mapRelay);
          // Expire old relay messages
          while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
          {
          }
  
          // Save original serialized message so newer versions are preserved
-         mapRelay[inv] = ss;
+         mapRelay.insert(std::make_pair(inv, ss));
          vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
      }
  
  }
  
  
- //
- // Templates for the publish and subscription system.
- // The object being published as T& obj needs to have:
- //   a set<unsigned int> setSources member
- //   specializations of AdvertInsert and AdvertErase
- // Currently implemented for CTable and CProduct.
- //
- template<typename T>
- void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
- {
-     // Add to sources
-     obj.setSources.insert(pfrom->addr.ip);
-     if (!AdvertInsert(obj))
-         return;
-     // Relay
-     CRITICAL_BLOCK(cs_vNodes)
-         BOOST_FOREACH(CNode* pnode, vNodes)
-             if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
-                 pnode->PushMessage("publish", nChannel, nHops, obj);
- }
- template<typename T>
- void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
- {
-     uint256 hash = obj.GetHash();
-     CRITICAL_BLOCK(cs_vNodes)
-         BOOST_FOREACH(CNode* pnode, vNodes)
-             if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
-                 pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
-     AdvertErase(obj);
- }
- template<typename T>
- void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
- {
-     // Remove a source
-     obj.setSources.erase(pfrom->addr.ip);
-     // If no longer supported by any sources, cancel it
-     if (obj.setSources.empty())
-         AdvertStopPublish(pfrom, nChannel, nHops, obj);
- }
  #endif
diff --combined src/protocol.h
@@@ -1,7 -1,7 +1,7 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #ifndef __cplusplus
  # error This header can only be compiled as C++.
  #define __INCLUDED_PROTOCOL_H__
  
  #include "serialize.h"
+ #include "netbase.h"
  #include <string>
  #include "uint256.h"
  
 +#define PPCOIN_PORT  9901
 +#define RPC_PORT     9902
 +#define TESTNET_PORT 9903
 +
  extern bool fTestNet;
 +
  static inline unsigned short GetDefaultPort(const bool testnet = fTestNet)
  {
 -    return testnet ? 18333 : 8333;
 +    return testnet ? TESTNET_PORT : PPCOIN_PORT;
  }
  
  
  extern unsigned char pchMessageStart[4];
  
+ /** Message header.
+  * (4) message start.
+  * (12) command.
+  * (4) size.
+  * (4) checksum.
+  */
  class CMessageHeader
  {
      public:
@@@ -48,7 -44,6 +49,6 @@@
               READWRITE(FLATDATA(pchMessageStart));
               READWRITE(FLATDATA(pchCommand));
               READWRITE(nMessageSize);
-              if (nVersion >= 209)
               READWRITE(nChecksum);
              )
  
          unsigned int nChecksum;
  };
  
+ /** nServices flags */
  enum
  {
      NODE_NETWORK = (1 << 0),
  };
  
- class CAddress
+ /** A CService with information about it as peer */
+ class CAddress : public CService
  {
      public:
          CAddress();
-         CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK);
-         explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK);
-         explicit CAddress(const char* pszIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
-         explicit CAddress(const char* pszIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
-         explicit CAddress(std::string strIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
-         explicit CAddress(std::string strIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
+         explicit CAddress(CService ipIn, uint64 nServicesIn=NODE_NETWORK);
  
          void Init();
  
          IMPLEMENT_SERIALIZE
              (
+              CAddress* pthis = const_cast<CAddress*>(this);
+              CService* pip = (CService*)pthis;
               if (fRead)
-              const_cast<CAddress*>(this)->Init();
+                  pthis->Init();
               if (nType & SER_DISK)
-              READWRITE(nVersion);
-              if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
-              READWRITE(nTime);
+                  READWRITE(nVersion);
+              if ((nType & SER_DISK) ||
+                  (nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH)))
+                  READWRITE(nTime);
               READWRITE(nServices);
-              READWRITE(FLATDATA(pchReserved)); // for IPv6
-              READWRITE(ip);
-              READWRITE(port);
+              READWRITE(*pip);
              )
  
-         friend bool operator==(const CAddress& a, const CAddress& b);
-         friend bool operator!=(const CAddress& a, const CAddress& b);
-         friend bool operator<(const CAddress& a, const CAddress& b);
-         std::vector<unsigned char> GetKey() const;
-         struct sockaddr_in GetSockAddr() const;
-         bool IsIPv4() const;
-         bool IsRFC1918() const;
-         bool IsRFC3927() const;
-         bool IsLocal() const;
-         bool IsRoutable() const;
-         bool IsValid() const;
-         unsigned char GetByte(int n) const;
-         std::string ToStringIPPort() const;
-         std::string ToStringIP() const;
-         std::string ToStringPort() const;
-         std::string ToString() const;
          void print() const;
  
      // TODO: make private (improves encapsulation)
      public:
          uint64 nServices;
-         unsigned char pchReserved[12];
-         unsigned int ip;
-         unsigned short port;
  
          // disk and network only
          unsigned int nTime;
  
          // memory only
-         unsigned int nLastTry;
+         int64 nLastTry;
  };
  
+ /** inv message data */
  class CInv
  {
      public:
diff --combined src/script.cpp
@@@ -1,17 -1,25 +1,25 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011-2012 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
++// Copyright (c) 2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
- #include "headers.h"
- #include "script.h"
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
+ #include <boost/foreach.hpp>
+ #include <boost/tuple/tuple.hpp>
  
  using namespace std;
  using namespace boost;
  
+ #include "script.h"
+ #include "keystore.h"
+ #include "bignum.h"
+ #include "key.h"
+ #include "main.h"
+ #include "util.h"
  bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
  
  
  
 -typedef vector<unsigned char> valtype;
  static const valtype vchFalse(0);
  static const valtype vchZero(0);
  static const valtype vchTrue(1, 1);
@@@ -32,7 -40,7 +40,7 @@@ CBigNum CastToBigNum(const valtype& vch
  
  bool CastToBool(const valtype& vch)
  {
-     for (int i = 0; i < vch.size(); i++)
+     for (unsigned int i = 0; i < vch.size(); i++)
      {
          if (vch[i] != 0)
          {
@@@ -70,6 -78,163 +78,163 @@@ static inline void popstack(vector<valt
  }
  
  
+ const char* GetTxnOutputType(txnouttype t)
+ {
+     switch (t)
+     {
+     case TX_NONSTANDARD: return "nonstandard";
+     case TX_PUBKEY: return "pubkey";
+     case TX_PUBKEYHASH: return "pubkeyhash";
+     case TX_SCRIPTHASH: return "scripthash";
+     case TX_MULTISIG: return "multisig";
+     }
+     return NULL;
+ }
+ const char* GetOpName(opcodetype opcode)
+ {
+     switch (opcode)
+     {
+     // push value
+     case OP_0                      : return "0";
+     case OP_PUSHDATA1              : return "OP_PUSHDATA1";
+     case OP_PUSHDATA2              : return "OP_PUSHDATA2";
+     case OP_PUSHDATA4              : return "OP_PUSHDATA4";
+     case OP_1NEGATE                : return "-1";
+     case OP_RESERVED               : return "OP_RESERVED";
+     case OP_1                      : return "1";
+     case OP_2                      : return "2";
+     case OP_3                      : return "3";
+     case OP_4                      : return "4";
+     case OP_5                      : return "5";
+     case OP_6                      : return "6";
+     case OP_7                      : return "7";
+     case OP_8                      : return "8";
+     case OP_9                      : return "9";
+     case OP_10                     : return "10";
+     case OP_11                     : return "11";
+     case OP_12                     : return "12";
+     case OP_13                     : return "13";
+     case OP_14                     : return "14";
+     case OP_15                     : return "15";
+     case OP_16                     : return "16";
+     // control
+     case OP_NOP                    : return "OP_NOP";
+     case OP_VER                    : return "OP_VER";
+     case OP_IF                     : return "OP_IF";
+     case OP_NOTIF                  : return "OP_NOTIF";
+     case OP_VERIF                  : return "OP_VERIF";
+     case OP_VERNOTIF               : return "OP_VERNOTIF";
+     case OP_ELSE                   : return "OP_ELSE";
+     case OP_ENDIF                  : return "OP_ENDIF";
+     case OP_VERIFY                 : return "OP_VERIFY";
+     case OP_RETURN                 : return "OP_RETURN";
+     // stack ops
+     case OP_TOALTSTACK             : return "OP_TOALTSTACK";
+     case OP_FROMALTSTACK           : return "OP_FROMALTSTACK";
+     case OP_2DROP                  : return "OP_2DROP";
+     case OP_2DUP                   : return "OP_2DUP";
+     case OP_3DUP                   : return "OP_3DUP";
+     case OP_2OVER                  : return "OP_2OVER";
+     case OP_2ROT                   : return "OP_2ROT";
+     case OP_2SWAP                  : return "OP_2SWAP";
+     case OP_IFDUP                  : return "OP_IFDUP";
+     case OP_DEPTH                  : return "OP_DEPTH";
+     case OP_DROP                   : return "OP_DROP";
+     case OP_DUP                    : return "OP_DUP";
+     case OP_NIP                    : return "OP_NIP";
+     case OP_OVER                   : return "OP_OVER";
+     case OP_PICK                   : return "OP_PICK";
+     case OP_ROLL                   : return "OP_ROLL";
+     case OP_ROT                    : return "OP_ROT";
+     case OP_SWAP                   : return "OP_SWAP";
+     case OP_TUCK                   : return "OP_TUCK";
+     // splice ops
+     case OP_CAT                    : return "OP_CAT";
+     case OP_SUBSTR                 : return "OP_SUBSTR";
+     case OP_LEFT                   : return "OP_LEFT";
+     case OP_RIGHT                  : return "OP_RIGHT";
+     case OP_SIZE                   : return "OP_SIZE";
+     // bit logic
+     case OP_INVERT                 : return "OP_INVERT";
+     case OP_AND                    : return "OP_AND";
+     case OP_OR                     : return "OP_OR";
+     case OP_XOR                    : return "OP_XOR";
+     case OP_EQUAL                  : return "OP_EQUAL";
+     case OP_EQUALVERIFY            : return "OP_EQUALVERIFY";
+     case OP_RESERVED1              : return "OP_RESERVED1";
+     case OP_RESERVED2              : return "OP_RESERVED2";
+     // numeric
+     case OP_1ADD                   : return "OP_1ADD";
+     case OP_1SUB                   : return "OP_1SUB";
+     case OP_2MUL                   : return "OP_2MUL";
+     case OP_2DIV                   : return "OP_2DIV";
+     case OP_NEGATE                 : return "OP_NEGATE";
+     case OP_ABS                    : return "OP_ABS";
+     case OP_NOT                    : return "OP_NOT";
+     case OP_0NOTEQUAL              : return "OP_0NOTEQUAL";
+     case OP_ADD                    : return "OP_ADD";
+     case OP_SUB                    : return "OP_SUB";
+     case OP_MUL                    : return "OP_MUL";
+     case OP_DIV                    : return "OP_DIV";
+     case OP_MOD                    : return "OP_MOD";
+     case OP_LSHIFT                 : return "OP_LSHIFT";
+     case OP_RSHIFT                 : return "OP_RSHIFT";
+     case OP_BOOLAND                : return "OP_BOOLAND";
+     case OP_BOOLOR                 : return "OP_BOOLOR";
+     case OP_NUMEQUAL               : return "OP_NUMEQUAL";
+     case OP_NUMEQUALVERIFY         : return "OP_NUMEQUALVERIFY";
+     case OP_NUMNOTEQUAL            : return "OP_NUMNOTEQUAL";
+     case OP_LESSTHAN               : return "OP_LESSTHAN";
+     case OP_GREATERTHAN            : return "OP_GREATERTHAN";
+     case OP_LESSTHANOREQUAL        : return "OP_LESSTHANOREQUAL";
+     case OP_GREATERTHANOREQUAL     : return "OP_GREATERTHANOREQUAL";
+     case OP_MIN                    : return "OP_MIN";
+     case OP_MAX                    : return "OP_MAX";
+     case OP_WITHIN                 : return "OP_WITHIN";
+     // crypto
+     case OP_RIPEMD160              : return "OP_RIPEMD160";
+     case OP_SHA1                   : return "OP_SHA1";
+     case OP_SHA256                 : return "OP_SHA256";
+     case OP_HASH160                : return "OP_HASH160";
+     case OP_HASH256                : return "OP_HASH256";
+     case OP_CODESEPARATOR          : return "OP_CODESEPARATOR";
+     case OP_CHECKSIG               : return "OP_CHECKSIG";
+     case OP_CHECKSIGVERIFY         : return "OP_CHECKSIGVERIFY";
+     case OP_CHECKMULTISIG          : return "OP_CHECKMULTISIG";
+     case OP_CHECKMULTISIGVERIFY    : return "OP_CHECKMULTISIGVERIFY";
+     // expanson
+     case OP_NOP1                   : return "OP_NOP1";
+     case OP_NOP2                   : return "OP_NOP2";
+     case OP_NOP3                   : return "OP_NOP3";
+     case OP_NOP4                   : return "OP_NOP4";
+     case OP_NOP5                   : return "OP_NOP5";
+     case OP_NOP6                   : return "OP_NOP6";
+     case OP_NOP7                   : return "OP_NOP7";
+     case OP_NOP8                   : return "OP_NOP8";
+     case OP_NOP9                   : return "OP_NOP9";
+     case OP_NOP10                  : return "OP_NOP10";
+     // template matching params
+     case OP_PUBKEYHASH             : return "OP_PUBKEYHASH";
+     case OP_PUBKEY                 : return "OP_PUBKEY";
+     case OP_INVALIDOPCODE          : return "OP_INVALIDOPCODE";
+     default:
+         return "OP_UNKNOWN";
+     }
+ }
  bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType)
  {
      CAutoBN_CTX pctx;
                          return false;
                      int n = CastToBigNum(stacktop(-1)).getint();
                      popstack(stack);
-                     if (n < 0 || n >= stack.size())
+                     if (n < 0 || n >= (int)stack.size())
                          return false;
                      valtype vch = stacktop(-n-1);
                      if (opcode == OP_ROLL)
                      int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint();
                      if (nBegin < 0 || nEnd < nBegin)
                          return false;
-                     if (nBegin > vch.size())
+                     if (nBegin > (int)vch.size())
                          nBegin = vch.size();
-                     if (nEnd > vch.size())
+                     if (nEnd > (int)vch.size())
                          nEnd = vch.size();
                      vch.erase(vch.begin() + nEnd, vch.end());
                      vch.erase(vch.begin(), vch.begin() + nBegin);
                      int nSize = CastToBigNum(stacktop(-1)).getint();
                      if (nSize < 0)
                          return false;
-                     if (nSize > vch.size())
+                     if (nSize > (int)vch.size())
                          nSize = vch.size();
                      if (opcode == OP_LEFT)
                          vch.erase(vch.begin() + nSize, vch.end());
                      if (stack.size() < 1)
                          return false;
                      valtype& vch = stacktop(-1);
-                     for (int i = 0; i < vch.size(); i++)
+                     for (unsigned int i = 0; i < vch.size(); i++)
                          vch[i] = ~vch[i];
                  }
                  break;
                      MakeSameSize(vch1, vch2);
                      if (opcode == OP_AND)
                      {
-                         for (int i = 0; i < vch1.size(); i++)
+                         for (unsigned int i = 0; i < vch1.size(); i++)
                              vch1[i] &= vch2[i];
                      }
                      else if (opcode == OP_OR)
                      {
-                         for (int i = 0; i < vch1.size(); i++)
+                         for (unsigned int i = 0; i < vch1.size(); i++)
                              vch1[i] |= vch2[i];
                      }
                      else if (opcode == OP_XOR)
                      {
-                         for (int i = 0; i < vch1.size(); i++)
+                         for (unsigned int i = 0; i < vch1.size(); i++)
                              vch1[i] ^= vch2[i];
                      }
                      popstack(stack);
@@@ -887,7 -1052,7 +1052,7 @@@ uint256 SignatureHash(CScript scriptCod
      scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
  
      // Blank out other inputs' signatures
-     for (int i = 0; i < txTmp.vin.size(); i++)
+     for (unsigned int i = 0; i < txTmp.vin.size(); i++)
          txTmp.vin[i].scriptSig = CScript();
      txTmp.vin[nIn].scriptSig = scriptCode;
  
          txTmp.vout.clear();
  
          // Let the others update at will
-         for (int i = 0; i < txTmp.vin.size(); i++)
+         for (unsigned int i = 0; i < txTmp.vin.size(); i++)
              if (i != nIn)
                  txTmp.vin[i].nSequence = 0;
      }
              return 1;
          }
          txTmp.vout.resize(nOut+1);
-         for (int i = 0; i < nOut; i++)
+         for (unsigned int i = 0; i < nOut; i++)
              txTmp.vout[i].SetNull();
  
          // Let the others update at will
-         for (int i = 0; i < txTmp.vin.size(); i++)
+         for (unsigned int i = 0; i < txTmp.vin.size(); i++)
              if (i != nIn)
                  txTmp.vin[i].nSequence = 0;
      }
      }
  
      // Serialize and hash
-     CDataStream ss(SER_GETHASH);
+     CDataStream ss(SER_GETHASH, 0);
      ss.reserve(10000);
      ss << txTmp << nHashType;
      return Hash(ss.begin(), ss.end());
  }
  
  
+ // Valid signature cache, to avoid doing expensive ECDSA signature checking
+ // twice for every transaction (once when accepted into memory pool, and
+ // again when accepted into the block chain)
+ class CSignatureCache
+ {
+ private:
+      // sigdata_type is (signature hash, signature, public key):
+     typedef boost::tuple<uint256, std::vector<unsigned char>, std::vector<unsigned char> > sigdata_type;
+     std::set< sigdata_type> setValid;
+     CCriticalSection cs_sigcache;
+ public:
+     bool
+     Get(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
+     {
+         LOCK(cs_sigcache);
+         sigdata_type k(hash, vchSig, pubKey);
+         std::set<sigdata_type>::iterator mi = setValid.find(k);
+         if (mi != setValid.end())
+             return true;
+         return false;
+     }
+     void
+     Set(uint256 hash, const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& pubKey)
+     {
+         // DoS prevention: limit cache size to less than 10MB
+         // (~200 bytes per cache entry times 50,000 entries)
+         // Since there are a maximum of 20,000 signature operations per block
+         // 50,000 is a reasonable default.
+         int64 nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
+         if (nMaxCacheSize <= 0) return;
+         LOCK(cs_sigcache);
+         while (static_cast<int64>(setValid.size()) > nMaxCacheSize)
+         {
+             // Evict a random entry. Random because that helps
+             // foil would-be DoS attackers who might try to pre-generate
+             // and re-use a set of valid signatures just-slightly-greater
+             // than our cache size.
+             uint256 randomHash = GetRandHash();
+             std::vector<unsigned char> unused;
+             std::set<sigdata_type>::iterator it =
+                 setValid.lower_bound(sigdata_type(randomHash, unused, unused));
+             if (it == setValid.end())
+                 it = setValid.begin();
+             setValid.erase(*it);
+         }
+         sigdata_type k(hash, vchSig, pubKey);
+         setValid.insert(k);
+     }
+ };
  bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode,
                const CTransaction& txTo, unsigned int nIn, int nHashType)
  {
-     CKey key;
-     if (!key.SetPubKey(vchPubKey))
-         return false;
+     static CSignatureCache signatureCache;
  
      // Hash type is one byte tacked on to the end of the signature
      if (vchSig.empty())
          return false;
      vchSig.pop_back();
  
-     return key.Verify(SignatureHash(scriptCode, txTo, nIn, nHashType), vchSig);
- }
+     uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
  
+     if (signatureCache.Get(sighash, vchSig, vchPubKey))
+         return true;
  
+     CKey key;
+     if (!key.SetPubKey(vchPubKey))
+         return false;
  
+     if (!key.Verify(sighash, vchSig))
+         return false;
+     signatureCache.Set(sighash, vchSig, vchPubKey);
+     return true;
+ }
  
  
  
  
  
  
- bool Solver(const CScript& scriptPubKey, vector<pair<opcodetype, valtype> >& vSolutionRet)
+ //
+ // Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
+ //
+ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
  {
      // Templates
-     static vector<CScript> vTemplates;
-     if (vTemplates.empty())
+     static map<txnouttype, CScript> mTemplates;
+     if (mTemplates.empty())
      {
          // Standard tx, sender provides pubkey, receiver adds signature
-         vTemplates.push_back(CScript() << OP_PUBKEY << OP_CHECKSIG);
+         mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
  
          // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
-         vTemplates.push_back(CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG);
+         mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
+         // Sender provides N pubkeys, receivers provides M signatures
+         mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+     }
+     // Shortcut for pay-to-script-hash, which are more constrained than the other types:
+     // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
+     if (scriptPubKey.IsPayToScriptHash())
+     {
+         typeRet = TX_SCRIPTHASH;
+         vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
+         vSolutionsRet.push_back(hashBytes);
+         return true;
      }
  
      // Scan templates
      const CScript& script1 = scriptPubKey;
-     BOOST_FOREACH(const CScript& script2, vTemplates)
+     BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
      {
-         vSolutionRet.clear();
+         const CScript& script2 = tplate.second;
+         vSolutionsRet.clear();
          opcodetype opcode1, opcode2;
          vector<unsigned char> vch1, vch2;
  
              if (pc1 == script1.end() && pc2 == script2.end())
              {
                  // Found a match
-                 reverse(vSolutionRet.begin(), vSolutionRet.end());
+                 typeRet = tplate.first;
+                 if (typeRet == TX_MULTISIG)
+                 {
+                     // Additional checks for TX_MULTISIG:
+                     unsigned char m = vSolutionsRet.front()[0];
+                     unsigned char n = vSolutionsRet.back()[0];
+                     if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
+                         return false;
+                 }
                  return true;
              }
              if (!script1.GetOp(pc1, opcode1, vch1))
                  break;
              if (!script2.GetOp(pc2, opcode2, vch2))
                  break;
+             // Template matching opcodes:
+             if (opcode2 == OP_PUBKEYS)
+             {
+                 while (vch1.size() >= 33 && vch1.size() <= 120)
+                 {
+                     vSolutionsRet.push_back(vch1);
+                     if (!script1.GetOp(pc1, opcode1, vch1))
+                         break;
+                 }
+                 if (!script2.GetOp(pc2, opcode2, vch2))
+                     break;
+                 // Normal situation is to fall through
+                 // to other if/else statments
+             }
              if (opcode2 == OP_PUBKEY)
              {
                  if (vch1.size() < 33 || vch1.size() > 120)
                      break;
-                 vSolutionRet.push_back(make_pair(opcode2, vch1));
+                 vSolutionsRet.push_back(vch1);
              }
              else if (opcode2 == OP_PUBKEYHASH)
              {
                  if (vch1.size() != sizeof(uint160))
                      break;
-                 vSolutionRet.push_back(make_pair(opcode2, vch1));
+                 vSolutionsRet.push_back(vch1);
+             }
+             else if (opcode2 == OP_SMALLINTEGER)
+             {   // Single-byte small integer pushed onto vSolutions
+                 if (opcode1 == OP_0 ||
+                     (opcode1 >= OP_1 && opcode1 <= OP_16))
+                 {
+                     char n = (char)CScript::DecodeOP_N(opcode1);
+                     vSolutionsRet.push_back(valtype(1, n));
+                 }
+                 else
+                     break;
              }
              else if (opcode1 != opcode2 || vch1 != vch2)
              {
+                 // Others must match exactly
                  break;
              }
          }
      }
  
-     vSolutionRet.clear();
+     vSolutionsRet.clear();
+     typeRet = TX_NONSTANDARD;
      return false;
  }
  
  
- bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet)
+ bool Sign1(const CBitcoinAddress& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
  {
-     scriptSigRet.clear();
+     CKey key;
+     if (!keystore.GetKey(address, key))
+         return false;
  
-     vector<pair<opcodetype, valtype> > vSolution;
-     if (!Solver(scriptPubKey, vSolution))
+     vector<unsigned char> vchSig;
+     if (!key.Sign(hash, vchSig))
          return false;
+     vchSig.push_back((unsigned char)nHashType);
+     scriptSigRet << vchSig;
+     return true;
+ }
  
-     // Compile solution
-     BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
+ {
+     int nSigned = 0;
+     int nRequired = multisigdata.front()[0];
+     for (vector<valtype>::const_iterator it = multisigdata.begin()+1; it != multisigdata.begin()+multisigdata.size()-1; it++)
      {
-         if (item.first == OP_PUBKEY)
-         {
-             // Sign
-             const valtype& vchPubKey = item.second;
-             CKey key;
-             if (!keystore.GetKey(Hash160(vchPubKey), key))
-                 return false;
-             if (key.GetPubKey() != vchPubKey)
-                 return false;
-             if (hash != 0)
-             {
-                 vector<unsigned char> vchSig;
-                 if (!key.Sign(hash, vchSig))
-                     return false;
-                 vchSig.push_back((unsigned char)nHashType);
-                 scriptSigRet << vchSig;
-             }
-         }
-         else if (item.first == OP_PUBKEYHASH)
+         const valtype& pubkey = *it;
+         CBitcoinAddress address;
+         address.SetPubKey(pubkey);
+         if (Sign1(address, keystore, hash, nHashType, scriptSigRet))
          {
-             // Sign and give pubkey
-             CKey key;
-             if (!keystore.GetKey(uint160(item.second), key))
-                 return false;
-             if (hash != 0)
-             {
-                 vector<unsigned char> vchSig;
-                 if (!key.Sign(hash, vchSig))
-                     return false;
-                 vchSig.push_back((unsigned char)nHashType);
-                 scriptSigRet << vchSig << key.GetPubKey();
-             }
+             ++nSigned;
+             if (nSigned == nRequired) break;
          }
+     }
+     return nSigned==nRequired;
+ }
+ //
+ // Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
+ // Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
+ // unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
+ // Returns false if scriptPubKey could not be completely satisified.
+ //
+ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
+                   CScript& scriptSigRet, txnouttype& whichTypeRet)
+ {
+     scriptSigRet.clear();
+     vector<valtype> vSolutions;
+     if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
+         return false;
+     CBitcoinAddress address;
+     switch (whichTypeRet)
+     {
+     case TX_NONSTANDARD:
+         return false;
+     case TX_PUBKEY:
+         address.SetPubKey(vSolutions[0]);
+         return Sign1(address, keystore, hash, nHashType, scriptSigRet);
+     case TX_PUBKEYHASH:
+         address.SetHash160(uint160(vSolutions[0]));
+         if (!Sign1(address, keystore, hash, nHashType, scriptSigRet))
+             return false;
          else
          {
-             return false;
+             valtype vch;
+             keystore.GetPubKey(address, vch);
+             scriptSigRet << vch;
          }
-     }
+         return true;
+     case TX_SCRIPTHASH:
+         return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
  
-     return true;
+     case TX_MULTISIG:
+         scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
+         return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
+     }
+     return false;
  }
  
+ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
+ {
+     switch (t)
+     {
+     case TX_NONSTANDARD:
+         return -1;
+     case TX_PUBKEY:
+         return 1;
+     case TX_PUBKEYHASH:
+         return 2;
+     case TX_MULTISIG:
+         if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
+             return -1;
+         return vSolutions[0][0] + 1;
+     case TX_SCRIPTHASH:
+         return 1; // doesn't include args needed by the script
+     }
+     return -1;
+ }
  
  bool IsStandard(const CScript& scriptPubKey)
  {
-     vector<pair<opcodetype, valtype> > vSolution;
-     return Solver(scriptPubKey, vSolution);
+     vector<valtype> vSolutions;
+     txnouttype whichType;
+     if (!Solver(scriptPubKey, whichType, vSolutions))
+         return false;
+     if (whichType == TX_MULTISIG)
+     {
+         unsigned char m = vSolutions.front()[0];
+         unsigned char n = vSolutions.back()[0];
+         // Support up to x-of-3 multisig txns as standard
+         if (n < 1 || n > 3)
+             return false;
+         if (m < 1 || m > n)
+             return false;
+     }
+     return whichType != TX_NONSTANDARD;
  }
  
  
+ unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
+ {
+     unsigned int nResult = 0;
+     BOOST_FOREACH(const valtype& pubkey, pubkeys)
+     {
+         CBitcoinAddress address;
+         address.SetPubKey(pubkey);
+         if (keystore.HaveKey(address))
+             ++nResult;
+     }
+     return nResult;
+ }
  bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
  {
-     vector<pair<opcodetype, valtype> > vSolution;
-     if (!Solver(scriptPubKey, vSolution))
+     vector<valtype> vSolutions;
+     txnouttype whichType;
+     if (!Solver(scriptPubKey, whichType, vSolutions))
          return false;
  
-     // Compile solution
-     BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+     CBitcoinAddress address;
+     switch (whichType)
      {
-         if (item.first == OP_PUBKEY)
-         {
-             const valtype& vchPubKey = item.second;
-             vector<unsigned char> vchPubKeyFound;
-             if (!keystore.GetPubKey(Hash160(vchPubKey), vchPubKeyFound))
-                 return false;
-             if (vchPubKeyFound != vchPubKey)
-                 return false;
-         }
-         else if (item.first == OP_PUBKEYHASH)
-         {
-             if (!keystore.HaveKey(uint160(item.second)))
-                 return false;
-         }
-         else
-         {
+     case TX_NONSTANDARD:
+         return false;
+     case TX_PUBKEY:
+         address.SetPubKey(vSolutions[0]);
+         return keystore.HaveKey(address);
+     case TX_PUBKEYHASH:
+         address.SetHash160(uint160(vSolutions[0]));
+         return keystore.HaveKey(address);
+     case TX_SCRIPTHASH:
+     {
+         CScript subscript;
+         if (!keystore.GetCScript(uint160(vSolutions[0]), subscript))
              return false;
-         }
+         return IsMine(keystore, subscript);
      }
-     return true;
+     case TX_MULTISIG:
+     {
+         // Only consider transactions "mine" if we own ALL the
+         // keys involved. multi-signature transactions that are
+         // partially owned (somebody else has a key that can spend
+         // them) enable spend-out-from-under-you attacks, especially
+         // in shared-wallet situations.
+         vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
+         return HaveKeys(keys, keystore) == keys.size();
+     }
+     }
+     return false;
  }
  
- bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
+ bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet)
  {
-     vector<pair<opcodetype, valtype> > vSolution;
-     if (!Solver(scriptPubKey, vSolution))
+     vector<valtype> vSolutions;
+     txnouttype whichType;
+     if (!Solver(scriptPubKey, whichType, vSolutions))
          return false;
  
-     BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+     if (whichType == TX_PUBKEY)
      {
-         if (item.first == OP_PUBKEY)
-             addressRet.SetPubKey(item.second);
-         else if (item.first == OP_PUBKEYHASH)
-             addressRet.SetHash160((uint160)item.second);
-         if (keystore == NULL || keystore->HaveKey(addressRet))
-             return true;
+         addressRet.SetPubKey(vSolutions[0]);
+         return true;
      }
+     else if (whichType == TX_PUBKEYHASH)
+     {
+         addressRet.SetHash160(uint160(vSolutions[0]));
+         return true;
+     }
+     else if (whichType == TX_SCRIPTHASH)
+     {
+         addressRet.SetScriptHash160(uint160(vSolutions[0]));
+         return true;
+     }
+     // Multisig txns have more than one address...
      return false;
  }
  
- bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
+ bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, vector<CBitcoinAddress>& addressRet, int& nRequiredRet)
  {
-     if (keystore)
-         return ExtractAddressInner(scriptPubKey, keystore, addressRet);
+     addressRet.clear();
+     typeRet = TX_NONSTANDARD;
+     vector<valtype> vSolutions;
+     if (!Solver(scriptPubKey, typeRet, vSolutions))
+         return false;
+     if (typeRet == TX_MULTISIG)
+     {
+         nRequiredRet = vSolutions.front()[0];
+         for (unsigned int i = 1; i < vSolutions.size()-1; i++)
+         {
+             CBitcoinAddress address;
+             address.SetPubKey(vSolutions[i]);
+             addressRet.push_back(address);
+         }
+     }
      else
-         return ExtractAddressInner(scriptPubKey, NULL, addressRet);
-     return false;
- }
+     {
+         nRequiredRet = 1;
+         CBitcoinAddress address;
+         if (typeRet == TX_PUBKEYHASH)
+             address.SetHash160(uint160(vSolutions.front()));
+         else if (typeRet == TX_SCRIPTHASH)
+             address.SetScriptHash160(uint160(vSolutions.front()));
+         else if (typeRet == TX_PUBKEY)
+             address.SetPubKey(vSolutions.front());
+         addressRet.push_back(address);
+     }
  
+     return true;
+ }
  
- bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType)
+ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
+                   bool fValidatePayToScriptHash, int nHashType)
  {
-     vector<vector<unsigned char> > stack;
+     vector<vector<unsigned char> > stack, stackCopy;
      if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType))
          return false;
+     if (fValidatePayToScriptHash)
+         stackCopy = stack;
      if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType))
          return false;
      if (stack.empty())
          return false;
-     return CastToBool(stack.back());
+     if (CastToBool(stack.back()) == false)
+         return false;
+     // Additional validation for spend-to-script-hash transactions:
+     if (fValidatePayToScriptHash && scriptPubKey.IsPayToScriptHash())
+     {
+         if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only
+             return false;            // or validation fails
+         const valtype& pubKeySerialized = stackCopy.back();
+         CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
+         popstack(stackCopy);
+         if (!EvalScript(stackCopy, pubKey2, txTo, nIn, nHashType))
+             return false;
+         if (stackCopy.empty())
+             return false;
+         return CastToBool(stackCopy.back());
+     }
+     return true;
  }
  
  
- bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq)
+ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType)
  {
      assert(nIn < txTo.vin.size());
      CTxIn& txin = txTo.vin[nIn];
      assert(txin.prevout.n < txFrom.vout.size());
 +    assert(txin.prevout.hash == txFrom.GetHash());
      const CTxOut& txout = txFrom.vout[txin.prevout.n];
  
      // Leave out the signature from the hash, since a signature can't sign itself.
      // The checksig op will also drop the signatures from its hash.
-     uint256 hash = SignatureHash(scriptPrereq + txout.scriptPubKey, txTo, nIn, nHashType);
+     uint256 hash = SignatureHash(txout.scriptPubKey, txTo, nIn, nHashType);
  
-     if (!Solver(keystore, txout.scriptPubKey, hash, nHashType, txin.scriptSig))
+     txnouttype whichType;
+     if (!Solver(keystore, txout.scriptPubKey, hash, nHashType, txin.scriptSig, whichType))
          return false;
  
-     txin.scriptSig = scriptPrereq + txin.scriptSig;
+     if (whichType == TX_SCRIPTHASH)
+     {
+         // Solver returns the subscript that need to be evaluated;
+         // the final scriptSig is the signatures from that
+         // and then the serialized subscript:
+         CScript subscript = txin.scriptSig;
+         // Recompute txn hash using subscript in place of scriptPubKey:
+         uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
+         txnouttype subType;
+         if (!Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType))
+             return false;
+         if (subType == TX_SCRIPTHASH)
+             return false;
+         txin.scriptSig << static_cast<valtype>(subscript); // Append serialized subscript
+     }
  
      // Test solution
-     if (scriptPrereq.empty())
-         if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, 0))
-             return false;
+     if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, true, 0))
+         return false;
  
      return true;
  }
  
  
- bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType)
+ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType)
  {
      assert(nIn < txTo.vin.size());
      const CTxIn& txin = txTo.vin[nIn];
      if (txin.prevout.hash != txFrom.GetHash())
          return false;
  
-     if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nHashType))
+     if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, nHashType))
          return false;
  
      return true;
  }
+ unsigned int CScript::GetSigOpCount(bool fAccurate) const
+ {
+     unsigned int n = 0;
+     const_iterator pc = begin();
+     opcodetype lastOpcode = OP_INVALIDOPCODE;
+     while (pc < end())
+     {
+         opcodetype opcode;
+         if (!GetOp(pc, opcode))
+             break;
+         if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
+             n++;
+         else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
+         {
+             if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
+                 n += DecodeOP_N(lastOpcode);
+             else
+                 n += 20;
+         }
+         lastOpcode = opcode;
+     }
+     return n;
+ }
+ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
+ {
+     if (!IsPayToScriptHash())
+         return GetSigOpCount(true);
+     // This is a pay-to-script-hash scriptPubKey;
+     // get the last item that the scriptSig
+     // pushes onto the stack:
+     const_iterator pc = scriptSig.begin();
+     vector<unsigned char> data;
+     while (pc < scriptSig.end())
+     {
+         opcodetype opcode;
+         if (!scriptSig.GetOp(pc, opcode, data))
+             return 0;
+         if (opcode > OP_16)
+             return 0;
+     }
+     /// ... and return it's opcount:
+     CScript subscript(data.begin(), data.end());
+     return subscript.GetSigOpCount(true);
+ }
+ bool CScript::IsPayToScriptHash() const
+ {
+     // Extra-fast test for pay-to-script-hash CScripts:
+     return (this->size() == 23 &&
+             this->at(0) == OP_HASH160 &&
+             this->at(1) == 0x14 &&
+             this->at(22) == OP_EQUAL);
+ }
+ void CScript::SetBitcoinAddress(const CBitcoinAddress& address)
+ {
+     this->clear();
+     if (address.IsScript())
+         *this << OP_HASH160 << address.GetHash160() << OP_EQUAL;
+     else
+         *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_CHECKSIG;
+ }
+ void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
+ {
+     this->clear();
+     *this << EncodeOP_N(nRequired);
+     BOOST_FOREACH(const CKey& key, keys)
+         *this << key.GetPubKey();
+     *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
+ }
+ void CScript::SetPayToScriptHash(const CScript& subscript)
+ {
+     assert(!subscript.empty());
+     uint160 subscriptHash = Hash160(subscript);
+     this->clear();
+     *this << OP_HASH160 << subscriptHash << OP_EQUAL;
+ }
diff --combined src/script.h
@@@ -1,22 -1,21 +1,24 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
++// Copyright (c) 2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef H_BITCOIN_SCRIPT
  #define H_BITCOIN_SCRIPT
  
  #include "base58.h"
- #include "keystore.h"
  
  #include <string>
  #include <vector>
  
  #include <boost/foreach.hpp>
  
 +typedef std::vector<unsigned char> valtype;
 +
  class CTransaction;
+ class CKeyStore;
  
+ /** Signature hash types/flags */
  enum
  {
      SIGHASH_ALL = 1,
  };
  
  
+ enum txnouttype
+ {
+     TX_NONSTANDARD,
+     // 'standard' transaction types:
+     TX_PUBKEY,
+     TX_PUBKEYHASH,
+     TX_SCRIPTHASH,
+     TX_MULTISIG,
+ };
  
+ const char* GetTxnOutputType(txnouttype t);
+ /** Script opcodes */
  enum opcodetype
  {
      // push value
-     OP_0=0,
-     OP_FALSE=OP_0,
-     OP_PUSHDATA1=76,
-     OP_PUSHDATA2,
-     OP_PUSHDATA4,
-     OP_1NEGATE,
-     OP_RESERVED,
-     OP_1,
+     OP_0 = 0x00,
+     OP_FALSE = OP_0,
+     OP_PUSHDATA1 = 0x4c,
+     OP_PUSHDATA2 = 0x4d,
+     OP_PUSHDATA4 = 0x4e,
+     OP_1NEGATE = 0x4f,
+     OP_RESERVED = 0x50,
+     OP_1 = 0x51,
      OP_TRUE=OP_1,
-     OP_2,
-     OP_3,
-     OP_4,
-     OP_5,
-     OP_6,
-     OP_7,
-     OP_8,
-     OP_9,
-     OP_10,
-     OP_11,
-     OP_12,
-     OP_13,
-     OP_14,
-     OP_15,
-     OP_16,
+     OP_2 = 0x52,
+     OP_3 = 0x53,
+     OP_4 = 0x54,
+     OP_5 = 0x55,
+     OP_6 = 0x56,
+     OP_7 = 0x57,
+     OP_8 = 0x58,
+     OP_9 = 0x59,
+     OP_10 = 0x5a,
+     OP_11 = 0x5b,
+     OP_12 = 0x5c,
+     OP_13 = 0x5d,
+     OP_14 = 0x5e,
+     OP_15 = 0x5f,
+     OP_16 = 0x60,
  
      // control
-     OP_NOP,
-     OP_VER,
-     OP_IF,
-     OP_NOTIF,
-     OP_VERIF,
-     OP_VERNOTIF,
-     OP_ELSE,
-     OP_ENDIF,
-     OP_VERIFY,
-     OP_RETURN,
+     OP_NOP = 0x61,
+     OP_VER = 0x62,
+     OP_IF = 0x63,
+     OP_NOTIF = 0x64,
+     OP_VERIF = 0x65,
+     OP_VERNOTIF = 0x66,
+     OP_ELSE = 0x67,
+     OP_ENDIF = 0x68,
+     OP_VERIFY = 0x69,
+     OP_RETURN = 0x6a,
  
      // stack ops
-     OP_TOALTSTACK,
-     OP_FROMALTSTACK,
-     OP_2DROP,
-     OP_2DUP,
-     OP_3DUP,
-     OP_2OVER,
-     OP_2ROT,
-     OP_2SWAP,
-     OP_IFDUP,
-     OP_DEPTH,
-     OP_DROP,
-     OP_DUP,
-     OP_NIP,
-     OP_OVER,
-     OP_PICK,
-     OP_ROLL,
-     OP_ROT,
-     OP_SWAP,
-     OP_TUCK,
+     OP_TOALTSTACK = 0x6b,
+     OP_FROMALTSTACK = 0x6c,
+     OP_2DROP = 0x6d,
+     OP_2DUP = 0x6e,
+     OP_3DUP = 0x6f,
+     OP_2OVER = 0x70,
+     OP_2ROT = 0x71,
+     OP_2SWAP = 0x72,
+     OP_IFDUP = 0x73,
+     OP_DEPTH = 0x74,
+     OP_DROP = 0x75,
+     OP_DUP = 0x76,
+     OP_NIP = 0x77,
+     OP_OVER = 0x78,
+     OP_PICK = 0x79,
+     OP_ROLL = 0x7a,
+     OP_ROT = 0x7b,
+     OP_SWAP = 0x7c,
+     OP_TUCK = 0x7d,
  
      // splice ops
-     OP_CAT,
-     OP_SUBSTR,
-     OP_LEFT,
-     OP_RIGHT,
-     OP_SIZE,
+     OP_CAT = 0x7e,
+     OP_SUBSTR = 0x7f,
+     OP_LEFT = 0x80,
+     OP_RIGHT = 0x81,
+     OP_SIZE = 0x82,
  
      // bit logic
-     OP_INVERT,
-     OP_AND,
-     OP_OR,
-     OP_XOR,
-     OP_EQUAL,
-     OP_EQUALVERIFY,
-     OP_RESERVED1,
-     OP_RESERVED2,
+     OP_INVERT = 0x83,
+     OP_AND = 0x84,
+     OP_OR = 0x85,
+     OP_XOR = 0x86,
+     OP_EQUAL = 0x87,
+     OP_EQUALVERIFY = 0x88,
+     OP_RESERVED1 = 0x89,
+     OP_RESERVED2 = 0x8a,
  
      // numeric
-     OP_1ADD,
-     OP_1SUB,
-     OP_2MUL,
-     OP_2DIV,
-     OP_NEGATE,
-     OP_ABS,
-     OP_NOT,
-     OP_0NOTEQUAL,
-     OP_ADD,
-     OP_SUB,
-     OP_MUL,
-     OP_DIV,
-     OP_MOD,
-     OP_LSHIFT,
-     OP_RSHIFT,
-     OP_BOOLAND,
-     OP_BOOLOR,
-     OP_NUMEQUAL,
-     OP_NUMEQUALVERIFY,
-     OP_NUMNOTEQUAL,
-     OP_LESSTHAN,
-     OP_GREATERTHAN,
-     OP_LESSTHANOREQUAL,
-     OP_GREATERTHANOREQUAL,
-     OP_MIN,
-     OP_MAX,
-     OP_WITHIN,
+     OP_1ADD = 0x8b,
+     OP_1SUB = 0x8c,
+     OP_2MUL = 0x8d,
+     OP_2DIV = 0x8e,
+     OP_NEGATE = 0x8f,
+     OP_ABS = 0x90,
+     OP_NOT = 0x91,
+     OP_0NOTEQUAL = 0x92,
+     OP_ADD = 0x93,
+     OP_SUB = 0x94,
+     OP_MUL = 0x95,
+     OP_DIV = 0x96,
+     OP_MOD = 0x97,
+     OP_LSHIFT = 0x98,
+     OP_RSHIFT = 0x99,
+     OP_BOOLAND = 0x9a,
+     OP_BOOLOR = 0x9b,
+     OP_NUMEQUAL = 0x9c,
+     OP_NUMEQUALVERIFY = 0x9d,
+     OP_NUMNOTEQUAL = 0x9e,
+     OP_LESSTHAN = 0x9f,
+     OP_GREATERTHAN = 0xa0,
+     OP_LESSTHANOREQUAL = 0xa1,
+     OP_GREATERTHANOREQUAL = 0xa2,
+     OP_MIN = 0xa3,
+     OP_MAX = 0xa4,
+     OP_WITHIN = 0xa5,
  
      // crypto
-     OP_RIPEMD160,
-     OP_SHA1,
-     OP_SHA256,
-     OP_HASH160,
-     OP_HASH256,
-     OP_CODESEPARATOR,
-     OP_CHECKSIG,
-     OP_CHECKSIGVERIFY,
-     OP_CHECKMULTISIG,
-     OP_CHECKMULTISIGVERIFY,
+     OP_RIPEMD160 = 0xa6,
+     OP_SHA1 = 0xa7,
+     OP_SHA256 = 0xa8,
+     OP_HASH160 = 0xa9,
+     OP_HASH256 = 0xaa,
+     OP_CODESEPARATOR = 0xab,
+     OP_CHECKSIG = 0xac,
+     OP_CHECKSIGVERIFY = 0xad,
+     OP_CHECKMULTISIG = 0xae,
+     OP_CHECKMULTISIGVERIFY = 0xaf,
  
      // expansion
-     OP_NOP1,
-     OP_NOP2,
-     OP_NOP3,
-     OP_NOP4,
-     OP_NOP5,
-     OP_NOP6,
-     OP_NOP7,
-     OP_NOP8,
-     OP_NOP9,
-     OP_NOP10,
+     OP_NOP1 = 0xb0,
+     OP_NOP2 = 0xb1,
+     OP_NOP3 = 0xb2,
+     OP_NOP4 = 0xb3,
+     OP_NOP5 = 0xb4,
+     OP_NOP6 = 0xb5,
+     OP_NOP7 = 0xb6,
+     OP_NOP8 = 0xb7,
+     OP_NOP9 = 0xb8,
+     OP_NOP10 = 0xb9,
  
  
  
      // template matching params
+     OP_SMALLINTEGER = 0xfa,
+     OP_PUBKEYS = 0xfb,
      OP_PUBKEYHASH = 0xfd,
      OP_PUBKEY = 0xfe,
  
      OP_INVALIDOPCODE = 0xff,
  };
  
- inline const char* GetOpName(opcodetype opcode)
- {
-     switch (opcode)
-     {
-     // push value
-     case OP_0                      : return "0";
-     case OP_PUSHDATA1              : return "OP_PUSHDATA1";
-     case OP_PUSHDATA2              : return "OP_PUSHDATA2";
-     case OP_PUSHDATA4              : return "OP_PUSHDATA4";
-     case OP_1NEGATE                : return "-1";
-     case OP_RESERVED               : return "OP_RESERVED";
-     case OP_1                      : return "1";
-     case OP_2                      : return "2";
-     case OP_3                      : return "3";
-     case OP_4                      : return "4";
-     case OP_5                      : return "5";
-     case OP_6                      : return "6";
-     case OP_7                      : return "7";
-     case OP_8                      : return "8";
-     case OP_9                      : return "9";
-     case OP_10                     : return "10";
-     case OP_11                     : return "11";
-     case OP_12                     : return "12";
-     case OP_13                     : return "13";
-     case OP_14                     : return "14";
-     case OP_15                     : return "15";
-     case OP_16                     : return "16";
-     // control
-     case OP_NOP                    : return "OP_NOP";
-     case OP_VER                    : return "OP_VER";
-     case OP_IF                     : return "OP_IF";
-     case OP_NOTIF                  : return "OP_NOTIF";
-     case OP_VERIF                  : return "OP_VERIF";
-     case OP_VERNOTIF               : return "OP_VERNOTIF";
-     case OP_ELSE                   : return "OP_ELSE";
-     case OP_ENDIF                  : return "OP_ENDIF";
-     case OP_VERIFY                 : return "OP_VERIFY";
-     case OP_RETURN                 : return "OP_RETURN";
-     // stack ops
-     case OP_TOALTSTACK             : return "OP_TOALTSTACK";
-     case OP_FROMALTSTACK           : return "OP_FROMALTSTACK";
-     case OP_2DROP                  : return "OP_2DROP";
-     case OP_2DUP                   : return "OP_2DUP";
-     case OP_3DUP                   : return "OP_3DUP";
-     case OP_2OVER                  : return "OP_2OVER";
-     case OP_2ROT                   : return "OP_2ROT";
-     case OP_2SWAP                  : return "OP_2SWAP";
-     case OP_IFDUP                  : return "OP_IFDUP";
-     case OP_DEPTH                  : return "OP_DEPTH";
-     case OP_DROP                   : return "OP_DROP";
-     case OP_DUP                    : return "OP_DUP";
-     case OP_NIP                    : return "OP_NIP";
-     case OP_OVER                   : return "OP_OVER";
-     case OP_PICK                   : return "OP_PICK";
-     case OP_ROLL                   : return "OP_ROLL";
-     case OP_ROT                    : return "OP_ROT";
-     case OP_SWAP                   : return "OP_SWAP";
-     case OP_TUCK                   : return "OP_TUCK";
-     // splice ops
-     case OP_CAT                    : return "OP_CAT";
-     case OP_SUBSTR                 : return "OP_SUBSTR";
-     case OP_LEFT                   : return "OP_LEFT";
-     case OP_RIGHT                  : return "OP_RIGHT";
-     case OP_SIZE                   : return "OP_SIZE";
-     // bit logic
-     case OP_INVERT                 : return "OP_INVERT";
-     case OP_AND                    : return "OP_AND";
-     case OP_OR                     : return "OP_OR";
-     case OP_XOR                    : return "OP_XOR";
-     case OP_EQUAL                  : return "OP_EQUAL";
-     case OP_EQUALVERIFY            : return "OP_EQUALVERIFY";
-     case OP_RESERVED1              : return "OP_RESERVED1";
-     case OP_RESERVED2              : return "OP_RESERVED2";
-     // numeric
-     case OP_1ADD                   : return "OP_1ADD";
-     case OP_1SUB                   : return "OP_1SUB";
-     case OP_2MUL                   : return "OP_2MUL";
-     case OP_2DIV                   : return "OP_2DIV";
-     case OP_NEGATE                 : return "OP_NEGATE";
-     case OP_ABS                    : return "OP_ABS";
-     case OP_NOT                    : return "OP_NOT";
-     case OP_0NOTEQUAL              : return "OP_0NOTEQUAL";
-     case OP_ADD                    : return "OP_ADD";
-     case OP_SUB                    : return "OP_SUB";
-     case OP_MUL                    : return "OP_MUL";
-     case OP_DIV                    : return "OP_DIV";
-     case OP_MOD                    : return "OP_MOD";
-     case OP_LSHIFT                 : return "OP_LSHIFT";
-     case OP_RSHIFT                 : return "OP_RSHIFT";
-     case OP_BOOLAND                : return "OP_BOOLAND";
-     case OP_BOOLOR                 : return "OP_BOOLOR";
-     case OP_NUMEQUAL               : return "OP_NUMEQUAL";
-     case OP_NUMEQUALVERIFY         : return "OP_NUMEQUALVERIFY";
-     case OP_NUMNOTEQUAL            : return "OP_NUMNOTEQUAL";
-     case OP_LESSTHAN               : return "OP_LESSTHAN";
-     case OP_GREATERTHAN            : return "OP_GREATERTHAN";
-     case OP_LESSTHANOREQUAL        : return "OP_LESSTHANOREQUAL";
-     case OP_GREATERTHANOREQUAL     : return "OP_GREATERTHANOREQUAL";
-     case OP_MIN                    : return "OP_MIN";
-     case OP_MAX                    : return "OP_MAX";
-     case OP_WITHIN                 : return "OP_WITHIN";
-     // crypto
-     case OP_RIPEMD160              : return "OP_RIPEMD160";
-     case OP_SHA1                   : return "OP_SHA1";
-     case OP_SHA256                 : return "OP_SHA256";
-     case OP_HASH160                : return "OP_HASH160";
-     case OP_HASH256                : return "OP_HASH256";
-     case OP_CODESEPARATOR          : return "OP_CODESEPARATOR";
-     case OP_CHECKSIG               : return "OP_CHECKSIG";
-     case OP_CHECKSIGVERIFY         : return "OP_CHECKSIGVERIFY";
-     case OP_CHECKMULTISIG          : return "OP_CHECKMULTISIG";
-     case OP_CHECKMULTISIGVERIFY    : return "OP_CHECKMULTISIGVERIFY";
-     // expanson
-     case OP_NOP1                   : return "OP_NOP1";
-     case OP_NOP2                   : return "OP_NOP2";
-     case OP_NOP3                   : return "OP_NOP3";
-     case OP_NOP4                   : return "OP_NOP4";
-     case OP_NOP5                   : return "OP_NOP5";
-     case OP_NOP6                   : return "OP_NOP6";
-     case OP_NOP7                   : return "OP_NOP7";
-     case OP_NOP8                   : return "OP_NOP8";
-     case OP_NOP9                   : return "OP_NOP9";
-     case OP_NOP10                  : return "OP_NOP10";
-     // template matching params
-     case OP_PUBKEYHASH             : return "OP_PUBKEYHASH";
-     case OP_PUBKEY                 : return "OP_PUBKEY";
-     case OP_INVALIDOPCODE          : return "OP_INVALIDOPCODE";
-     default:
-         return "OP_UNKNOWN";
-     }
- };
+ const char* GetOpName(opcodetype opcode);
  
  
  
@@@ -350,7 -214,7 +217,7 @@@ inline std::string StackString(const st
  
  
  
+ /** Serialized script, used inside transaction inputs and outputs */
  class CScript : public std::vector<unsigned char>
  {
  protected:
@@@ -404,7 -268,8 +271,8 @@@ public
      }
  
  
-     explicit CScript(char b)           { operator<<(b); }
+     //explicit CScript(char b) is not portable.  Use 'signed char' or 'unsigned char'.
+     explicit CScript(signed char b)    { operator<<(b); }
      explicit CScript(short b)          { operator<<(b); }
      explicit CScript(int b)            { operator<<(b); }
      explicit CScript(long b)           { operator<<(b); }
      explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); }
  
  
-     CScript& operator<<(char b)           { return push_int64(b); }
+     //CScript& operator<<(char b) is not portable.  Use 'signed char' or 'unsigned char'.
+     CScript& operator<<(signed char b)    { return push_int64(b); }
      CScript& operator<<(short b)          { return push_int64(b); }
      CScript& operator<<(int b)            { return push_int64(b); }
      CScript& operator<<(long b)           { return push_int64(b); }
          return true;
      }
  
+     // Encode/decode small integers:
+     static int DecodeOP_N(opcodetype opcode)
+     {
+         if (opcode == OP_0)
+             return 0;
+         assert(opcode >= OP_1 && opcode <= OP_16);
+         return (int)opcode - (int)(OP_1 - 1);
+     }
+     static opcodetype EncodeOP_N(int n)
+     {
+         assert(n >= 0 && n <= 16);
+         if (n == 0)
+             return OP_0;
+         return (opcodetype)(OP_1+n-1);
+     }
  
-     void FindAndDelete(const CScript& b)
+     int FindAndDelete(const CScript& b)
      {
+         int nFound = 0;
          if (b.empty())
-             return;
+             return nFound;
          iterator pc = begin();
          opcodetype opcode;
          do
          {
-             while (end() - pc >= b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
+             while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
+             {
                  erase(pc, pc + b.size());
+                 ++nFound;
+             }
          }
          while (GetOp(pc, opcode));
+         return nFound;
      }
-     int GetSigOpCount() const
+     int Find(opcodetype op) const
      {
-         int n = 0;
-         const_iterator pc = begin();
-         while (pc < end())
-         {
-             opcodetype opcode;
-             if (!GetOp(pc, opcode))
-                 break;
-             if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
-                 n++;
-             else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
-                 n += 20;
-         }
-         return n;
+         int nFound = 0;
+         opcodetype opcode;
+         for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);)
+             if (opcode == op)
+                 ++nFound;
+         return nFound;
      }
  
+     // Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs
+     // as 20 sigops. With pay-to-script-hash, that changed:
+     // CHECKMULTISIGs serialized in scriptSigs are
+     // counted more accurately, assuming they are of the form
+     //  ... OP_N CHECKMULTISIG ...
+     unsigned int GetSigOpCount(bool fAccurate) const;
+     // Accurately count sigOps, including sigOps in
+     // pay-to-script-hash transactions:
+     unsigned int GetSigOpCount(const CScript& scriptSig) const;
  
+     bool IsPayToScriptHash() const;
+     // Called by CTransaction::IsStandard
      bool IsPushOnly() const
      {
-         if (size() > 200)
-             return false;
          const_iterator pc = begin();
          while (pc < end())
          {
      }
  
  
-     CBitcoinAddress GetBitcoinAddress() const
-     {
-         opcodetype opcode;
-         std::vector<unsigned char> vch;
-         CScript::const_iterator pc = begin();
-         if (!GetOp(pc, opcode, vch) || opcode != OP_DUP) return 0;
-         if (!GetOp(pc, opcode, vch) || opcode != OP_HASH160) return 0;
-         if (!GetOp(pc, opcode, vch) || vch.size() != sizeof(uint160)) return 0;
-         uint160 hash160 = uint160(vch);
-         if (!GetOp(pc, opcode, vch) || opcode != OP_EQUALVERIFY) return 0;
-         if (!GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG) return 0;
-         if (pc != end()) return 0;
-         return CBitcoinAddress(hash160);
-     }
-     void SetBitcoinAddress(const CBitcoinAddress& address)
-     {
-         this->clear();
-         *this << OP_DUP << OP_HASH160 << address.GetHash160() << OP_EQUALVERIFY << OP_CHECKSIG;
-     }
+     void SetBitcoinAddress(const CBitcoinAddress& address);
      void SetBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
      {
          SetBitcoinAddress(CBitcoinAddress(vchPubKey));
      }
+     void SetMultisig(int nRequired, const std::vector<CKey>& keys);
+     void SetPayToScriptHash(const CScript& subscript);
  
  
      void PrintHex() const
  
  
  
  bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType);
+ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
  bool IsStandard(const CScript& scriptPubKey);
  bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
- bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* pkeystore, CBitcoinAddress& addressRet);
- bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript());
- bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType=0);
- bool Solver(const CScript& scriptPubKey, std::vector<std::pair<opcodetype, valtype> >& vSolutionRet);
+ bool ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet);
+ bool ExtractAddresses(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CBitcoinAddress>& addressRet, int& nRequiredRet);
+ bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
+ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, int nHashType);
  
  #endif
diff --combined src/serialize.h
@@@ -1,8 -1,7 +1,8 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_SERIALIZE_H
  #define BITCOIN_SERIALIZE_H
  
@@@ -11,7 -10,7 +11,7 @@@
  #include <map>
  #include <set>
  #include <cassert>
- #include <climits>
+ #include <limits>
  #include <cstring>
  #include <cstdio>
  
  #include <boost/tuple/tuple_comparison.hpp>
  #include <boost/tuple/tuple_io.hpp>
  
- #if defined(_MSC_VER) || defined(__BORLANDC__)
- typedef __int64  int64;
- typedef unsigned __int64  uint64;
- #else
+ #include "allocators.h"
+ #include "version.h"
  typedef long long  int64;
  typedef unsigned long long  uint64;
- #endif
- #if defined(_MSC_VER) && _MSC_VER < 1300
- #define for  if (false) ; else for
- #endif
- #ifdef WIN32
- #include <windows.h>
- // This is used to attempt to keep keying material out of swap
- // Note that VirtualLock does not provide this as a guarantee on Windows,
- // but, in practice, memory that has been VirtualLock'd almost never gets written to
- // the pagefile except in rare circumstances where memory is extremely low.
- #include <windows.h>
- #define mlock(p, n) VirtualLock((p), (n));
- #define munlock(p, n) VirtualUnlock((p), (n));
- #else
- #include <sys/mman.h>
- #include <limits.h>
- /* This comes from limits.h if it's not defined there set a sane default */
- #ifndef PAGESIZE
- #include <unistd.h>
- #define PAGESIZE sysconf(_SC_PAGESIZE)
- #endif
- #define mlock(a,b) \
-   mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
-   (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
- #define munlock(a,b) \
-   munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
-   (((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
- #endif
  
  class CScript;
  class CDataStream;
  class CAutoFile;
  static const unsigned int MAX_SIZE = 0x02000000;
  
- static const int VERSION = 50100;
- static const char* pszSubVer = "";
- static const bool VERSION_IS_BETA = true;
- static const int PPCOIN_VERSION = 100;
  // Used to bypass the rule against non-const reference to temporary
  // where it makes sense with wrappers such as CFlatData or CTxDB
  template<typename T>
@@@ -94,7 -57,7 +58,7 @@@ enu
  };
  
  #define IMPLEMENT_SERIALIZE(statements)    \
-     unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const  \
+     unsigned int GetSerializeSize(int nType, int nVersion) const  \
      {                                           \
          CSerActionGetSerializeSize ser_action;  \
          const bool fGetSize = true;             \
          const bool fRead = false;               \
          unsigned int nSerSize = 0;              \
          ser_streamplaceholder s;                \
+         assert(fGetSize||fWrite||fRead); /* suppress warning */ \
          s.nType = nType;                        \
          s.nVersion = nVersion;                  \
          {statements}                            \
          return nSerSize;                        \
      }                                           \
      template<typename Stream>                   \
-     void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const  \
+     void Serialize(Stream& s, int nType, int nVersion) const  \
      {                                           \
          CSerActionSerialize ser_action;         \
          const bool fGetSize = false;            \
          const bool fWrite = true;               \
          const bool fRead = false;               \
          unsigned int nSerSize = 0;              \
+         assert(fGetSize||fWrite||fRead); /* suppress warning */ \
          {statements}                            \
      }                                           \
      template<typename Stream>                   \
-     void Unserialize(Stream& s, int nType=0, int nVersion=VERSION)  \
+     void Unserialize(Stream& s, int nType, int nVersion)  \
      {                                           \
          CSerActionUnserialize ser_action;       \
          const bool fGetSize = false;            \
          const bool fWrite = false;              \
          const bool fRead = true;                \
          unsigned int nSerSize = 0;              \
+         assert(fGetSize||fWrite||fRead); /* suppress warning */ \
          {statements}                            \
      }
  
@@@ -189,14 -155,8 +156,14 @@@ template<typename Stream> inline void U
  
  
  
 -
 -
 +#ifndef THROW_WITH_STACKTRACE
 +#define THROW_WITH_STACKTRACE(exception)  \
 +{                                         \
 +    LogStackTrace();                      \
 +    throw (exception);                    \
 +}
 +void LogStackTrace();
 +#endif
  
  //
  // Compact size
  inline unsigned int GetSizeOfCompactSize(uint64 nSize)
  {
      if (nSize < 253)             return sizeof(unsigned char);
-     else if (nSize <= USHRT_MAX) return sizeof(unsigned char) + sizeof(unsigned short);
-     else if (nSize <= UINT_MAX)  return sizeof(unsigned char) + sizeof(unsigned int);
+     else if (nSize <= std::numeric_limits<unsigned short>::max()) return sizeof(unsigned char) + sizeof(unsigned short);
+     else if (nSize <= std::numeric_limits<unsigned int>::max())  return sizeof(unsigned char) + sizeof(unsigned int);
      else                         return sizeof(unsigned char) + sizeof(uint64);
  }
  
@@@ -221,14 -181,14 +188,14 @@@ void WriteCompactSize(Stream& os, uint6
          unsigned char chSize = nSize;
          WRITEDATA(os, chSize);
      }
-     else if (nSize <= USHRT_MAX)
+     else if (nSize <= std::numeric_limits<unsigned short>::max())
      {
          unsigned char chSize = 253;
          unsigned short xSize = nSize;
          WRITEDATA(os, chSize);
          WRITEDATA(os, xSize);
      }
-     else if (nSize <= UINT_MAX)
+     else if (nSize <= std::numeric_limits<unsigned int>::max())
      {
          unsigned char chSize = 254;
          unsigned int xSize = nSize;
@@@ -274,17 -234,17 +241,17 @@@ uint64 ReadCompactSize(Stream& is
          nSizeRet = xSize;
      }
      if (nSizeRet > (uint64)MAX_SIZE)
 -        throw std::ios_base::failure("ReadCompactSize() : size too large");
 +        THROW_WITH_STACKTRACE(std::ios_base::failure("ReadCompactSize() : size too large"));
      return nSizeRet;
  }
  
  
  
- //
- // Wrapper for serializing arrays and POD
- // There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it
- //
  #define FLATDATA(obj)   REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
+ /** Wrapper for serializing arrays and POD.
+  * There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it.
+  */
  class CFlatData
  {
  protected:
@@@ -315,50 -275,6 +282,6 @@@ public
      }
  };
  
- //
- // string stored as a fixed length field
- //
- template<std::size_t LEN>
- class CFixedFieldString
- {
- protected:
-     const std::string* pcstr;
-     std::string* pstr;
- public:
-     explicit CFixedFieldString(const std::string& str) : pcstr(&str), pstr(NULL) { }
-     explicit CFixedFieldString(std::string& str) : pcstr(&str), pstr(&str) { }
-     unsigned int GetSerializeSize(int, int=0) const
-     {
-         return LEN;
-     }
-     template<typename Stream>
-     void Serialize(Stream& s, int, int=0) const
-     {
-         char pszBuf[LEN];
-         strncpy(pszBuf, pcstr->c_str(), LEN);
-         s.write(pszBuf, LEN);
-     }
-     template<typename Stream>
-     void Unserialize(Stream& s, int, int=0)
-     {
-         if (pstr == NULL)
-             THROW_WITH_STACKTRACE(std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string"));
-         char pszBuf[LEN+1];
-         s.read(pszBuf, LEN);
-         pszBuf[LEN] = '\0';
-         *pstr = pszBuf;
-     }
- };
  //
  // Forward declarations
  //
@@@ -371,43 -287,43 +294,43 @@@ template<typename Stream, typename C> v
  // vector
  template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
  template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
- template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion=VERSION);
+ template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion);
  template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
  template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
- template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion=VERSION);
+ template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion);
  template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
  template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
- template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion=VERSION);
+ template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion);
  
  // others derived from vector
- extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=VERSION);
- template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion=VERSION);
- template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion=VERSION);
+ extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion);
+ template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion);
+ template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion);
  
  // pair
- template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion=VERSION);
- template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion=VERSION);
- template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion=VERSION);
+ template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion);
+ template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion);
+ template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion);
  
  // 3 tuple
- template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=VERSION);
- template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=VERSION);
- template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion=VERSION);
+ template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
+ template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
+ template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion);
  
  // 4 tuple
- template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=VERSION);
- template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=VERSION);
- template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=VERSION);
+ template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
+ template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
+ template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion);
  
  // map
- template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion=VERSION);
- template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion=VERSION);
- template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion=VERSION);
+ template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion);
+ template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion);
+ template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion);
  
  // set
- template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion=VERSION);
- template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion=VERSION);
- template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion=VERSION);
+ template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion);
+ template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion);
+ template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion);
  
  
  
  // Thanks to Boost serialization for this idea.
  //
  template<typename T>
- inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=VERSION)
+ inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion)
  {
      return a.GetSerializeSize((int)nType, nVersion);
  }
  
  template<typename Stream, typename T>
- inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION)
+ inline void Serialize(Stream& os, const T& a, long nType, int nVersion)
  {
      a.Serialize(os, (int)nType, nVersion);
  }
  
  template<typename Stream, typename T>
- inline void Unserialize(Stream& is, T& a, long nType, int nVersion=VERSION)
+ inline void Unserialize(Stream& is, T& a, long nType, int nVersion)
  {
      a.Unserialize(is, (int)nType, nVersion);
  }
@@@ -520,10 -436,6 +443,6 @@@ inline void Serialize(Stream& os, cons
  template<typename Stream, typename T, typename A>
  void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
  {
-     //unsigned int nSize = ReadCompactSize(is);
-     //v.resize(nSize);
-     //is.read((char*)&v[0], nSize * sizeof(T));
      // Limit size per read so bogus size value won't cause out of memory
      v.clear();
      unsigned int nSize = ReadCompactSize(is);
  template<typename Stream, typename T, typename A>
  void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
  {
-     //unsigned int nSize = ReadCompactSize(is);
-     //v.resize(nSize);
-     //for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi)
-     //    Unserialize(is, (*vi), nType, nVersion);
      v.clear();
      unsigned int nSize = ReadCompactSize(is);
      unsigned int i = 0;
@@@ -793,61 -700,18 +707,18 @@@ struct ser_streamplaceholde
  
  
  
  
  
  
- //
- // Double ended buffer combining vector and stream-like interfaces.
- // >> and << read and write unformatted data using the above serialization templates.
- // Fills with data in linear time; some stringstream implementations take N^2 time.
- //
+ /** Double ended buffer combining vector and stream-like interfaces.
+  *
+  * >> and << read and write unformatted data using the above serialization templates.
+  * Fills with data in linear time; some stringstream implementations take N^2 time.
+  */
  class CDataStream
  {
  protected:
-     typedef std::vector<char, secure_allocator<char> > vector_type;
+     typedef std::vector<char, zero_after_free_allocator<char> > vector_type;
      vector_type vch;
      unsigned int nReadPos;
      short state;
@@@ -866,39 -730,39 +737,39 @@@ public
      typedef vector_type::const_iterator   const_iterator;
      typedef vector_type::reverse_iterator reverse_iterator;
  
-     explicit CDataStream(int nTypeIn=SER_NETWORK, int nVersionIn=VERSION)
+     explicit CDataStream(int nTypeIn, int nVersionIn)
      {
          Init(nTypeIn, nVersionIn);
      }
  
-     CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch(pbegin, pend)
+     CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
      {
          Init(nTypeIn, nVersionIn);
      }
  
  #if !defined(_MSC_VER) || _MSC_VER >= 1300
-     CDataStream(const char* pbegin, const char* pend, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch(pbegin, pend)
+     CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend)
      {
          Init(nTypeIn, nVersionIn);
      }
  #endif
  
-     CDataStream(const vector_type& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end())
+     CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
      {
          Init(nTypeIn, nVersionIn);
      }
  
-     CDataStream(const std::vector<char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end())
+     CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end())
      {
          Init(nTypeIn, nVersionIn);
      }
  
-     CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
+     CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
      {
          Init(nTypeIn, nVersionIn);
      }
  
-     void Init(int nTypeIn=SER_NETWORK, int nVersionIn=VERSION)
+     void Init(int nTypeIn, int nVersionIn)
      {
          nReadPos = 0;
          nType = nTypeIn;
      {
          state |= bits;
          if (state & exceptmask)
 -            throw std::ios_base::failure(psz);
 +            THROW_WITH_STACKTRACE(std::ios_base::failure(psz));
      }
  
      bool eof() const             { return size() == 0; }
      }
  
      template<typename Stream>
-     void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
+     void Serialize(Stream& s, int nType, int nVersion) const
      {
          // Special case: stream << stream concatenates like stream += stream
          if (!vch.empty())
@@@ -1203,12 -1067,12 +1074,12 @@@ int main(int argc, char *argv[]
  
  
  
- //
- // Automatic closing wrapper for FILE*
- //  - Will automatically close the file when it goes out of scope if not null.
- //  - If you're returning the file pointer, return file.release().
- //  - If you need to close the file early, use file.fclose() instead of fclose(file).
- //
+ /** RAII wrapper for FILE*.
+  *
+  * Will automatically close the file when it goes out of scope if not null.
+  * If you're returning the file pointer, return file.release().
+  * If you need to close the file early, use file.fclose() instead of fclose(file).
+  */
  class CAutoFile
  {
  protected:
@@@ -1219,9 -1083,7 +1090,7 @@@ public
      int nType;
      int nVersion;
  
-     typedef FILE element_type;
-     CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=VERSION)
+     CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn)
      {
          file = filenew;
          nType = nTypeIn;
      {
          state |= bits;
          if (state & exceptmask)
 -            throw std::ios_base::failure(psz);
 +            THROW_WITH_STACKTRACE(std::ios_base::failure(psz));
      }
  
      bool fail() const            { return state & (std::ios::badbit | std::ios::failbit); }
      void ReadVersion()           { *this >> nVersion; }
      void WriteVersion()          { *this << nVersion; }
  
-     CAutoFile& read(char* pch, int nSize)
+     CAutoFile& read(char* pch, size_t nSize)
      {
          if (!file)
              throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
          return (*this);
      }
  
-     CAutoFile& write(const char* pch, int nSize)
+     CAutoFile& write(const char* pch, size_t nSize)
      {
          if (!file)
              throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
diff --combined src/util.cpp
@@@ -1,10 -1,24 +1,25 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
- #include "headers.h"
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
+ #include "util.h"
  #include "strlcpy.h"
+ #include "version.h"
+ #include "ui_interface.h"
+ #include <boost/algorithm/string/join.hpp>
+ // Work around clang compilation problem in Boost 1.46:
+ // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
+ // See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
+ //           http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
+ namespace boost {
+     namespace program_options {
+         std::string to_internal(const std::string&);
+     }
+ }
  #include <boost/program_options/detail/config_file.hpp>
  #include <boost/program_options/parsers.hpp>
  #include <boost/filesystem.hpp>
  #include <boost/interprocess/sync/interprocess_mutex.hpp>
  #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
  #include <boost/foreach.hpp>
+ #include <boost/thread.hpp>
+ #include <openssl/crypto.h>
+ #include <openssl/rand.h>
+ #ifdef WIN32
+ #ifdef _MSC_VER
+ #pragma warning(disable:4786)
+ #pragma warning(disable:4804)
+ #pragma warning(disable:4805)
+ #pragma warning(disable:4717)
+ #endif
+ #ifdef _WIN32_WINNT
+ #undef _WIN32_WINNT
+ #endif
+ #define _WIN32_WINNT 0x0501
+ #ifdef _WIN32_IE
+ #undef _WIN32_IE
+ #endif
+ #define _WIN32_IE 0x0400
+ #define WIN32_LEAN_AND_MEAN 1
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+ #include "shlobj.h"
+ #include "shlwapi.h"
+ #endif
  
 +#ifndef WIN32
 +#include <execinfo.h>
 +#endif
 +
  using namespace std;
  using namespace boost;
  
@@@ -25,7 -61,6 +66,6 @@@ map<string, vector<string> > mapMultiAr
  bool fDebug = false;
  bool fPrintToConsole = false;
  bool fPrintToDebugger = false;
- char pszSetDataDir[MAX_PATH] = "";
  bool fRequestShutdown = false;
  bool fShutdown = false;
  bool fDaemon = false;
@@@ -35,17 -70,7 +75,7 @@@ string strMiscWarning
  bool fTestNet = false;
  bool fNoListen = false;
  bool fLogTimestamps = false;
- // Workaround for "multiple definition of `_tls_used'"
- // http://svn.boost.org/trac/boost/ticket/4258
- extern "C" void tss_cleanup_implemented() { }
+ CMedianFilter<int64> vTimeOffsets(200,0);
  
  // Init openssl library multithreading support
  static boost::interprocess::interprocess_mutex** ppmutexOpenSSL;
@@@ -137,7 -162,7 +167,7 @@@ uint64 GetRand(uint64 nMax
  
      // The range of the random source must be a multiple of the modulus
      // to give every possible output value an equal possibility
-     uint64 nRange = (UINT64_MAX / nMax) * nMax;
+     uint64 nRange = (std::numeric_limits<uint64>::max() / nMax) * nMax;
      uint64 nRand = 0;
      do
          RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
@@@ -150,6 -175,12 +180,12 @@@ int GetRandInt(int nMax
      return GetRand(nMax);
  }
  
+ uint256 GetRandHash()
+ {
+     uint256 hash;
+     RAND_bytes((unsigned char*)&hash, sizeof(hash));
+     return hash;
+ }
  
  
  
  
  
  
 -
 +static FILE* fileout = NULL;
  
  inline int OutputDebugStringF(const char* pszFormat, ...)
  {
      else
      {
          // print to debug.log
 -        static FILE* fileout = NULL;
 -
          if (!fileout)
          {
-             char pszFile[MAX_PATH+100];
-             GetDataDir(pszFile);
-             strlcat(pszFile, "/debug.log", sizeof(pszFile));
-             fileout = fopen(pszFile, "a");
+             boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
+             fileout = fopen(pathDebug.string().c_str(), "a");
              if (fileout) setbuf(fileout, NULL); // unbuffered
          }
          if (fileout)
          {
              static bool fStartedNewLine = true;
+             static boost::mutex mutexDebugLog;
+             boost::mutex::scoped_lock scoped_lock(mutexDebugLog);
  
              // Debug print useful for profiling
              if (fLogTimestamps && fStartedNewLine)
          static CCriticalSection cs_OutputDebugStringF;
  
          // accumulate a line at a time
-         CRITICAL_BLOCK(cs_OutputDebugStringF)
          {
+             LOCK(cs_OutputDebugStringF);
              static char pszBuffer[50000];
              static char* pend;
              if (pend == NULL)
              *pend = '\0';
              char* p1 = pszBuffer;
              char* p2;
-             while (p2 = strchr(p1, '\n'))
+             while ((p2 = strchr(p1, '\n')))
              {
                  p2++;
                  char c = *p2;
@@@ -259,7 -292,7 +295,7 @@@ int my_snprintf(char* buffer, size_t li
      va_start(arg_ptr, format);
      int ret = _vsnprintf(buffer, limit, format, arg_ptr);
      va_end(arg_ptr);
-     if (ret < 0 || ret >= limit)
+     if (ret < 0 || ret >= (int)limit)
      {
          ret = limit - 1;
          buffer[limit-1] = 0;
      return ret;
  }
  
- string strprintf(const std::string &format, ...)
+ string real_strprintf(const std::string &format, int dummy, ...)
  {
      char buffer[50000];
      char* p = buffer;
      loop
      {
          va_list arg_ptr;
-         va_start(arg_ptr, format);
+         va_start(arg_ptr, dummy);
          ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
          va_end(arg_ptr);
          if (ret >= 0 && ret < limit)
      return str;
  }
  
- bool error(const std::string &format, ...)
+ bool error(const char *format, ...)
  {
      char buffer[50000];
      int limit = sizeof(buffer);
      va_list arg_ptr;
      va_start(arg_ptr, format);
-     int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
+     int ret = _vsnprintf(buffer, limit, format, arg_ptr);
      va_end(arg_ptr);
      if (ret < 0 || ret >= limit)
      {
-         ret = limit - 1;
          buffer[limit-1] = 0;
      }
      printf("ERROR: %s\n", buffer);
@@@ -339,7 -371,7 +374,7 @@@ string FormatMoney(int64 n, bool fPlus
      int64 n_abs = (n > 0 ? n : -n);
      int64 quotient = n_abs/COIN;
      int64 remainder = n_abs%COIN;
 -    string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder);
 +    string str = strprintf("%"PRI64d".%06"PRI64d, quotient, remainder);
  
      // Right-trim excess 0's before the decimal point:
      int nTrim = 0;
@@@ -402,38 -434,48 +437,48 @@@ bool ParseMoney(const char* pszIn, int6
  }
  
  
- vector<unsigned char> ParseHex(const char* psz)
+ static signed char phexdigit[256] =
+ { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
+   -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
+ bool IsHex(const string& str)
  {
-     static char phexdigit[256] =
-     { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
-       -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
+     BOOST_FOREACH(unsigned char c, str)
+     {
+         if (phexdigit[c] < 0)
+             return false;
+     }
+     return (str.size() > 0) && (str.size()%2 == 0);
+ }
  
+ vector<unsigned char> ParseHex(const char* psz)
+ {
      // convert hex dump to vector
      vector<unsigned char> vch;
      loop
      {
          while (isspace(*psz))
              psz++;
-         char c = phexdigit[(unsigned char)*psz++];
-         if (c == (char)-1)
+         signed char c = phexdigit[(unsigned char)*psz++];
+         if (c == (signed char)-1)
              break;
          unsigned char n = (c << 4);
          c = phexdigit[(unsigned char)*psz++];
-         if (c == (char)-1)
+         if (c == (signed char)-1)
              break;
          n |= c;
          vch.push_back(n);
@@@ -446,7 -488,22 +491,22 @@@ vector<unsigned char> ParseHex(const st
      return ParseHex(str.c_str());
  }
  
- void ParseParameters(int argc, char* argv[])
+ static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
+ {
+     // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
+     if (name.find("-no") == 0)
+     {
+         std::string positive("-");
+         positive.append(name.begin()+3, name.end());
+         if (mapSettingsRet.count(positive) == 0)
+         {
+             bool value = !GetBoolArg(name);
+             mapSettingsRet[positive] = (value ? "1" : "0");
+         }
+     }
+ }
+ void ParseParameters(int argc, const char*const argv[])
  {
      mapArgs.clear();
      mapMultiArgs.clear();
          #endif
          if (psz[0] != '-')
              break;
          mapArgs[psz] = pszValue;
          mapMultiArgs[psz].push_back(pszValue);
      }
+     // New 0.6 features:
+     BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
+     {
+         string name = entry.first;
+         //  interpret --foo as -foo (as long as both are not set)
+         if (name.find("--") == 0)
+         {
+             std::string singleDash(name.begin()+1, name.end());
+             if (mapArgs.count(singleDash) == 0)
+                 mapArgs[singleDash] = entry.second;
+             name = singleDash;
+         }
+         // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
+         InterpretNegativeSetting(name, mapArgs);
+     }
  }
  
+ std::string GetArg(const std::string& strArg, const std::string& strDefault)
+ {
+     if (mapArgs.count(strArg))
+         return mapArgs[strArg];
+     return strDefault;
+ }
+ int64 GetArg(const std::string& strArg, int64 nDefault)
+ {
+     if (mapArgs.count(strArg))
+         return atoi64(mapArgs[strArg]);
+     return nDefault;
+ }
+ bool GetBoolArg(const std::string& strArg, bool fDefault)
+ {
+     if (mapArgs.count(strArg))
+     {
+         if (mapArgs[strArg].empty())
+             return true;
+         return (atoi(mapArgs[strArg]) != 0);
+     }
+     return fDefault;
+ }
+ bool SoftSetArg(const std::string& strArg, const std::string& strValue)
+ {
+     if (mapArgs.count(strArg))
+         return false;
+     mapArgs[strArg] = strValue;
+     return true;
+ }
+ bool SoftSetBoolArg(const std::string& strArg, bool fValue)
+ {
+     if (fValue)
+         return SoftSetArg(strArg, std::string("1"));
+     else
+         return SoftSetArg(strArg, std::string("0"));
+ }
  string EncodeBase64(const unsigned char* pch, size_t len)
  {
      static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@@ -553,7 -671,7 +674,7 @@@ vector<unsigned char> DecodeBase64(cons
  
      while (1)
      {
-          int dec = decode64_table[*p];
+          int dec = decode64_table[(unsigned char)*p];
           if (dec == -1) break;
           p++;
           switch (mode)
                  break;
  
              case 2: // 4n+2 base64 characters processed: require '=='
-                 if (left || p[0] != '=' || p[1] != '=' || decode64_table[p[2]] != -1)
+                 if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1)
                      *pfInvalid = true;
                  break;
  
              case 3: // 4n+3 base64 characters processed: require '='
-                 if (left || p[0] != '=' || decode64_table[p[1]] != -1)
+                 if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1)
                      *pfInvalid = true;
                  break;
          }
@@@ -683,30 -801,6 +804,19 @@@ void PrintException(std::exception* pex
      throw;
  }
  
 +void LogStackTrace() {
 +    printf("\n\n******* exception encountered *******\n");
 +    if (fileout)
 +    {
 +#ifndef WIN32
 +        void* pszBuffer[32];
 +        size_t size;
 +        size = backtrace(pszBuffer, 32);
 +        backtrace_symbols_fd(pszBuffer, size, fileno(fileout));
 +#endif
 +    }
 +}
 +
- void ThreadOneMessageBox(string strMessage)
- {
-     // Skip message boxes if one is already open
-     static bool fMessageBoxOpen;
-     if (fMessageBoxOpen)
-         return;
-     fMessageBoxOpen = true;
-     ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
-     fMessageBoxOpen = false;
- }
  void PrintExceptionContinue(std::exception* pex, const char* pszThread)
  {
      char pszMessage[10000];
      strMiscWarning = pszMessage;
  }
  
  #ifdef WIN32
- typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
- string MyGetSpecialFolderPath(int nFolder, bool fCreate)
+ boost::filesystem::path MyGetSpecialFolderPath(int nFolder, bool fCreate)
  {
-     char pszPath[MAX_PATH+100] = "";
+     namespace fs = boost::filesystem;
  
-     // SHGetSpecialFolderPath isn't always available on old Windows versions
-     HMODULE hShell32 = LoadLibraryA("shell32.dll");
-     if (hShell32)
+     char pszPath[MAX_PATH] = "";
+     if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
      {
-         PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
-             (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
-         if (pSHGetSpecialFolderPath)
-             (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
-         FreeModule(hShell32);
+         return fs::path(pszPath);
      }
-     // Backup option
-     if (pszPath[0] == '\0')
+     else if (nFolder == CSIDL_STARTUP)
      {
-         if (nFolder == CSIDL_STARTUP)
-         {
-             strcpy(pszPath, getenv("USERPROFILE"));
-             strcat(pszPath, "\\Start Menu\\Programs\\Startup");
-         }
-         else if (nFolder == CSIDL_APPDATA)
-         {
-             strcpy(pszPath, getenv("APPDATA"));
-         }
+         return fs::path(getenv("USERPROFILE")) / "Start Menu" / "Programs" / "Startup";
      }
-     return pszPath;
+     else if (nFolder == CSIDL_APPDATA)
+     {
+         return fs::path(getenv("APPDATA"));
+     }
+     return fs::path("");
  }
  #endif
  
- string GetDefaultDataDir()
+ boost::filesystem::path GetDefaultDataDir()
  {
+     namespace fs = boost::filesystem;
 -    // Windows: C:\Documents and Settings\username\Application Data\Bitcoin
 -    // Mac: ~/Library/Application Support/Bitcoin
 -    // Unix: ~/.bitcoin
 +    // Windows: C:\Documents and Settings\username\Application Data\PPCoin
 +    // Mac: ~/Library/Application Support/PPCoin
 +    // Unix: ~/.ppcoin
  #ifdef WIN32
      // Windows
-     return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\PPCoin";
 -    return MyGetSpecialFolderPath(CSIDL_APPDATA, true) / "Bitcoin";
++    return MyGetSpecialFolderPath(CSIDL_APPDATA, true) / "PPCoin";
  #else
+     fs::path pathRet;
      char* pszHome = getenv("HOME");
      if (pszHome == NULL || strlen(pszHome) == 0)
-         pszHome = (char*)"/";
-     string strHome = pszHome;
-     if (strHome[strHome.size()-1] != '/')
-         strHome += '/';
+         pathRet = fs::path("/");
+     else
+         pathRet = fs::path(pszHome);
  #ifdef MAC_OSX
      // Mac
-     strHome += "Library/Application Support/";
-     filesystem::create_directory(strHome.c_str());
-     return strHome + "PPCoin";
+     pathRet /= "Library/Application Support";
+     fs::create_directory(pathRet);
 -    return pathRet / "Bitcoin";
++    return pathRet / "PPCoin";
  #else
      // Unix
-     return strHome + ".ppcoin";
 -    return pathRet / ".bitcoin";
++    return pathRet / ".ppcoin";
  #endif
  #endif
  }
  
- void GetDataDir(char* pszDir)
+ const boost::filesystem::path &GetDataDir(bool fNetSpecific)
  {
-     // pszDir must be at least MAX_PATH length.
-     int nVariation;
-     if (pszSetDataDir[0] != 0)
-     {
-         strlcpy(pszDir, pszSetDataDir, MAX_PATH);
-         nVariation = 0;
-     }
-     else
-     {
-         // This can be called during exceptions by printf, so we cache the
-         // value so we don't have to do memory allocations after that.
-         static char pszCachedDir[MAX_PATH];
-         if (pszCachedDir[0] == 0)
-             strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
-         strlcpy(pszDir, pszCachedDir, MAX_PATH);
-         nVariation = 1;
-     }
-     if (fTestNet)
-     {
-         char* p = pszDir + strlen(pszDir);
-         if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
-             *p++ = '/';
-         strcpy(p, "testnet");
-         nVariation += 2;
-     }
-     static bool pfMkdir[4];
-     if (!pfMkdir[nVariation])
-     {
-         pfMkdir[nVariation] = true;
-         boost::filesystem::create_directory(pszDir);
+     namespace fs = boost::filesystem;
+     static fs::path pathCached[2];
+     static CCriticalSection csPathCached;
+     static bool cachedPath[2] = {false, false};
+     fs::path &path = pathCached[fNetSpecific];
+     // This can be called during exceptions by printf, so we cache the
+     // value so we don't have to do memory allocations after that.
+     if (cachedPath[fNetSpecific])
+         return path;
+     LOCK(csPathCached);
+     if (mapArgs.count("-datadir")) {
+         path = fs::system_complete(mapArgs["-datadir"]);
+         if (!fs::is_directory(path)) {
+             path = "";
+             return path;
+         }
+     } else {
+         path = GetDefaultDataDir();
      }
- }
+     if (fNetSpecific && GetBoolArg("-testnet", false))
+         path /= "testnet";
  
- string GetDataDir()
- {
-     char pszDir[MAX_PATH];
-     GetDataDir(pszDir);
-     return pszDir;
+     fs::create_directory(path);
+     cachedPath[fNetSpecific]=true;
+     return path;
  }
  
- string GetConfigFile()
+ boost::filesystem::path GetConfigFile()
  {
      namespace fs = boost::filesystem;
-     fs::path pathConfig(GetArg("-conf", "ppcoin.conf"));
-     if (!pathConfig.is_complete())
-         pathConfig = fs::path(GetDataDir()) / pathConfig;
-     return pathConfig.string();
 -    fs::path pathConfigFile(GetArg("-conf", "bitcoin.conf"));
++    fs::path pathConfigFile(GetArg("-conf", "ppcoin.conf"));
+     if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile;
+     return pathConfigFile;
  }
  
  void ReadConfigFile(map<string, string>& mapSettingsRet,
  
      fs::ifstream streamConfig(GetConfigFile());
      if (!streamConfig.good())
-         return;
+         return; // No bitcoin.conf file is OK
  
      set<string> setOptions;
      setOptions.insert("*");
-     
      for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
      {
          // Don't overwrite existing settings so command line settings override bitcoin.conf
          string strKey = string("-") + it->string_key;
          if (mapSettingsRet.count(strKey) == 0)
+         {
              mapSettingsRet[strKey] = it->value[0];
+             //  interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
+             InterpretNegativeSetting(strKey, mapSettingsRet);
+         }
          mapMultiSettingsRet[strKey].push_back(it->value[0]);
      }
  }
  
- string GetPidFile()
+ boost::filesystem::path GetPidFile()
  {
      namespace fs = boost::filesystem;
-     fs::path pathConfig(GetArg("-pid", "ppcoind.pid"));
-     if (!pathConfig.is_complete())
-         pathConfig = fs::path(GetDataDir()) / pathConfig;
-     return pathConfig.string();
 -    fs::path pathPidFile(GetArg("-pid", "bitcoind.pid"));
++    fs::path pathPidFile(GetArg("-pid", "ppcoind.pid"));
+     if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
+     return pathPidFile;
  }
  
- void CreatePidFile(string pidFile, pid_t pid)
+ void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
  {
-     FILE* file = fopen(pidFile.c_str(), "w");
+     FILE* file = fopen(path.string().c_str(), "w");
      if (file)
      {
          fprintf(file, "%d\n", pid);
@@@ -892,8 -964,8 +980,8 @@@ int GetFilesize(FILE* file
  void ShrinkDebugFile()
  {
      // Scroll debug.log if it's getting too big
-     string strFile = GetDataDir() + "/debug.log";
-     FILE* file = fopen(strFile.c_str(), "r");
+     boost::filesystem::path pathLog = GetDataDir() / "debug.log";
+     FILE* file = fopen(pathLog.string().c_str(), "r");
      if (file && GetFilesize(file) > 10 * 1000000)
      {
          // Restart the file with some of the end
          int nBytes = fread(pch, 1, sizeof(pch), file);
          fclose(file);
  
-         file = fopen(strFile.c_str(), "w");
+         file = fopen(pathLog.string().c_str(), "w");
          if (file)
          {
              fwrite(pch, 1, nBytes, file);
@@@ -946,25 -1018,22 +1034,22 @@@ int64 GetAdjustedTime(
      return GetTime() + nTimeOffset;
  }
  
- void AddTimeData(unsigned int ip, int64 nTime)
+ void AddTimeData(const CNetAddr& ip, int64 nTime)
  {
      int64 nOffsetSample = nTime - GetTime();
  
      // Ignore duplicates
-     static set<unsigned int> setKnown;
+     static set<CNetAddr> setKnown;
      if (!setKnown.insert(ip).second)
          return;
  
      // Add data
-     static vector<int64> vTimeOffsets;
-     if (vTimeOffsets.empty())
-         vTimeOffsets.push_back(0);
-     vTimeOffsets.push_back(nOffsetSample);
-     printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
+     vTimeOffsets.input(nOffsetSample);
+     printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
      if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
      {
-         sort(vTimeOffsets.begin(), vTimeOffsets.end());
-         int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
+         int64 nMedian = vTimeOffsets.median();
+         std::vector<int64> vSorted = vTimeOffsets.sorted();
          // Only let other nodes change our time by so much
          if (abs64(nMedian) < 70 * 60)
          {
              {
                  // If nobody has a time different than ours but within 5 minutes of ours, give a warning
                  bool fMatch = false;
-                 BOOST_FOREACH(int64 nOffset, vTimeOffsets)
+                 BOOST_FOREACH(int64 nOffset, vSorted)
                      if (nOffset != 0 && abs64(nOffset) < 5 * 60)
                          fMatch = true;
  
                      string strMessage = _("Warning: Please check that your computer's date and time are correct.  If your clock is wrong Bitcoin will not work properly.");
                      strMiscWarning = strMessage;
                      printf("*** %s\n", strMessage.c_str());
-                     boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
+                     ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION);
                  }
              }
          }
-         BOOST_FOREACH(int64 n, vTimeOffsets)
-             printf("%+"PRI64d"  ", n);
-         printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
+         if (fDebug) {
+             BOOST_FOREACH(int64 n, vSorted)
+                 printf("%+"PRI64d"  ", n);
+             printf("|  ");
+         }
+         printf("nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
      }
  }
  
  
  
  
  string FormatVersion(int nVersion)
  {
      if (nVersion%100 == 0)
  
  string FormatFullVersion()
  {
-     string s = FormatVersion(PPCOIN_VERSION) + pszSubVer;
-     if (VERSION_IS_BETA) {
-         s += "-";
-         s += _("beta");
+     return CLIENT_BUILD;
+ }
+ // Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
+ std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
+ {
+     std::ostringstream ss;
+     ss << "/";
+     ss << name << ":" << FormatVersion(nClientVersion);
+     if (!comments.empty())
+         ss << "(" << boost::algorithm::join(comments, "; ") << ")";
+     ss << "/";
+     return ss.str();
+ }
+ #ifdef WIN32
+ boost::filesystem::path static StartupShortcutPath()
+ {
+     return MyGetSpecialFolderPath(CSIDL_STARTUP, true) / "Bitcoin.lnk";
+ }
+ bool GetStartOnSystemStartup()
+ {
+     return filesystem::exists(StartupShortcutPath());
+ }
+ bool SetStartOnSystemStartup(bool fAutoStart)
+ {
+     // If the shortcut exists already, remove it for updating
+     boost::filesystem::remove(StartupShortcutPath());
+     if (fAutoStart)
+     {
+         CoInitialize(NULL);
+         // Get a pointer to the IShellLink interface.
+         IShellLink* psl = NULL;
+         HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
+                                 CLSCTX_INPROC_SERVER, IID_IShellLink,
+                                 reinterpret_cast<void**>(&psl));
+         if (SUCCEEDED(hres))
+         {
+             // Get the current executable path
+             TCHAR pszExePath[MAX_PATH];
+             GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
+             TCHAR pszArgs[5] = TEXT("-min");
+             // Set the path to the shortcut target
+             psl->SetPath(pszExePath);
+             PathRemoveFileSpec(pszExePath);
+             psl->SetWorkingDirectory(pszExePath);
+             psl->SetShowCmd(SW_SHOWMINNOACTIVE);
+             psl->SetArguments(pszArgs);
+             // Query IShellLink for the IPersistFile interface for
+             // saving the shortcut in persistent storage.
+             IPersistFile* ppf = NULL;
+             hres = psl->QueryInterface(IID_IPersistFile,
+                                        reinterpret_cast<void**>(&ppf));
+             if (SUCCEEDED(hres))
+             {
+                 WCHAR pwsz[MAX_PATH];
+                 // Ensure that the string is ANSI.
+                 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH);
+                 // Save the link by calling IPersistFile::Save.
+                 hres = ppf->Save(pwsz, TRUE);
+                 ppf->Release();
+                 psl->Release();
+                 CoUninitialize();
+                 return true;
+             }
+             psl->Release();
+         }
+         CoUninitialize();
+         return false;
+     }
+     return true;
+ }
+ #elif defined(LINUX)
+ // Follow the Desktop Application Autostart Spec:
+ //  http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
+ boost::filesystem::path static GetAutostartDir()
+ {
+     namespace fs = boost::filesystem;
+     char* pszConfigHome = getenv("XDG_CONFIG_HOME");
+     if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
+     char* pszHome = getenv("HOME");
+     if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
+     return fs::path();
+ }
+ boost::filesystem::path static GetAutostartFilePath()
+ {
+     return GetAutostartDir() / "bitcoin.desktop";
+ }
+ bool GetStartOnSystemStartup()
+ {
+     boost::filesystem::ifstream optionFile(GetAutostartFilePath());
+     if (!optionFile.good())
+         return false;
+     // Scan through file for "Hidden=true":
+     string line;
+     while (!optionFile.eof())
+     {
+         getline(optionFile, line);
+         if (line.find("Hidden") != string::npos &&
+             line.find("true") != string::npos)
+             return false;
++>>>>>>> bitcoin
      }
-     return s;
+     optionFile.close();
+     return true;
  }
  
+ bool SetStartOnSystemStartup(bool fAutoStart)
+ {
+     if (!fAutoStart)
+         boost::filesystem::remove(GetAutostartFilePath());
+     else
+     {
+         char pszExePath[MAX_PATH+1];
+         memset(pszExePath, 0, sizeof(pszExePath));
+         if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
+             return false;
+         boost::filesystem::create_directories(GetAutostartDir());
+         boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
+         if (!optionFile.good())
+             return false;
+         // Write a bitcoin.desktop file to the autostart directory:
+         optionFile << "[Desktop Entry]\n";
+         optionFile << "Type=Application\n";
+         optionFile << "Name=Bitcoin\n";
+         optionFile << "Exec=" << pszExePath << " -min\n";
+         optionFile << "Terminal=false\n";
+         optionFile << "Hidden=false\n";
+         optionFile.close();
+     }
+     return true;
+ }
+ #else
+ // TODO: OSX startup stuff; see:
+ // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
+ bool GetStartOnSystemStartup() { return false; }
+ bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
+ #endif
  
  
  
@@@ -1060,25 -1280,25 +1297,25 @@@ private
      int sourceLine;
  };
  
- typedef std::vector< std::pair<CCriticalSection*, CLockLocation> > LockStack;
+ typedef std::vector< std::pair<void*, CLockLocation> > LockStack;
  
  static boost::interprocess::interprocess_mutex dd_mutex;
- static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders;
+ static std::map<std::pair<void*, void*>, LockStack> lockorders;
  static boost::thread_specific_ptr<LockStack> lockstack;
  
  
- static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2)
+ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
  {
      printf("POTENTIAL DEADLOCK DETECTED\n");
      printf("Previous lock order was:\n");
-     BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2)
+     BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2)
      {
          if (i.first == mismatch.first) printf(" (1)");
          if (i.first == mismatch.second) printf(" (2)");
          printf(" %s\n", i.second.ToString().c_str());
      }
      printf("Current lock order is:\n");
-     BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1)
+     BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1)
      {
          if (i.first == mismatch.first) printf(" (1)");
          if (i.first == mismatch.second) printf(" (2)");
      }
  }
  
- static void push_lock(CCriticalSection* c, const CLockLocation& locklocation)
+ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
  {
      bool fOrderOK = true;
      if (lockstack.get() == NULL)
  
      (*lockstack).push_back(std::make_pair(c, locklocation));
  
-     BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack))
+     if (!fTry) BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack))
      {
          if (i.first == c) break;
  
-         std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c);
+         std::pair<void*, void*> p1 = std::make_pair(i.first, c);
          if (lockorders.count(p1))
              continue;
          lockorders[p1] = (*lockstack);
  
-         std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first);
+         std::pair<void*, void*> p2 = std::make_pair(c, i.first);
          if (lockorders.count(p2))
          {
              potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
@@@ -1128,40 -1348,14 +1365,14 @@@ static void pop_lock(
      dd_mutex.unlock();
  }
  
- void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
+ void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
  {
-     push_lock(this, CLockLocation(pszName, pszFile, nLine));
-     mutex.lock();
- }
- void CCriticalSection::Leave()
- {
-     mutex.unlock();
-     pop_lock();
+     push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
  }
- bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine)
- {
-     push_lock(this, CLockLocation(pszName, pszFile, nLine));
-     bool result = mutex.try_lock();
-     if (!result) pop_lock();
-     return result;
- }
- #else
  
- void CCriticalSection::Enter(const char*, const char*, int)
+ void LeaveCritical()
  {
-     mutex.lock();
- }
- void CCriticalSection::Leave()
- {
-     mutex.unlock();
- }
- bool CCriticalSection::TryEnter(const char*, const char*, int)
- {
-     bool result = mutex.try_lock();
-     return result;
+     pop_lock();
  }
  
  #endif /* DEBUG_LOCKORDER */
diff --combined src/util.h
@@@ -1,8 -1,7 +1,8 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_UTIL_H
  #define BITCOIN_UTIL_H
  
  #include <sys/types.h>
  #include <sys/time.h>
  #include <sys/resource.h>
+ #else
+ typedef int pid_t; /* define for windows compatiblity */
  #endif
  #include <map>
  #include <vector>
  #include <string>
  
  #include <boost/thread.hpp>
+ #include <boost/filesystem.hpp>
+ #include <boost/filesystem/path.hpp>
  #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
+ #include <boost/interprocess/sync/scoped_lock.hpp>
+ #include <boost/interprocess/sync/interprocess_semaphore.hpp>
+ #include <boost/interprocess/sync/lock_options.hpp>
  #include <boost/date_time/gregorian/gregorian_types.hpp>
  #include <boost/date_time/posix_time/posix_time_types.hpp>
  
  #include <openssl/sha.h>
  #include <openssl/ripemd.h>
  
+ #include "netbase.h" // for AddTimeData
  
- #if defined(_MSC_VER) || defined(__BORLANDC__)
- typedef __int64  int64;
- typedef unsigned __int64  uint64;
- #else
  typedef long long  int64;
  typedef unsigned long long  uint64;
- #endif
- #if defined(_MSC_VER) && _MSC_VER < 1300
- #define for  if (false) ; else for
- #endif
- #ifndef _MSC_VER
- #define __forceinline  inline
- #endif
 -static const int64 COIN = 100000000;
 -static const int64 CENT = 1000000;
++static const int64 COIN = 1000000;
++static const int64 CENT = 10000;
  
  #define loop                for (;;)
  #define BEGIN(a)            ((char*)&(a))
@@@ -54,7 -53,7 +54,7 @@@
  #define snprintf my_snprintf
  
  #ifndef PRI64d
- #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MSVCRT__)
+ #if defined(_MSC_VER) || defined(__MSVCRT__)
  #define PRI64d  "I64d"
  #define PRI64u  "I64u"
  #define PRI64x  "I64x"
@@@ -85,69 -84,27 +85,33 @@@ T* alignup(T* p
  #ifdef WIN32
  #define MSG_NOSIGNAL        0
  #define MSG_DONTWAIT        0
- #ifndef UINT64_MAX
- #define UINT64_MAX          _UI64_MAX
- #define INT64_MAX           _I64_MAX
- #define INT64_MIN           _I64_MIN
- #endif
  #ifndef S_IRUSR
  #define S_IRUSR             0400
  #define S_IWUSR             0200
  #endif
  #define unlink              _unlink
- typedef int socklen_t;
  #else
- #define WSAGetLastError()   errno
- #define WSAEINVAL           EINVAL
- #define WSAEALREADY         EALREADY
- #define WSAEWOULDBLOCK      EWOULDBLOCK
- #define WSAEMSGSIZE         EMSGSIZE
- #define WSAEINTR            EINTR
- #define WSAEINPROGRESS      EINPROGRESS
- #define WSAEADDRINUSE       EADDRINUSE
- #define WSAENOTSOCK         EBADF
- #define INVALID_SOCKET      (SOCKET)(~0)
- #define SOCKET_ERROR        -1
- typedef u_int SOCKET;
  #define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
  #define strlwr(psz)         to_lower(psz)
  #define _strlwr(psz)        to_lower(psz)
  #define MAX_PATH            1024
- #define Beep(n1,n2)         (0)
  inline void Sleep(int64 n)
  {
-     boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(n));
- }
- #endif
- inline int myclosesocket(SOCKET& hSocket)
- {
-     if (hSocket == INVALID_SOCKET)
-         return WSAENOTSOCK;
- #ifdef WIN32
-     int ret = closesocket(hSocket);
- #else
-     int ret = close(hSocket);
- #endif
-     hSocket = INVALID_SOCKET;
-     return ret;
- }
- #define closesocket(s)      myclosesocket(s)
- #if !defined(QT_GUI)
- inline const char* _(const char* psz)
- {
-     return psz;
+     /*Boost has a year 2038 problem— if the request sleep time is past epoch+2^31 seconds the sleep returns instantly.
+       So we clamp our sleeps here to 10 years and hope that boost is fixed by 2028.*/
+     boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(n>315576000000LL?315576000000LL:n));
  }
  #endif
  
 -
 -
 +#ifndef THROW_WITH_STACKTRACE
 +#define THROW_WITH_STACKTRACE(exception)  \
 +{                                         \
 +    LogStackTrace();                      \
 +    throw (exception);                    \
 +}
 +void LogStackTrace();
 +#endif
  
  
  
@@@ -159,7 -116,6 +123,6 @@@ extern std::map<std::string, std::vecto
  extern bool fDebug;
  extern bool fPrintToConsole;
  extern bool fPrintToDebugger;
- extern char pszSetDataDir[MAX_PATH];
  extern bool fRequestShutdown;
  extern bool fShutdown;
  extern bool fDaemon;
@@@ -174,8 -130,15 +137,15 @@@ void RandAddSeed()
  void RandAddSeedPerfmon();
  int OutputDebugStringF(const char* pszFormat, ...);
  int my_snprintf(char* buffer, size_t limit, const char* format, ...);
- std::string strprintf(const std::string &format, ...);
- bool error(const std::string &format, ...);
+ /* It is not allowed to use va_start with a pass-by-reference argument.
+    (C++ standard, 18.7, paragraph 3). Use a dummy argument to work around this, and use a
+    macro to keep similar semantics.
+ */
+ std::string real_strprintf(const std::string &format, int dummy, ...);
+ #define strprintf(format, ...) real_strprintf(format, 0, __VA_ARGS__)
+ bool error(const char *format, ...);
  void LogException(std::exception* pex, const char* pszThread);
  void PrintException(std::exception* pex, const char* pszThread);
  void PrintExceptionContinue(std::exception* pex, const char* pszThread);
@@@ -185,33 -148,33 +155,33 @@@ bool ParseMoney(const std::string& str
  bool ParseMoney(const char* pszIn, int64& nRet);
  std::vector<unsigned char> ParseHex(const char* psz);
  std::vector<unsigned char> ParseHex(const std::string& str);
+ bool IsHex(const std::string& str);
  std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
  std::string DecodeBase64(const std::string& str);
  std::string EncodeBase64(const unsigned char* pch, size_t len);
  std::string EncodeBase64(const std::string& str);
- void ParseParameters(int argc, char* argv[]);
- const char* wxGetTranslation(const char* psz);
+ void ParseParameters(int argc, const char*const argv[]);
  bool WildcardMatch(const char* psz, const char* mask);
  bool WildcardMatch(const std::string& str, const std::string& mask);
  int GetFilesize(FILE* file);
- void GetDataDir(char* pszDirRet);
- std::string GetConfigFile();
- std::string GetPidFile();
- void CreatePidFile(std::string pidFile, pid_t pid);
+ boost::filesystem::path GetDefaultDataDir();
+ const boost::filesystem::path &GetDataDir(bool fNetSpecific = true);
+ boost::filesystem::path GetConfigFile();
+ boost::filesystem::path GetPidFile();
+ void CreatePidFile(const boost::filesystem::path &path, pid_t pid);
  void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
- #ifdef WIN32
- std::string MyGetSpecialFolderPath(int nFolder, bool fCreate);
- #endif
- std::string GetDefaultDataDir();
- std::string GetDataDir();
+ bool GetStartOnSystemStartup();
+ bool SetStartOnSystemStartup(bool fAutoStart);
  void ShrinkDebugFile();
  int GetRandInt(int nMax);
  uint64 GetRand(uint64 nMax);
+ uint256 GetRandHash();
  int64 GetTime();
  void SetMockTime(int64 nMockTimeIn);
  int64 GetAdjustedTime();
- void AddTimeData(unsigned int ip, int64 nTime);
  std::string FormatFullVersion();
+ std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
+ void AddTimeData(const CNetAddr& ip, int64 nTime);
  
  
  
  
  
  
+ /** Wrapped boost mutex: supports recursive locking, but no waiting  */
+ typedef boost::interprocess::interprocess_recursive_mutex CCriticalSection;
  
+ /** Wrapped boost mutex: supports waiting but not recursive locking */
+ typedef boost::interprocess::interprocess_mutex CWaitableCriticalSection;
  
- // Wrapper to automatically initialize mutex
- class CCriticalSection
- {
- protected:
-     boost::interprocess::interprocess_recursive_mutex mutex;
- public:
-     explicit CCriticalSection() { }
-     ~CCriticalSection() { }
-     void Enter(const char* pszName, const char* pszFile, int nLine);
-     void Leave();
-     bool TryEnter(const char* pszName, const char* pszFile, int nLine);
- };
+ #ifdef DEBUG_LOCKORDER
+ void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
+ void LeaveCritical();
+ #else
+ void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
+ void static inline LeaveCritical() {}
+ #endif
  
- // Automatically leave critical section when leaving block, needed for exception safety
- class CCriticalBlock
+ /** Wrapper around boost::interprocess::scoped_lock */
+ template<typename Mutex>
+ class CMutexLock
  {
- protected:
-     CCriticalSection* pcs;
+ private:
+     boost::interprocess::scoped_lock<Mutex> lock;
  public:
-     CCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
+     void Enter(const char* pszName, const char* pszFile, int nLine)
      {
-         pcs = &csIn;
-         pcs->Enter(pszName, pszFile, nLine);
+         if (!lock.owns())
+         {
+             EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
+ #ifdef DEBUG_LOCKCONTENTION
+             if (!lock.try_lock())
+             {
+                 printf("LOCKCONTENTION: %s\n", pszName);
+                 printf("Locker: %s:%d\n", pszFile, nLine);
+ #endif
+             lock.lock();
+ #ifdef DEBUG_LOCKCONTENTION
+             }
+ #endif
+         }
      }
  
-     operator bool() const
+     void Leave()
      {
-         return true;
+         if (lock.owns())
+         {
+             lock.unlock();
+             LeaveCritical();
+         }
      }
  
-     ~CCriticalBlock()
+     bool TryEnter(const char* pszName, const char* pszFile, int nLine)
      {
-         pcs->Leave();
+         if (!lock.owns())
+         {
+             EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
+             lock.try_lock();
+             if (!lock.owns())
+                 LeaveCritical();
+         }
+         return lock.owns();
      }
- };
- #define CRITICAL_BLOCK(cs)     \
-     if (CCriticalBlock criticalblock = CCriticalBlock(cs, #cs, __FILE__, __LINE__))
  
- class CTryCriticalBlock
- {
- protected:
-     CCriticalSection* pcs;
+     CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::interprocess::defer_lock)
+     {
+         if (fTry)
+             TryEnter(pszName, pszFile, nLine);
+         else
+             Enter(pszName, pszFile, nLine);
+     }
  
- public:
-     CTryCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
+     ~CMutexLock()
      {
-         pcs = (csIn.TryEnter(pszName, pszFile, nLine) ? &csIn : NULL);
+         if (lock.owns())
+             LeaveCritical();
      }
  
-     operator bool() const
+     operator bool()
      {
-         return Entered();
+         return lock.owns();
      }
  
-     ~CTryCriticalBlock()
+     boost::interprocess::scoped_lock<Mutex> &GetLock()
      {
-         if (pcs)
-         {
-             pcs->Leave();
-         }
+         return lock;
      }
-     bool Entered() const { return pcs != NULL; }
  };
  
- #define TRY_CRITICAL_BLOCK(cs)     \
-     if (CTryCriticalBlock criticalblock = CTryCriticalBlock(cs, #cs, __FILE__, __LINE__))
+ typedef CMutexLock<CCriticalSection> CCriticalBlock;
  
+ #define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
+ #define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__)
+ #define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
  
+ #define ENTER_CRITICAL_SECTION(cs) \
+     { \
+         EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
+         (cs).lock(); \
+     }
  
- // This is exactly like std::string, but with a custom allocator.
- // (secure_allocator<> is defined in serialize.h)
- typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
+ #define LEAVE_CRITICAL_SECTION(cs) \
+     { \
+         (cs).unlock(); \
+         LeaveCritical(); \
+     }
  
+ #ifdef MAC_OSX
+ // boost::interprocess::interprocess_semaphore seems to spinlock on OSX; prefer polling instead
+ class CSemaphore
+ {
+ private:
+     CCriticalSection cs;
+     int val;
  
+ public:
+     CSemaphore(int init) : val(init) {}
+     void wait() {
+         do {
+             {
+                 LOCK(cs);
+                 if (val>0) {
+                     val--;
+                     return;
+                 }
+             }
+             Sleep(100);
+         } while(1);
+     }
  
+     bool try_wait() {
+         LOCK(cs);
+         if (val>0) {
+             val--;
+             return true;
+         }
+         return false;
+     }
  
+     void post() {
+         LOCK(cs);
+         val++;
+     }
+ };
+ #else
+ typedef boost::interprocess::interprocess_semaphore CSemaphore;
+ #endif
  
  inline std::string i64tostr(int64 n)
  {
@@@ -358,15 -383,20 +390,20 @@@ inline int64 abs64(int64 n
  template<typename T>
  std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
  {
-     if (itbegin == itend)
-         return "";
-     const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
-     const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
-     std::string str;
-     str.reserve((pend-pbegin) * (fSpaces ? 3 : 2));
-     for (const unsigned char* p = pbegin; p != pend; p++)
-         str += strprintf((fSpaces && p != pend-1 ? "%02x " : "%02x"), *p);
-     return str;
+     std::vector<char> rv;
+     static char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+                                '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+     rv.reserve((itend-itbegin)*3);
+     for(T it = itbegin; it < itend; ++it)
+     {
+         unsigned char val = (unsigned char)(*it);
+         if(fSpaces && it != itbegin)
+             rv.push_back(' ');
+         rv.push_back(hexmap[val>>4]);
+         rv.push_back(hexmap[val&15]);
+     }
+     return std::string(rv.begin(), rv.end());
  }
  
  inline std::string HexStr(const std::vector<unsigned char>& vch, bool fSpaces=false)
  }
  
  template<typename T>
- std::string HexNumStr(const T itbegin, const T itend, bool f0x=true)
- {
-     if (itbegin == itend)
-         return "";
-     const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
-     const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
-     std::string str = (f0x ? "0x" : "");
-     str.reserve(str.size() + (pend-pbegin) * 2);
-     for (const unsigned char* p = pend-1; p >= pbegin; p--)
-         str += strprintf("%02x", *p);
-     return str;
- }
- inline std::string HexNumStr(const std::vector<unsigned char>& vch, bool f0x=true)
- {
-     return HexNumStr(vch.begin(), vch.end(), f0x);
- }
- template<typename T>
  void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true)
  {
      printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str());
@@@ -448,32 -459,50 +466,50 @@@ inline bool IsSwitchChar(char c
  #endif
  }
  
- inline std::string GetArg(const std::string& strArg, const std::string& strDefault)
- {
-     if (mapArgs.count(strArg))
-         return mapArgs[strArg];
-     return strDefault;
- }
+ /**
+  * Return string argument or default value
+  *
+  * @param strArg Argument to get (e.g. "-foo")
+  * @param default (e.g. "1")
+  * @return command-line argument or default value
+  */
+ std::string GetArg(const std::string& strArg, const std::string& strDefault);
  
- inline int64 GetArg(const std::string& strArg, int64 nDefault)
- {
-     if (mapArgs.count(strArg))
-         return atoi64(mapArgs[strArg]);
-     return nDefault;
- }
+ /**
+  * Return integer argument or default value
+  *
+  * @param strArg Argument to get (e.g. "-foo")
+  * @param default (e.g. 1)
+  * @return command-line argument (0 if invalid number) or default value
+  */
+ int64 GetArg(const std::string& strArg, int64 nDefault);
  
- inline bool GetBoolArg(const std::string& strArg)
- {
-     if (mapArgs.count(strArg))
-     {
-         if (mapArgs[strArg].empty())
-             return true;
-         return (atoi(mapArgs[strArg]) != 0);
-     }
-     return false;
- }
+ /**
+  * Return boolean argument or default value
+  *
+  * @param strArg Argument to get (e.g. "-foo")
+  * @param default (true or false)
+  * @return command-line argument or default value
+  */
+ bool GetBoolArg(const std::string& strArg, bool fDefault=false);
  
+ /**
+  * Set an argument if it doesn't already have a value
+  *
+  * @param strArg Argument to set (e.g. "-foo")
+  * @param strValue Value (e.g. "1")
+  * @return true if argument gets set, false if it already had a value
+  */
+ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
  
+ /**
+  * Set a boolean argument if it doesn't already have a value
+  *
+  * @param strArg Argument to set (e.g. "-foo")
+  * @param fValue Value (e.g. false)
+  * @return true if argument gets set, false if it already had a value
+  */
+ bool SoftSetBoolArg(const std::string& strArg, bool fValue);
  
  
  
  
  
  
- inline void heapchk()
- {
- #ifdef WIN32
-     /// for debugging
-     //if (_heapchk() != _HEAPOK)
-     //    DebugBreak();
- #endif
- }
  
  // Randomize the stack to help protect against buffer overrun exploits
  #define IMPLEMENT_RANDOMIZE_STACK(ThreadFn)     \
          }                                       \
      }
  
- #define CATCH_PRINT_EXCEPTION(pszFn)     \
-     catch (std::exception& e) {          \
-         PrintException(&e, (pszFn));     \
-     } catch (...) {                      \
-         PrintException(NULL, (pszFn));   \
-     }
  
  template<typename T1>
  inline uint256 Hash(const T1 pbegin, const T1 pend)
@@@ -566,7 -572,7 +579,7 @@@ inline uint256 Hash(const T1 p1begin, c
  }
  
  template<typename T>
- uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=VERSION)
+ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
  {
      // Most of the time is spent allocating and deallocating CDataStream's
      // buffer.  If this ever needs to be optimized further, make a CStaticStream
@@@ -587,16 -593,17 +600,17 @@@ inline uint160 Hash160(const std::vecto
  }
  
  
- // Median filter over a stream of values
- // Returns the median of the last N numbers
+ /** Median filter over a stream of values. 
+  * Returns the median of the last N numbers
+  */
  template <typename T> class CMedianFilter
  {
  private:
      std::vector<T> vValues;
      std::vector<T> vSorted;
-     int nSize;
+     unsigned int nSize;
  public:
-     CMedianFilter(int size, T initial_value):
+     CMedianFilter(unsigned int size, T initial_value):
          nSize(size)
      {
          vValues.reserve(size);
              return (vSorted[size/2-1] + vSorted[size/2]) / 2;
          }
      }
+     int size() const
+     {
+         return vValues.size();
+     }
+     std::vector<T> sorted () const
+     {
+         return vSorted;
+     }
  };
  
  
  // Note: It turns out we might have been able to use boost::thread
  // by using TerminateThread(boost::thread.native_handle(), 0);
  #ifdef WIN32
 -typedef HANDLE pthread_t;
 +typedef HANDLE bitcoin_pthread_t;
  
 -inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
 +inline bitcoin_pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
  {
      DWORD nUnused = 0;
      HANDLE hthread =
      if (hthread == NULL)
      {
          printf("Error: CreateThread() returned %d\n", GetLastError());
 -        return (pthread_t)0;
 +        return (bitcoin_pthread_t)0;
      }
      if (!fWantHandle)
      {
          CloseHandle(hthread);
 -        return (pthread_t)-1;
 +        return (bitcoin_pthread_t)-1;
      }
      return hthread;
  }
@@@ -708,11 -725,6 +732,6 @@@ inline void SetThreadPriority(int nPrio
  #endif
  }
  
- inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)
- {
-     return (pthread_cancel(hthread) == 0);
- }
  inline void ExitThread(size_t nExitCode)
  {
      pthread_exit((void*)nExitCode);
  
  
  
- inline bool AffinityBugWorkaround(void(*pfn)(void*))
- {
- #ifdef WIN32
-     // Sometimes after a few hours affinity gets stuck on one processor
-     DWORD_PTR dwProcessAffinityMask = -1;
-     DWORD_PTR dwSystemAffinityMask = -1;
-     GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
-     DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
-     DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
-     if (dwPrev2 != dwProcessAffinityMask)
-     {
-         printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask);
-         if (!CreateThread(pfn, NULL))
-             printf("Error: CreateThread() failed\n");
-         return true;
-     }
- #endif
-     return false;
- }
  inline uint32_t ByteReverse(uint32_t value)
  {
-       value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
-       return (value<<16) | (value>>16);
+     value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
+     return (value<<16) | (value>>16);
  }
  
  #endif
diff --combined src/version.cpp
index 0000000,60b7aae..3ae1784
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,67 +1,67 @@@
+ // Copyright (c) 2012 The Bitcoin developers
+ // Distributed under the MIT/X11 software license, see the accompanying
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
+ #include <string>
+ #include "version.h"
+ // Name of client reported in the 'version' message. Report the same name
+ // for both bitcoind and bitcoin-qt, to make it harder for attackers to
+ // target servers or GUI users specifically.
+ const std::string CLIENT_NAME("Satoshi");
+ // Client version number
+ #define CLIENT_VERSION_SUFFIX   "-beta"
+ // The following part of the code determines the CLIENT_BUILD variable.
+ // Several mechanisms are used for this:
+ // * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
+ //   generated by the build environment, possibly containing the output
+ //   of git-describe in a macro called BUILD_DESC
+ // * secondly, if this is an exported version of the code, GIT_ARCHIVE will
+ //   be defined (automatically using the export-subst git attribute), and
+ //   GIT_COMMIT will contain the commit id.
+ // * then, three options exist for determining CLIENT_BUILD:
+ //   * if BUILD_DESC is defined, use that literally (output of git-describe)
+ //   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
+ //   * otherwise, use v[maj].[min].[rev].[build]-unk
+ // finally CLIENT_VERSION_SUFFIX is added
+ // First, include build.h if requested
+ #ifdef HAVE_BUILD_INFO
+ #    include "build.h"
+ #endif
+ // git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
+ #ifdef GIT_ARCHIVE
+ #    define GIT_COMMIT_ID "$Format:%h$"
+ #    define GIT_COMMIT_DATE "$Format:%cD"
+ #endif
+ #define STRINGIFY(s) #s
+ #define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
+     "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-g" commit
+ #define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
+     "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-unk"
+ #ifndef BUILD_DESC
+ #    ifdef GIT_COMMIT_ID
 -#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
++#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(PPCOIN_VERSION_MAJOR, PPCOIN_VERSION_MINOR, PPCOIN_VERSION_REVISION, PPCOIN_VERSION_BUILD, GIT_COMMIT_ID)
+ #    else
 -#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
++#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(PPCOIN_VERSION_MAJOR, PPCOIN_VERSION_MINOR, PPCOIN_VERSION_REVISION, PPCOIN_VERSION_BUILD)
+ #    endif
+ #endif
+ #ifndef BUILD_DATE
+ #    ifdef GIT_COMMIT_DATE
+ #        define BUILD_DATE GIT_COMMIT_DATE
+ #    else
+ #        define BUILD_DATE __DATE__ ", " __TIME__
+ #    endif
+ #endif
+ const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
+ const std::string CLIENT_DATE(BUILD_DATE);
diff --combined src/version.h
index 0000000,9718e75..29efa06
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,49 +1,55 @@@
+ // Copyright (c) 2012 The Bitcoin developers
+ // Distributed under the MIT/X11 software license, see the accompanying
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
+ #ifndef BITCOIN_VERSION_H
+ #define BITCOIN_VERSION_H
+ #include <string>
+ //
+ // client versioning
+ //
+ // These need to be macro's, as version.cpp's voodoo requires it
+ #define CLIENT_VERSION_MAJOR       0
+ #define CLIENT_VERSION_MINOR       6
+ #define CLIENT_VERSION_REVISION    3
+ #define CLIENT_VERSION_BUILD       0
+ static const int CLIENT_VERSION =
+                            1000000 * CLIENT_VERSION_MAJOR
+                          +   10000 * CLIENT_VERSION_MINOR 
+                          +     100 * CLIENT_VERSION_REVISION
+                          +       1 * CLIENT_VERSION_BUILD;
+ extern const std::string CLIENT_NAME;
+ extern const std::string CLIENT_BUILD;
+ extern const std::string CLIENT_DATE;
++// ppcoin version - intended for display purpose ONLY
++#define PPCOIN_VERSION_MAJOR       0
++#define PPCOIN_VERSION_MINOR       1
++#define PPCOIN_VERSION_REVISION    0
++#define PPCOIN_VERSION_BUILD       0
++
+ //
+ // network protocol versioning
+ //
+ static const int PROTOCOL_VERSION = 60001;
+ // earlier versions not supported as of Feb 2012, and are disconnected
 -static const int MIN_PROTO_VERSION = 209;
++static const int MIN_PROTO_VERSION = 60001;
+ // nTime field added to CAddress, starting with this version;
+ // if possible, avoid requesting addresses nodes older than this
+ static const int CADDR_TIME_VERSION = 31402;
+ // only request blocks from nodes outside this range of versions
+ static const int NOBLKS_VERSION_START = 32000;
+ static const int NOBLKS_VERSION_END = 32400;
+ // BIP 0031, pong message, is enabled for all versions AFTER this one
+ static const int BIP0031_VERSION = 60000;
+ #endif
diff --combined src/wallet.cpp
@@@ -1,13 -1,12 +1,14 @@@
- // Copyright (c) 2009-2011 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2010 Satoshi Nakamoto
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
- #include "headers.h"
- #include "db.h"
+ #include "wallet.h"
+ #include "walletdb.h"
  #include "crypter.h"
 +#include "checkpoints.h"
+ #include "ui_interface.h"
  
  using namespace std;
  
  // mapWallet
  //
  
+ std::vector<unsigned char> CWallet::GenerateNewKey()
+ {
+     bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
+     RandAddSeedPerfmon();
+     CKey key;
+     key.MakeNewKey(fCompressed);
+     // Compressed public keys were introduced in version 0.6.0
+     if (fCompressed)
+         SetMinVersion(FEATURE_COMPRPUBKEY);
+     if (!AddKey(key))
+         throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
+     return key.GetPubKey();
+ }
  bool CWallet::AddKey(const CKey& key)
  {
      if (!CCryptoKeyStore::AddKey(key))
@@@ -34,8 -50,8 +52,8 @@@ bool CWallet::AddCryptedKey(const vecto
          return false;
      if (!fFileBacked)
          return true;
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          if (pwalletdbEncryption)
              return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
          else
      return false;
  }
  
+ bool CWallet::AddCScript(const CScript& redeemScript)
+ {
+     if (!CCryptoKeyStore::AddCScript(redeemScript))
+         return false;
+     if (!fFileBacked)
+         return true;
+     return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
+ }
 +// ppcoin: optional setting to create coinstake only when unlocked;
 +//         serves to disable the trivial sendmoney when OS account compromised
 +bool fWalletUnlockStakeOnly = false;
 +
  bool CWallet::Unlock(const SecureString& strWalletPassphrase)
  {
      if (!IsLocked())
@@@ -56,7 -77,8 +83,8 @@@
      CCrypter crypter;
      CKeyingMaterial vMasterKey;
  
-     CRITICAL_BLOCK(cs_wallet)
+     {
+         LOCK(cs_wallet);
          BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
          {
              if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
@@@ -66,6 -88,7 +94,7 @@@
              if (CCryptoKeyStore::Unlock(vMasterKey))
                  return true;
          }
+     }
      return false;
  }
  
@@@ -73,8 -96,8 +102,8 @@@ bool CWallet::ChangeWalletPassphrase(co
  {
      bool fWasLocked = IsLocked();
  
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          Lock();
  
          CCrypter crypter;
      return false;
  }
  
+ void CWallet::SetBestChain(const CBlockLocator& loc)
+ {
+     CWalletDB walletdb(strWalletFile);
+     walletdb.WriteBestBlock(loc);
+ }
  
  // This class implements an addrIncoming entry that causes pre-0.4
  // clients to crash on startup if reading a private-key-encrypted wallet.
@@@ -128,6 -156,50 +162,50 @@@ public
      )
  };
  
+ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
+ {
+     if (nWalletVersion >= nVersion)
+         return true;
+     // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
+     if (fExplicit && nVersion > nWalletMaxVersion)
+             nVersion = FEATURE_LATEST;
+     nWalletVersion = nVersion;
+     if (nVersion > nWalletMaxVersion)
+         nWalletMaxVersion = nVersion;
+     if (fFileBacked)
+     {
+         CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
+         if (nWalletVersion >= 40000)
+         {
+             // Versions prior to 0.4.0 did not support the "minversion" record.
+             // Use a CCorruptAddress to make them crash instead.
+             CCorruptAddress corruptAddress;
+             pwalletdb->WriteSetting("addrIncoming", corruptAddress);
+         }
+         if (nWalletVersion > 40000)
+             pwalletdb->WriteMinVersion(nWalletVersion);
+         if (!pwalletdbIn)
+             delete pwalletdb;
+     }
+     return true;
+ }
+ bool CWallet::SetMaxVersion(int nVersion)
+ {
+     // cannot downgrade below current version
+     if (nWalletVersion > nVersion)
+         return false;
+     nWalletMaxVersion = nVersion;
+     return true;
+ }
  bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
  {
      if (IsCrypted())
      if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
          return false;
  
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
          if (fFileBacked)
          {
              pwalletdbEncryption = new CWalletDB(strWalletFile);
-             pwalletdbEncryption->TxnBegin();
+             if (!pwalletdbEncryption->TxnBegin())
+                 return false;
              pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
          }
  
              exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
          }
  
+         // Encryption was introduced in version 0.4.0
+         SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
          if (fFileBacked)
          {
              if (!pwalletdbEncryption->TxnCommit())
                  exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
  
-             pwalletdbEncryption->Close();
+             delete pwalletdbEncryption;
              pwalletdbEncryption = NULL;
          }
  
@@@ -210,8 -284,8 +290,8 @@@ void CWallet::WalletUpdateSpent(const C
      // Anytime a signature is successfully verified, it's proof the outpoint is spent.
      // Update the wallet spent flag if it doesn't know due to wallet.dat being
      // restored from backup or the user making copies of wallet.dat.
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          BOOST_FOREACH(const CTxIn& txin, tx.vin)
          {
              map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
                  CWalletTx& wtx = (*mi).second;
                  if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
                  {
 -                    printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
 +                    printf("WalletUpdateSpent found spent coin %sppc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
                      wtx.MarkSpent(txin.prevout.n);
                      wtx.WriteToDisk();
                      vWalletUpdated.push_back(txin.prevout.hash);
      }
  }
  
+ void CWallet::MarkDirty()
+ {
+     {
+         LOCK(cs_wallet);
+         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+             item.second.MarkDirty();
+     }
+ }
  bool CWallet::AddToWallet(const CWalletTx& wtxIn)
  {
      uint256 hash = wtxIn.GetHash();
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          // Inserts only if not already there, returns tx inserted or tx found
          pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
          CWalletTx& wtx = (*ret.first).second;
-         wtx.pwallet = this;
+         wtx.BindWallet(this);
          bool fInsertedNew = ret.second;
          if (fInsertedNew)
              wtx.nTimeReceived = GetAdjustedTime();
  // Add a transaction to the wallet, or update it.
  // pblock is optional, but should be provided if the transaction is known to be in a block.
  // If fUpdate is true, existing transactions will be updated.
- bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
+ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
  {
      uint256 hash = tx.GetHash();
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          bool fExisted = mapWallet.count(hash);
          if (fExisted && !fUpdate) return false;
          if (fExisted || IsMine(tx) || IsFromMe(tx))
@@@ -330,8 -413,8 +419,8 @@@ bool CWallet::EraseFromWallet(uint256 h
  {
      if (!fFileBacked)
          return false;
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          if (mapWallet.erase(hash))
              CWalletDB(strWalletFile).EraseTx(hash);
      }
  
  bool CWallet::IsMine(const CTxIn &txin) const
  {
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
          if (mi != mapWallet.end())
          {
  
  int64 CWallet::GetDebit(const CTxIn &txin) const
  {
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
          if (mi != mapWallet.end())
          {
      return 0;
  }
  
+ bool CWallet::IsChange(const CTxOut& txout) const
+ {
+     CBitcoinAddress address;
+     // TODO: fix handling of 'change' outputs. The assumption is that any
+     // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
+     // is change. That assumption is likely to break when we implement multisignature
+     // wallets that return change back into a multi-signature-protected address;
+     // a better way of identifying which outputs are 'the send' and which are
+     // 'the change' will need to be implemented (maybe extend CWalletTx to remember
+     // which output, if any, was change).
+     if (ExtractAddress(txout.scriptPubKey, address) && HaveKey(address))
+     {
+         LOCK(cs_wallet);
+         if (!mapAddressBook.count(address))
+             return true;
+     }
+     return false;
+ }
  int64 CWalletTx::GetTxTime() const
  {
      return nTimeReceived;
@@@ -380,9 -483,9 +489,9 @@@ int CWalletTx::GetRequestCount() cons
  {
      // Returns -1 if it wasn't being tracked
      int nRequests = -1;
-     CRITICAL_BLOCK(pwallet->cs_wallet)
      {
+         LOCK(pwallet->cs_wallet);
 -        if (IsCoinBase())
 +        if (IsCoinBase() || IsCoinStake())
          {
              // Generated block
              if (hashBlock != 0)
@@@ -423,7 -526,7 +532,7 @@@ void CWalletTx::GetAmounts(int64& nGene
      listSent.clear();
      strSentAccount = strFromAccount;
  
 -    if (IsCoinBase())
 +    if (IsCoinBase() || IsCoinStake())
      {
          if (GetBlocksToMaturity() > 0)
              nGeneratedImmature = pwallet->GetCredit(*this);
          nFee = nDebit - nValueOut;
      }
  
-     // Sent/received.  Standard client will never generate a send-to-multiple-recipients,
-     // but non-standard clients might (so return a list of address/amount pairs)
+     // Sent/received.
      BOOST_FOREACH(const CTxOut& txout, vout)
      {
          CBitcoinAddress address;
          vector<unsigned char> vchPubKey;
-         if (!ExtractAddress(txout.scriptPubKey, NULL, address))
+         if (!ExtractAddress(txout.scriptPubKey, address))
          {
              printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
                     this->GetHash().ToString().c_str());
@@@ -486,8 -588,8 +594,8 @@@ void CWalletTx::GetAccountAmounts(cons
              nSent += s.second;
          nFee = allFee;
      }
-     CRITICAL_BLOCK(pwallet->cs_wallet)
      {
+         LOCK(pwallet->cs_wallet);
          BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
          {
              if (pwallet->mapAddressBook.count(r.first))
@@@ -516,11 -618,11 +624,11 @@@ void CWalletTx::AddSupportingTransactio
              vWorkQueue.push_back(txin.prevout.hash);
  
          // This critsect is OK because txdb is already open
-         CRITICAL_BLOCK(pwallet->cs_wallet)
          {
+             LOCK(pwallet->cs_wallet);
              map<uint256, const CMerkleTx*> mapWalletPrev;
              set<uint256> setAlreadyDone;
-             for (int i = 0; i < vWorkQueue.size(); i++)
+             for (unsigned int i = 0; i < vWorkQueue.size(); i++)
              {
                  uint256 hash = vWorkQueue[i];
                  if (setAlreadyDone.count(hash))
                  vtxPrev.push_back(tx);
  
                  if (nDepth < COPY_DEPTH)
+                 {
                      BOOST_FOREACH(const CTxIn& txin, tx.vin)
                          vWorkQueue.push_back(txin.prevout.hash);
+                 }
              }
          }
      }
@@@ -575,8 -679,8 +685,8 @@@ int CWallet::ScanForWalletTransactions(
      int ret = 0;
  
      CBlockIndex* pindex = pindexStart;
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          while (pindex)
          {
              CBlock block;
      return ret;
  }
  
+ int CWallet::ScanForWalletTransaction(const uint256& hashTx)
+ {
+     CTransaction tx;
+     tx.ReadFromDisk(COutPoint(hashTx, 0));
+     if (AddToWalletIfInvolvingMe(tx, NULL, true, true))
+         return 1;
+     return 0;
+ }
  void CWallet::ReacceptWalletTransactions()
  {
      CTxDB txdb("r");
      bool fRepeat = true;
-     while (fRepeat) CRITICAL_BLOCK(cs_wallet)
+     while (fRepeat)
      {
+         LOCK(cs_wallet);
          fRepeat = false;
          vector<CDiskTxPos> vMissingTx;
          BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
          {
              CWalletTx& wtx = item.second;
 -            if (wtx.IsCoinBase() && wtx.IsSpent(0))
 +            if ((wtx.IsCoinBase() && wtx.IsSpent(0)) || (wtx.IsCoinStake() && wtx.IsSpent(1)))
                  continue;
  
              CTxIndex txindex;
                      printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
                      continue;
                  }
-                 for (int i = 0; i < txindex.vSpent.size(); i++)
+                 for (unsigned int i = 0; i < txindex.vSpent.size(); i++)
                  {
                      if (wtx.IsSpent(i))
                          continue;
                  }
                  if (fUpdated)
                  {
 -                    printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
 +                    printf("ReacceptWalletTransactions found spent coin %sppc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
                      wtx.MarkDirty();
                      wtx.WriteToDisk();
                  }
              else
              {
                  // Reaccept any txes of ours that aren't already in a block
 -                if (!wtx.IsCoinBase())
 +                if (!(wtx.IsCoinBase() || wtx.IsCoinStake()))
                      wtx.AcceptWalletTransaction(txdb, false);
              }
          }
@@@ -654,14 -768,14 +774,14 @@@ void CWalletTx::RelayWalletTransaction(
  {
      BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
      {
 -        if (!tx.IsCoinBase())
 +        if (!(tx.IsCoinBase() || tx.IsCoinStake()))
          {
              uint256 hash = tx.GetHash();
              if (!txdb.ContainsTx(hash))
                  RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
          }
      }
 -    if (!IsCoinBase())
 +    if (!(IsCoinBase() || IsCoinStake()))
      {
          uint256 hash = GetHash();
          if (!txdb.ContainsTx(hash))
@@@ -699,8 -813,8 +819,8 @@@ void CWallet::ResendWalletTransactions(
      // Rebroadcast any of our txes that aren't in a block yet
      printf("ResendWalletTransactions()\n");
      CTxDB txdb("r");
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          // Sort them in chronological order
          multimap<unsigned int, CWalletTx*> mapSorted;
          BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
  int64 CWallet::GetBalance() const
  {
      int64 nTotal = 0;
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
          {
              const CWalletTx* pcoin = &(*it).second;
  int64 CWallet::GetUnconfirmedBalance() const
  {
      int64 nTotal = 0;
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
          {
              const CWalletTx* pcoin = &(*it).second;
      return nTotal;
  }
  
 -bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
 +// ppcoin: total coins staked (non-spendable until maturity)
 +int64 CWallet::GetStake() const
 +{
 +    int64 nTotal = 0;
-     CRITICAL_BLOCK(cs_wallet)
++    LOCK(cs_wallet);
++    for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
 +    {
-         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
-         {
-             const CWalletTx* pcoin = &(*it).second;
-             if (pcoin->IsCoinStake() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0)
-                 nTotal += CWallet::GetCredit(*pcoin);
-         }
++        const CWalletTx* pcoin = &(*it).second;
++        if (pcoin->IsCoinStake() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0)
++            nTotal += CWallet::GetCredit(*pcoin);
 +    }
 +    return nTotal;
 +}
 +
 +int64 CWallet::GetNewMint() const
 +{
 +    int64 nTotal = 0;
-     CRITICAL_BLOCK(cs_wallet)
++    LOCK(cs_wallet);
++    for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
 +    {
-         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
-         {
-             const CWalletTx* pcoin = &(*it).second;
-             if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0)
-                 nTotal += CWallet::GetCredit(*pcoin);
-         }
++        const CWalletTx* pcoin = &(*it).second;
++        if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0)
++            nTotal += CWallet::GetCredit(*pcoin);
 +    }
 +    return nTotal;
 +}
 +
 +
 +bool CWallet::SelectCoinsMinConf(int64 nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
  {
      setCoinsRet.clear();
      nValueRet = 0;
  
      // List of values less than target
      pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
-     coinLowestLarger.first = INT64_MAX;
+     coinLowestLarger.first = std::numeric_limits<int64>::max();
      coinLowestLarger.second.first = NULL;
      vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
      int64 nTotalLower = 0;
  
-     CRITICAL_BLOCK(cs_wallet)
      {
+        LOCK(cs_wallet);
         vector<const CWalletTx*> vCoins;
         vCoins.reserve(mapWallet.size());
         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
              if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
                  continue;
  
 -            if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
 +            if ((pcoin->IsCoinBase() || pcoin->IsCoinStake()) && pcoin->GetBlocksToMaturity() > 0)
                  continue;
  
              int nDepth = pcoin->GetDepthInMainChain();
              if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
                  continue;
  
-             for (int i = 0; i < pcoin->vout.size(); i++)
+             for (unsigned int i = 0; i < pcoin->vout.size(); i++)
              {
                  if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
                      continue;
  
 +                if (pcoin->nTime > nSpendTime)
 +                    continue;  // ppcoin: timestamp must not exceed spend time
 +
                  int64 n = pcoin->vout[i].nValue;
  
                  if (n <= 0)
  
      if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
      {
-         for (int i = 0; i < vValue.size(); ++i)
+         for (unsigned int i = 0; i < vValue.size(); ++i)
          {
              setCoinsRet.insert(vValue[i].second);
              nValueRet += vValue[i].first;
          bool fReachedTarget = false;
          for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
          {
-             for (int i = 0; i < vValue.size(); i++)
+             for (unsigned int i = 0; i < vValue.size(); i++)
              {
                  if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
                  {
          nValueRet += coinLowestLarger.first;
      }
      else {
-         for (int i = 0; i < vValue.size(); i++)
+         for (unsigned int i = 0; i < vValue.size(); i++)
              if (vfBest[i])
              {
                  setCoinsRet.insert(vValue[i].second);
  
          //// debug print
          printf("SelectCoins() best subset: ");
-         for (int i = 0; i < vValue.size(); i++)
+         for (unsigned int i = 0; i < vValue.size(); i++)
              if (vfBest[i])
                  printf("%s ", FormatMoney(vValue[i].first).c_str());
          printf("total %s\n", FormatMoney(nBest).c_str());
      return true;
  }
  
 -bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
 +bool CWallet::SelectCoins(int64 nTargetValue, unsigned int nSpendTime, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
  {
 -    return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
 -            SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
 -            SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
 +    return (SelectCoinsMinConf(nTargetValue, nSpendTime, 1, 6, setCoinsRet, nValueRet) ||
 +            SelectCoinsMinConf(nTargetValue, nSpendTime, 1, 1, setCoinsRet, nValueRet) ||
 +            SelectCoinsMinConf(nTargetValue, nSpendTime, 0, 1, setCoinsRet, nValueRet));
  }
  
  
@@@ -965,11 -1044,10 +1081,10 @@@ bool CWallet::CreateTransaction(const v
      if (vecSend.empty() || nValue < 0)
          return false;
  
-     wtxNew.pwallet = this;
+     wtxNew.BindWallet(this);
  
-     CRITICAL_BLOCK(cs_main)
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK2(cs_main, cs_wallet);
          // txdb must be opened before the mapWallet lock
          CTxDB txdb("r");
          {
                  // Choose coins to use
                  set<pair<const CWalletTx*,unsigned int> > setCoins;
                  int64 nValueIn = 0;
 -                if (!SelectCoins(nTotalValue, setCoins, nValueIn))
 +                if (!SelectCoins(nTotalValue, wtxNew.nTime, setCoins, nValueIn))
                      return false;
                  BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
                  {
                  int64 nChange = nValueIn - nValue - nFeeRet;
                  // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
                  // or until nChange becomes zero
+                 // NOTE: this depends on the exact behaviour of GetMinFee
                  if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
                  {
                      int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
                      vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
                      // assert(mapKeys.count(vchPubKey));
  
-                     // Fill a vout to ourself, using same address type as the payment
+                     // Fill a vout to ourself
+                     // TODO: pass in scriptChange instead of reservekey so
+                     // change transaction isn't always pay-to-bitcoin-address
                      CScript scriptChange;
-                     if (vecSend[0].first.GetBitcoinAddress().IsValid())
-                         scriptChange.SetBitcoinAddress(vchPubKey);
-                     else
-                         scriptChange << vchPubKey << OP_CHECKSIG;
+                     scriptChange.SetBitcoinAddress(vchPubKey);
  
                      // Insert change txn at random position:
                      vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
                          return false;
  
                  // Limit size
-                 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
+                 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
                  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(1, false);
 -                bool fAllowFree = CTransaction::AllowFree(dPriority);
 -                int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
++                int64 nMinFee = wtxNew.GetMinFee(1, false, GMF_SEND);
                  if (nFeeRet < max(nPayFee, nMinFee))
                  {
                      nFeeRet = max(nPayFee, nMinFee);
@@@ -1077,103 -1156,11 +1192,99 @@@ bool CWallet::CreateTransaction(CScrip
      return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
  }
  
 +// ppcoin: create coin stake transaction
 +bool CWallet::CreateCoinStake(unsigned int nBits, CTransaction& txNew)
 +{
 +    CBigNum bnTargetPerCoinDay;
 +    bnTargetPerCoinDay.SetCompact(nBits);
 +
-     CRITICAL_BLOCK(cs_main)
-     CRITICAL_BLOCK(cs_wallet)
++    LOCK2(cs_main, cs_wallet);
++    txNew.vin.clear();
++    txNew.vout.clear();
++    // Mark coin stake transaction
++    CScript scriptEmpty;
++    scriptEmpty.clear();
++    txNew.vout.push_back(CTxOut(0, scriptEmpty));
++    // Choose coins to use
++    int64 nBalance = GetBalance();
++    if (nBalance <= nBalanceReserve)
++        return false;
++    set<pair<const CWalletTx*,unsigned int> > setCoins;
++    vector<const CWalletTx*> vwtxPrev;
++    int64 nValueIn = 0;
++    if (!SelectCoins(nBalance - nBalanceReserve, txNew.nTime, setCoins, nValueIn))
++        return false;
++    if (setCoins.empty())
++        return false;
++    int64 nCredit = 0;
++    BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
 +    {
-         txNew.vin.clear();
-         txNew.vout.clear();
-         // Mark coin stake transaction
-         CScript scriptEmpty;
-         scriptEmpty.clear();
-         txNew.vout.push_back(CTxOut(0, scriptEmpty));
-         // Choose coins to use
-         int64 nBalance = GetBalance();
-         if (nBalance <= nBalanceReserve)
-             return false;
-         set<pair<const CWalletTx*,unsigned int> > setCoins;
-         vector<const CWalletTx*> vwtxPrev;
-         int64 nValueIn = 0;
-         if (!SelectCoins(nBalance - nBalanceReserve, txNew.nTime, setCoins, nValueIn))
-             return false;
-         if (setCoins.empty())
-             return false;
-         int64 nCredit = 0;
-         BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
-         {
-             CTxDB txdb("r");
-             CTxIndex txindex;
-             if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex))
-                 continue;
++        CTxDB txdb("r");
++        CTxIndex txindex;
++        if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex))
++            continue;
 +
-             // Read block header
-             CBlock block;
-             if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
-                 continue;
-             if (block.GetBlockTime() + STAKE_MIN_AGE > txNew.nTime)
-                 continue; // only count coins meeting min age requirement
-             int64 nValueIn = pcoin.first->vout[pcoin.second].nValue;
-             CBigNum bnCoinDay = CBigNum(nValueIn) * (txNew.nTime-pcoin.first->nTime) / COIN / (24 * 60 * 60);
-             // Calculate hash
-             CDataStream ss(SER_GETHASH, VERSION);
-             ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << pcoin.first->nTime << pcoin.second << txNew.nTime;
-             if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay)
-             {
-                 txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second));
-                 nCredit += pcoin.first->vout[pcoin.second].nValue;
-                 vwtxPrev.push_back(pcoin.first);
-                 // Set output scriptPubKey
-                 txNew.vout.push_back(CTxOut(0, pcoin.first->vout[pcoin.second].scriptPubKey));
-                 break;
-             }
-         }
-         if (nCredit == 0 || nCredit > nBalance - nBalanceReserve)
-             return false;
-         BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
++        // Read block header
++        CBlock block;
++        if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
++            continue;
++        if (block.GetBlockTime() + STAKE_MIN_AGE > txNew.nTime)
++            continue; // only count coins meeting min age requirement
++
++        int64 nValueIn = pcoin.first->vout[pcoin.second].nValue;
++        CBigNum bnCoinDay = CBigNum(nValueIn) * (txNew.nTime-pcoin.first->nTime) / COIN / (24 * 60 * 60);
++        // Calculate hash
++        CDataStream ss(SER_GETHASH, 0);
++        ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << pcoin.first->nTime << pcoin.second << txNew.nTime;
++        if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay)
 +        {
-             if (pcoin.first->vout[pcoin.second].scriptPubKey == txNew.vout[1].scriptPubKey && pcoin.first->GetHash() != txNew.vin[0].prevout.hash)
-             {
-                 if (nCredit + pcoin.first->vout[pcoin.second].nValue > nBalance - nBalanceReserve)
-                     break;
-                 txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second));
-                 nCredit += pcoin.first->vout[pcoin.second].nValue;
-                 vwtxPrev.push_back(pcoin.first);
-             }
++            txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second));
++            nCredit += pcoin.first->vout[pcoin.second].nValue;
++            vwtxPrev.push_back(pcoin.first);
++            // Set output scriptPubKey
++            txNew.vout.push_back(CTxOut(0, pcoin.first->vout[pcoin.second].scriptPubKey));
++            break;
 +        }
-         // Calculate coin age reward
++    }
++    if (nCredit == 0 || nCredit > nBalance - nBalanceReserve)
++        return false;
++    BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
++    {
++        if (pcoin.first->vout[pcoin.second].scriptPubKey == txNew.vout[1].scriptPubKey && pcoin.first->GetHash() != txNew.vin[0].prevout.hash)
 +        {
-             uint64 nCoinAge;
-             CTxDB txdb("r");
-             if (!txNew.GetCoinAge(txdb, nCoinAge))
-                 return error("CreateCoinStake : failed to calculate coin age");
-             nCredit += GetProofOfStakeReward(nCoinAge);
++            if (nCredit + pcoin.first->vout[pcoin.second].nValue > nBalance - nBalanceReserve)
++                break;
++            txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second));
++            nCredit += pcoin.first->vout[pcoin.second].nValue;
++            vwtxPrev.push_back(pcoin.first);
 +        }
-         // Set output amount
-         txNew.vout[1].nValue = nCredit;
++    }
++    // Calculate coin age reward
++    {
++        uint64 nCoinAge;
++        CTxDB txdb("r");
++        if (!txNew.GetCoinAge(txdb, nCoinAge))
++            return error("CreateCoinStake : failed to calculate coin age");
++        nCredit += GetProofOfStakeReward(nCoinAge);
++    }
++    // Set output amount
++    txNew.vout[1].nValue = nCredit;
 +
-         // Sign
-         int nIn = 0;
-         BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev)
-         {
-             if (!SignSignature(*this, *pcoin, txNew, nIn++))
-                 return error("CreateCoinStake : failed to sign coinstake");
-         }
++    // Sign
++    int nIn = 0;
++    BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev)
++    {
++        if (!SignSignature(*this, *pcoin, txNew, nIn++))
++            return error("CreateCoinStake : failed to sign coinstake");
 +    }
 +    return true;
 +}
 +
  // Call after CreateTransaction unless you want to abort
  bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
  {
-     CRITICAL_BLOCK(cs_main)
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK2(cs_main, cs_wallet);
          printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
          {
              // This is only to keep the database open to defeat the auto-flush for the
              BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
              {
                  CWalletTx &coin = mapWallet[txin.prevout.hash];
-                 coin.pwallet = this;
+                 coin.BindWallet(this);
                  coin.MarkSpent(txin.prevout.n);
                  coin.WriteToDisk();
                  vWalletUpdated.push_back(coin.GetHash());
@@@ -1233,12 -1220,6 +1344,12 @@@ string CWallet::SendMoney(CScript scrip
          printf("SendMoney() : %s", strError.c_str());
          return strError;
      }
 +    if (fWalletUnlockStakeOnly)
 +    {
 +        string strError = _("Error: Wallet unlocked for coinstake only, unable to create transaction.");
 +        printf("SendMoney() : %s", strError.c_str());
 +        return strError;
 +    }
      if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
      {
          string strError;
          return strError;
      }
  
-     if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
+     if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending...")))
          return "ABORTED";
  
      if (!CommitTransaction(wtxNew, reservekey))
@@@ -1302,19 -1283,6 +1413,6 @@@ int CWallet::LoadWallet(bool& fFirstRun
          return nLoadWalletRet;
      fFirstRunRet = vchDefaultKey.empty();
  
-     if (!HaveKey(Hash160(vchDefaultKey)))
-     {
-         // Create new keyUser and set as default key
-         RandAddSeedPerfmon();
-         std::vector<unsigned char> newDefaultKey;
-         if (!GetKeyFromPool(newDefaultKey, false))
-             return DB_LOAD_FAIL;
-         SetDefaultKey(newDefaultKey);
-         if (!SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""))
-             return DB_LOAD_FAIL;
-     }
      CreateThread(ThreadFlushWalletDB, &strWalletFile);
      return DB_LOAD_OK;
  }
  bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
  {
      mapAddressBook[address] = strName;
+     AddressBookRepaint();
      if (!fFileBacked)
          return false;
      return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
  bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
  {
      mapAddressBook.erase(address);
+     AddressBookRepaint();
      if (!fFileBacked)
          return false;
      return CWalletDB(strWalletFile).EraseName(address.ToString());
  
  void CWallet::PrintWallet(const CBlock& block)
  {
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
 -        if (mapWallet.count(block.vtx[0].GetHash()))
 +        if (block.IsProofOfWork() && mapWallet.count(block.vtx[0].GetHash()))
          {
              CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
 -            printf("    mine:  %d  %d  %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
 +            printf("    mine:  %d  %d  %s", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), FormatMoney(wtx.GetCredit()).c_str());
 +        }
 +        if (block.IsProofOfStake() && mapWallet.count(block.vtx[1].GetHash()))
 +        {
 +            CWalletTx& wtx = mapWallet[block.vtx[1].GetHash()];
 +            printf("    stake: %d  %d  %s", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), FormatMoney(wtx.GetCredit()).c_str());
          }
      }
      printf("\n");
  
  bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
  {
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
          if (mi != mapWallet.end())
          {
@@@ -1394,8 -1359,8 +1494,8 @@@ bool GetWalletFile(CWallet* pwallet, st
  //
  bool CWallet::NewKeyPool()
  {
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          CWalletDB walletdb(strWalletFile);
          BOOST_FOREACH(int64 nIndex, setKeyPool)
              walletdb.ErasePool(nIndex);
  
  bool CWallet::TopUpKeyPool()
  {
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          if (IsLocked())
              return false;
  
          CWalletDB walletdb(strWalletFile);
  
          // Top up key pool
-         int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
-         while (setKeyPool.size() < nTargetSize+1)
+         unsigned int nTargetSize = max(GetArg("-keypool", 100), 0LL);
+         while (setKeyPool.size() < (nTargetSize + 1))
          {
              int64 nEnd = 1;
              if (!setKeyPool.empty())
@@@ -1445,8 -1411,9 +1546,9 @@@ void CWallet::ReserveKeyFromKeyPool(int
  {
      nIndex = -1;
      keypool.vchPubKey.clear();
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          if (!IsLocked())
              TopUpKeyPool();
  
      }
  }
  
+ int64 CWallet::AddReserveKey(const CKeyPool& keypool)
+ {
+     {
+         LOCK2(cs_main, cs_wallet);
+         CWalletDB walletdb(strWalletFile);
+         int64 nIndex = 1 + *(--setKeyPool.end());
+         if (!walletdb.WritePool(nIndex, keypool))
+             throw runtime_error("AddReserveKey() : writing added key failed");
+         setKeyPool.insert(nIndex);
+         return nIndex;
+     }
+     return -1;
+ }
  void CWallet::KeepKey(int64 nIndex)
  {
      // Remove from key pool
  void CWallet::ReturnKey(int64 nIndex)
  {
      // Return to key pool
-     CRITICAL_BLOCK(cs_wallet)
+     {
+         LOCK(cs_wallet);
          setKeyPool.insert(nIndex);
+     }
      printf("keypool return %"PRI64d"\n", nIndex);
  }
  
@@@ -1490,8 -1474,8 +1609,8 @@@ bool CWallet::GetKeyFromPool(vector<uns
  {
      int64 nIndex = 0;
      CKeyPool keypool;
-     CRITICAL_BLOCK(cs_wallet)
      {
+         LOCK(cs_wallet);
          ReserveKeyFromKeyPool(nIndex, keypool);
          if (nIndex == -1)
          {
@@@ -1521,110 -1505,6 +1640,107 @@@ int64 CWallet::GetOldestKeyPoolTime(
      return keypool.nTime;
  }
  
 +// ppcoin: check 'spent' consistency between wallet and txindex
 +bool CWallet::CheckSpentCoins(int& nMismatchFound, int64& nBalanceInQuestion)
 +{
 +    nMismatchFound = 0;
 +    nBalanceInQuestion = 0;
-     CRITICAL_BLOCK(cs_wallet)
-     {
-        vector<const CWalletTx*> vCoins;
-        vCoins.reserve(mapWallet.size());
-        for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
-            vCoins.push_back(&(*it).second);
 +
-        CTxDB txdb("r");
-        BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
-        {
-            // Find the corresponding transaction index
-            CTxIndex txindex;
-            if (!txdb.ReadTxIndex(pcoin->GetHash(), txindex))
-                continue;
-            for (int n=0; n < pcoin->vout.size(); n++)
-            {
-                if (pcoin->IsSpent(n) && (txindex.vSpent.size() <= n || txindex.vSpent[n].IsNull()))
-                {
-                    printf("CheckSpentCoins found lost coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
-                    nMismatchFound++;
-                    nBalanceInQuestion += pcoin->vout[n].nValue;
-                }
-                else if (!pcoin->IsSpent(n) && (txindex.vSpent.size() > n && !txindex.vSpent[n].IsNull()))
-                {
-                    printf("CheckSpentCoins found spent coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
-                    nMismatchFound++;
-                    nBalanceInQuestion += pcoin->vout[n].nValue;
-                }
-            }
-        }
++    LOCK(cs_wallet);
++    vector<const CWalletTx*> vCoins;
++    vCoins.reserve(mapWallet.size());
++    for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
++        vCoins.push_back(&(*it).second);
++ 
++    CTxDB txdb("r");
++    BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
++    {
++        // Find the corresponding transaction index
++        CTxIndex txindex;
++        if (!txdb.ReadTxIndex(pcoin->GetHash(), txindex))
++            continue;
++        for (int n=0; n < pcoin->vout.size(); n++)
++        {
++            if (pcoin->IsSpent(n) && (txindex.vSpent.size() <= n || txindex.vSpent[n].IsNull()))
++            {
++                printf("CheckSpentCoins found lost coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
++                nMismatchFound++;
++                nBalanceInQuestion += pcoin->vout[n].nValue;
++            }
++            else if (!pcoin->IsSpent(n) && (txindex.vSpent.size() > n && !txindex.vSpent[n].IsNull()))
++            {
++                printf("CheckSpentCoins found spent coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
++                nMismatchFound++;
++                nBalanceInQuestion += pcoin->vout[n].nValue;
++            }
++        }
 +    }
 +    return (nMismatchFound == 0);
 +}
 +
 +// ppcoin: fix wallet spent state according to txindex
 +void CWallet::FixSpentCoins(int& nMismatchFound, int64& nBalanceInQuestion)
 +{
 +    nMismatchFound = 0;
 +    nBalanceInQuestion = 0;
-     CRITICAL_BLOCK(cs_wallet)
-     {
-        vector<CWalletTx*> vCoins;
-        vCoins.reserve(mapWallet.size());
-        for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
-            vCoins.push_back(&(*it).second);
 +
-        CTxDB txdb("r");
-        BOOST_FOREACH(CWalletTx* pcoin, vCoins)
-        {
-            // Find the corresponding transaction index
-            CTxIndex txindex;
-            if (!txdb.ReadTxIndex(pcoin->GetHash(), txindex))
-                continue;
-            for (int n=0; n < pcoin->vout.size(); n++)
-            {
-                if (pcoin->IsSpent(n) && (txindex.vSpent.size() <= n || txindex.vSpent[n].IsNull()))
-                {
-                    printf("FixSpentCoins found lost coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
-                    nMismatchFound++;
-                    nBalanceInQuestion += pcoin->vout[n].nValue;
-                    pcoin->MarkUnspent(n);
-                    pcoin->WriteToDisk();
-                }
-                else if (!pcoin->IsSpent(n) && (txindex.vSpent.size() > n && !txindex.vSpent[n].IsNull()))
-                {
-                    printf("FixSpentCoins found spent coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
-                    nMismatchFound++;
-                    nBalanceInQuestion += pcoin->vout[n].nValue;
-                    pcoin->MarkSpent(n);
-                    pcoin->WriteToDisk();
-                }
-            }
-        }
++    LOCK(cs_wallet);
++    vector<CWalletTx*> vCoins;
++    vCoins.reserve(mapWallet.size());
++    for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
++        vCoins.push_back(&(*it).second);
++
++    CTxDB txdb("r");
++    BOOST_FOREACH(CWalletTx* pcoin, vCoins)
++    {
++        // Find the corresponding transaction index
++        CTxIndex txindex;
++        if (!txdb.ReadTxIndex(pcoin->GetHash(), txindex))
++            continue;
++        for (int n=0; n < pcoin->vout.size(); n++)
++        {
++            if (pcoin->IsSpent(n) && (txindex.vSpent.size() <= n || txindex.vSpent[n].IsNull()))
++            {
++                printf("FixSpentCoins found lost coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
++                nMismatchFound++;
++                nBalanceInQuestion += pcoin->vout[n].nValue;
++                pcoin->MarkUnspent(n);
++                pcoin->WriteToDisk();
++            }
++            else if (!pcoin->IsSpent(n) && (txindex.vSpent.size() > n && !txindex.vSpent[n].IsNull()))
++            {
++                printf("FixSpentCoins found spent coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
++                nMismatchFound++;
++                nBalanceInQuestion += pcoin->vout[n].nValue;
++                pcoin->MarkSpent(n);
++                pcoin->WriteToDisk();
++            }
++        }
 +    }
 +}
 +
 +// ppcoin: disable transaction (only for coinstake)
 +void CWallet::DisableTransaction(const CTransaction &tx)
 +{
 +    if (!tx.IsCoinStake() || !IsFromMe(tx))
 +        return; // only disconnecting coinstake requires marking input unspent
-     CRITICAL_BLOCK(cs_wallet)
++
++    LOCK(cs_wallet);
++    BOOST_FOREACH(const CTxIn& txin, tx.vin)
 +    {
-         BOOST_FOREACH(const CTxIn& txin, tx.vin)
++        map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
++        if (mi != mapWallet.end())
 +        {
-             map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
-             if (mi != mapWallet.end())
++            CWalletTx& prev = (*mi).second;
++            if (txin.prevout.n < prev.vout.size() && IsMine(prev.vout[txin.prevout.n]))
 +            {
-                 CWalletTx& prev = (*mi).second;
-                 if (txin.prevout.n < prev.vout.size() && IsMine(prev.vout[txin.prevout.n]))
-                 {
-                     prev.MarkUnspent(txin.prevout.n);
-                     prev.WriteToDisk();
-                 }
++                prev.MarkUnspent(txin.prevout.n);
++                prev.WriteToDisk();
 +            }
 +        }
 +    }
 +}
 +
  vector<unsigned char> CReserveKey::GetReservedKey()
  {
      if (nIndex == -1)
@@@ -1659,3 -1539,22 +1775,22 @@@ void CReserveKey::ReturnKey(
      vchPubKey.clear();
  }
  
+ void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress)
+ {
+     setAddress.clear();
+     CWalletDB walletdb(strWalletFile);
+     LOCK2(cs_main, cs_wallet);
+     BOOST_FOREACH(const int64& id, setKeyPool)
+     {
+         CKeyPool keypool;
+         if (!walletdb.ReadPool(id, keypool))
+             throw runtime_error("GetAllReserveKeyHashes() : read failed");
+         CBitcoinAddress address(keypool.vchPubKey);
+         assert(!keypool.vchPubKey.empty());
+         if (!HaveKey(address))
+             throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool");
+         setAddress.insert(address);
+     }
+ }
diff --combined src/wallet.h
@@@ -1,32 -1,75 +1,78 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
 +// Copyright (c) 2011-2012 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_WALLET_H
  #define BITCOIN_WALLET_H
  
- #include "bignum.h"
+ #include "main.h"
  #include "key.h"
+ #include "keystore.h"
  #include "script.h"
  
 +extern bool fWalletUnlockStakeOnly;
 +
  class CWalletTx;
  class CReserveKey;
  class CWalletDB;
  
- // A CWallet is an extension of a keystore, which also maintains a set of
- // transactions and balances, and provides the ability to create new
- // transactions
+ /** (client) version numbers for particular wallet features */
+ enum WalletFeature
+ {
+     FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output)
+     FEATURE_WALLETCRYPT = 40000, // wallet encryption
+     FEATURE_COMPRPUBKEY = 60000, // compressed public keys
+     FEATURE_LATEST = 60000
+ };
+ /** A key pool entry */
+ class CKeyPool
+ {
+ public:
+     int64 nTime;
+     std::vector<unsigned char> vchPubKey;
+     CKeyPool()
+     {
+         nTime = GetTime();
+     }
+     CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
+     {
+         nTime = GetTime();
+         vchPubKey = vchPubKeyIn;
+     }
+     IMPLEMENT_SERIALIZE
+     (
+         if (!(nType & SER_GETHASH))
+             READWRITE(nVersion);
+         READWRITE(nTime);
+         READWRITE(vchPubKey);
+     )
+ };
+ /** A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
+  * and provides the ability to create new transactions.
+  */
  class CWallet : public CCryptoKeyStore
  {
  private:
 -    bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
 -    bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
 +    bool SelectCoinsMinConf(int64 nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
 +    bool SelectCoins(int64 nTargetValue, unsigned int nSpendTime, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
  
      CWalletDB *pwalletdbEncryption;
  
+     // the current wallet version: clients below this version are not able to load the wallet
+     int nWalletVersion;
+     // the maxmimum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded
+     int nWalletMaxVersion;
  public:
      mutable CCriticalSection cs_wallet;
  
  
      std::set<int64> setKeyPool;
  
      typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
      MasterKeyMap mapMasterKeys;
      unsigned int nMasterKeyMaxID;
  
      CWallet()
      {
+         nWalletVersion = FEATURE_BASE;
+         nWalletMaxVersion = FEATURE_BASE;
          fFileBacked = false;
          nMasterKeyMaxID = 0;
          pwalletdbEncryption = NULL;
      }
      CWallet(std::string strWalletFileIn)
      {
+         nWalletVersion = FEATURE_BASE;
+         nWalletMaxVersion = FEATURE_BASE;
          strWalletFile = strWalletFileIn;
          fFileBacked = true;
          nMasterKeyMaxID = 0;
  
      std::vector<unsigned char> vchDefaultKey;
  
+     // check whether we are allowed to upgrade (or already support) to the named feature
+     bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; }
      // keystore implementation
+     // Generate a new key
+     std::vector<unsigned char> GenerateNewKey();
      // Adds a key to the store, and saves it to disk.
      bool AddKey(const CKey& key);
      // Adds a key to the store, without saving it to disk (used by LoadWallet)
      bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
  
+     bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
      // Adds an encrypted key to the store, and saves it to disk.
      bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
      // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
-     bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
+     bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
+     bool AddCScript(const CScript& redeemScript);
+     bool LoadCScript(const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(redeemScript); }
  
      bool Unlock(const SecureString& strWalletPassphrase);
      bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
      bool EncryptWallet(const SecureString& strWalletPassphrase);
  
+     void MarkDirty();
      bool AddToWallet(const CWalletTx& wtxIn);
-     bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
+     bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false);
      bool EraseFromWallet(uint256 hash);
      void WalletUpdateSpent(const CTransaction& prevout);
      int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
+     int ScanForWalletTransaction(const uint256& hashTx);
      void ReacceptWalletTransactions();
      void ResendWalletTransactions();
      int64 GetBalance() const;
      int64 GetUnconfirmedBalance() const;
 +    int64 GetStake() const;
 +    int64 GetNewMint() const;
      bool CreateTransaction(const std::vector<std::pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
      bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
 +    bool CreateCoinStake(unsigned int nBits, CTransaction& txNew);
      bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
-     bool BroadcastTransaction(CWalletTx& wtxNew);
      std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
      std::string SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
  
      bool NewKeyPool();
      bool TopUpKeyPool();
+     int64 AddReserveKey(const CKeyPool& keypool);
      void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
      void KeepKey(int64 nIndex);
      void ReturnKey(int64 nIndex);
      bool GetKeyFromPool(std::vector<unsigned char> &key, bool fAllowReuse=true);
      int64 GetOldestKeyPoolTime();
+     void GetAllReserveAddresses(std::set<CBitcoinAddress>& setAddress);
  
      bool IsMine(const CTxIn& txin) const;
      int64 GetDebit(const CTxIn& txin) const;
              throw std::runtime_error("CWallet::GetCredit() : value out of range");
          return (IsMine(txout) ? txout.nValue : 0);
      }
-     bool IsChange(const CTxOut& txout) const
-     {
-         CBitcoinAddress address;
-         if (ExtractAddress(txout.scriptPubKey, this, address))
-             CRITICAL_BLOCK(cs_wallet)
-                 if (!mapAddressBook.count(address))
-                     return true;
-         return false;
-     }
+     bool IsChange(const CTxOut& txout) const;
      int64 GetChange(const CTxOut& txout) const
      {
          if (!MoneyRange(txout.nValue))
          }
          return nChange;
      }
-     void SetBestChain(const CBlockLocator& loc)
-     {
-         CWalletDB walletdb(strWalletFile);
-         walletdb.WriteBestBlock(loc);
-     }
+     void SetBestChain(const CBlockLocator& loc);
  
      int LoadWallet(bool& fFirstRunRet);
- //    bool BackupWallet(const std::string& strDest);
  
      bool SetAddressBookName(const CBitcoinAddress& address, const std::string& strName);
  
  
      void UpdatedTransaction(const uint256 &hashTx)
      {
-         CRITICAL_BLOCK(cs_wallet)
+         {
+             LOCK(cs_wallet);
              vWalletUpdated.push_back(hashTx);
+         }
      }
  
      void PrintWallet(const CBlock& block);
  
      void Inventory(const uint256 &hash)
      {
-         CRITICAL_BLOCK(cs_wallet)
          {
+             LOCK(cs_wallet);
              std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
              if (mi != mapRequestCount.end())
                  (*mi).second++;
  
      bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);
  
+     // signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
+     bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false);
+     // change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format)
+     bool SetMaxVersion(int nVersion);
+     // get the current wallet format (the oldest client version guaranteed to understand this wallet)
+     int GetVersion() { return nWalletVersion; }
++
 +    bool CheckSpentCoins(int& nMismatchSpent, int64& nBalanceInQuestion);
 +    void FixSpentCoins(int& nMismatchSpent, int64& nBalanceInQuestion);
 +    void DisableTransaction(const CTransaction &tx);
  };
  
+ /** A key allocated from the key pool. */
  class CReserveKey
  {
  protected:
@@@ -246,16 -297,15 +307,15 @@@ public
  };
  
  
- //
- // A transaction with a bunch of additional info that only the owner cares
- // about.  It includes any unrecorded transactions needed to link it back
- // to the block chain.
- //
+ /** A transaction with a bunch of additional info that only the owner cares about. 
+  * It includes any unrecorded transactions needed to link it back to the block chain.
+  */
  class CWalletTx : public CMerkleTx
  {
- public:
+ private:
      const CWallet* pwallet;
  
+ public:
      std::vector<CMerkleTx> vtxPrev;
      std::map<std::string, std::string> mapValue;
      std::vector<std::pair<std::string, std::string> > vOrderForm;
      std::vector<char> vfSpent; // which outputs are already spent
  
      // memory only
-     mutable char fDebitCached;
-     mutable char fCreditCached;
-     mutable char fAvailableCreditCached;
-     mutable char fChangeCached;
+     mutable bool fDebitCached;
+     mutable bool fCreditCached;
+     mutable bool fAvailableCreditCached;
+     mutable bool fChangeCached;
      mutable int64 nDebitCached;
      mutable int64 nCreditCached;
      mutable int64 nAvailableCreditCached;
      mutable int64 nChangeCached;
  
-     // memory only UI hints
-     mutable unsigned int nTimeDisplayed;
-     mutable int nLinesDisplayed;
-     mutable char fConfirmedDisplayed;
      CWalletTx()
      {
          Init(NULL);
          nCreditCached = 0;
          nAvailableCreditCached = 0;
          nChangeCached = 0;
-         nTimeDisplayed = 0;
-         nLinesDisplayed = 0;
-         fConfirmedDisplayed = false;
      }
  
      IMPLEMENT_SERIALIZE
      bool UpdateSpent(const std::vector<char>& vfNewSpent)
      {
          bool fReturn = false;
-         for (int i=0; i < vfNewSpent.size(); i++)
+         for (unsigned int i = 0; i < vfNewSpent.size(); i++)
          {
              if (i == vfSpent.size())
                  break;
          fChangeCached = false;
      }
  
+     void BindWallet(CWallet *pwalletIn)
+     {
+         pwallet = pwalletIn;
+         MarkDirty();
+     }
      void MarkSpent(unsigned int nOut)
      {
          if (nOut >= vout.size())
          }
      }
  
 +    void MarkUnspent(unsigned int nOut)
 +    {
 +        if (nOut >= vout.size())
 +            throw std::runtime_error("CWalletTx::MarkUnspent() : nOut out of range");
 +        vfSpent.resize(vout.size());
 +        if (vfSpent[nOut])
 +        {
 +            vfSpent[nOut] = false;
 +            fAvailableCreditCached = false;
 +        }
 +    }
 +
      bool IsSpent(unsigned int nOut) const
      {
          if (nOut >= vout.size())
      int64 GetCredit(bool fUseCache=true) const
      {
          // Must wait until coinbase is safely deep enough in the chain before valuing it
 -        if (IsCoinBase() && GetBlocksToMaturity() > 0)
 +        if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
              return 0;
  
          // GetBalance can assume transactions in mapWallet won't change
      int64 GetAvailableCredit(bool fUseCache=true) const
      {
          // Must wait until coinbase is safely deep enough in the chain before valuing it
 -        if (IsCoinBase() && GetBlocksToMaturity() > 0)
 +        if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
              return 0;
  
          if (fUseCache && fAvailableCreditCached)
              return nAvailableCreditCached;
  
          int64 nCredit = 0;
-         for (int i = 0; i < vout.size(); i++)
+         for (unsigned int i = 0; i < vout.size(); i++)
          {
              if (!IsSpent(i))
              {
          std::vector<const CMerkleTx*> vWorkQueue;
          vWorkQueue.reserve(vtxPrev.size()+1);
          vWorkQueue.push_back(this);
-         for (int i = 0; i < vWorkQueue.size(); i++)
+         for (unsigned int i = 0; i < vWorkQueue.size(); i++)
          {
              const CMerkleTx* ptx = vWorkQueue[i];
  
                  return false;
  
              if (mapPrev.empty())
+             {
                  BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
                      mapPrev[tx.GetHash()] = &tx;
+             }
  
              BOOST_FOREACH(const CTxIn& txin, ptx->vin)
              {
  };
  
  
- //
- // Private key that includes an expiration date in case it never gets used.
- //
+ /** Private key that includes an expiration date in case it never gets used. */
  class CWalletKey
  {
  public:
  
  
  
- //
- // Account information.
- // Stored in wallet with key "acc"+string account name
- //
+ /** Account information.
+  * Stored in wallet with key "acc"+string account name.
+  */
  class CAccount
  {
  public:
  
  
  
- //
- // Internal transfers.
- // Database key is acentry<account><counter>
- //
+ /** Internal transfers.
+  * Database key is acentry<account><counter>.
+  */
  class CAccountingEntry
  {
  public: