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 --cc 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.
  
  
  //
@@@ -252,17 -252,26 +253,26 @@@ 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;
      }
  
diff --cc src/bignum.h
Simple merge
@@@ -1,16 -1,20 +1,22 @@@
  // 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>
@@@ -52,22 -52,35 +54,35 @@@ Object JSONRPCError(int code, const str
      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;
  }
  
  
@@@ -164,14 -223,10 +225,10 @@@ Value stop(const Array& params, bool fH
      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
  }
  
  
@@@ -307,18 -333,14 +335,17 @@@ 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()));
@@@ -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();
@@@ -1478,15 -1616,9 +1621,15 @@@ Value walletpassphrase(const Array& par
              "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;
  }
  
@@@ -1580,8 -1707,8 +1718,8 @@@ Value encryptwallet(const Array& params
      // 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";
  }
  
  
@@@ -1768,10 -1924,10 +1937,10 @@@ Value getmemorypool(const Array& params
  
          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()));
      }
  }
  
+ 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
@@@ -2423,9 -2360,11 +2632,11 @@@ 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"))
      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)
      {
@@@ -2622,17 -2568,8 +2840,8 @@@ Object CallRPC(const string& strMethod
      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"]);
@@@ -2747,8 -2680,15 +2957,17 @@@ int CommandLineRPC(int argc, char *argv
              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);
@@@ -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?
  
      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;
  }
@@@ -1,24 -1,17 +1,24 @@@
- // 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
diff --cc src/db.cpp
@@@ -1,13 -1,12 +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.
+ // 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>
  
@@@ -575,6 -579,24 +609,9 @@@ bool CTxDB::LoadBlockIndex(
      }
      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))
diff --cc src/db.h
+++ b/src/db.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) 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
  
diff --cc src/init.cpp
@@@ -1,10 -1,9 +1,10 @@@
  // 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"
@@@ -64,9 -73,12 +74,12 @@@ void Shutdown(void* parg
          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
      {
@@@ -173,72 -175,82 +178,81 @@@ bool AppInit2(int argc, char* argv[]
      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());
      }
  #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;
      }
  
      // Load data files
      //
      if (fDaemon)
 -        fprintf(stdout, "bitcoin server starting\n");
 +        fprintf(stdout, "ppcoin server starting\n");
-     strErrors = "";
      int64 nStart;
  
      InitMessage(_("Loading addresses..."));
      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
      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;
      }
  
      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;
          }
      }
  
      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);
diff --cc src/main.cpp
@@@ -1,9 -1,8 +1,9 @@@
  // 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"
@@@ -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
@@@ -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);
  }
@@@ -369,38 -476,28 +495,31 @@@ bool CTxMemPool::accept(CTxDB& txdb, CT
      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;
  
      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
                  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
@@@ -598,10 -720,10 +742,10 @@@ bool CWalletTx::AcceptWalletTransaction
          // 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);
              }
          }
@@@ -832,6 -943,15 +976,11 @@@ void static InvalidChainFound(CBlockInd
          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());
+ }
  
  
  
@@@ -876,8 -998,126 +1027,126 @@@ bool CTransaction::DisconnectInputs(CTx
  }
  
  
- 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 (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 (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;
  }
  
@@@ -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)
      {
@@@ -1241,27 -1526,30 +1583,30 @@@ bool CBlock::SetBestChain(CTxDB& txdb, 
      }
      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);
      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
          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;
@@@ -1502,35 -1678,27 +1875,49 @@@ bool CBlock::CheckBlock() cons
          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
@@@ -1571,16 -1735,12 +1958,16 @@@ bool CBlock::AcceptBlock(
          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;
  }
  
@@@ -1633,12 -1783,18 +2023,13 @@@ bool ProcessBlock(CNode* pfrom, CBlock
          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");
          }
      }
  
      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;
++}
  
  
  
@@@ -1985,15 -2098,9 +2422,15 @@@ string GetWarnings(string strFor
          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;
@@@ -2193,15 -2321,12 +2655,19 @@@ bool static ProcessMessage(CNode* pfrom
          }
  
          // 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);
          }
      }
  
 +    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
      {
@@@ -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;
          while (!mapPriority.empty())
          {
              // Take highest priority transaction off priority queue
--            double dPriority = -(*mapPriority.begin()).first;
              CTransaction& tx = *(*mapPriority.begin()).second;
              mapPriority.erase(mapPriority.begin());
  
              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
                  }
              }
          }
+         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();
@@@ -3498,12 -3591,14 +4006,13 @@@ void static BitcoinMiner(CWallet *pwall
                  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
          }
      }
  }
diff --cc src/main.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) 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 <list>
  
+ class CWallet;
  class CBlock;
  class CBlockIndex;
- class CWalletTx;
- class CWallet;
  class CKeyItem;
  class CReserveKey;
- class CWalletDB;
++class COutPoint;
  
  class CAddress;
  class CInv;
@@@ -29,13 -28,11 +30,11 @@@ 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,9 -43,10 +45,12 @@@ 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;
  
  
  
@@@ -69,17 -69,9 +74,11 @@@ 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;
  
  
  
@@@ -366,17 -339,6 +349,17 @@@ 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);
@@@ -510,36 -476,38 +501,44 @@@ public
  
      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 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;
  
      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;
  };
  
  
@@@ -891,40 -884,9 +930,33 @@@ public
          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();
              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;
              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();
      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);
  };
  
  
@@@ -59,13 -12,13 +59,13 @@@ INCLUDEPATHS= 
  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
@@@ -116,29 -56,32 +103,32 @@@ OBJS= 
      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
@@@ -119,52 -101,53 +102,63 @@@ OBJS= 
      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 --cc src/net.cpp
@@@ -1,10 -1,8 +1,9 @@@
  // 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"
@@@ -45,13 -44,14 +45,15 @@@ bool OpenNetworkConnection(const CAddre
  //
  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;
@@@ -407,8 -248,8 +250,8 @@@ bool GetMyExternalIP(CNetAddr& ipRet
  
  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++)
          {
@@@ -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)
@@@ -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)
  {
diff --cc 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
  
@@@ -77,9 -86,9 +87,10 @@@ 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;
@@@ -146,10 -151,9 +153,10 @@@ 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;
          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)
diff --cc src/protocol.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;
  }
  
- //
- // Message header
- //  (4) message start
- //  (12) command
- //  (4) size
- //  (4) checksum
  
  extern unsigned char pchMessageStart[4];
  
diff --cc src/script.cpp
@@@ -1,9 -1,9 +1,10 @@@
  // 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;
diff --cc src/script.h
@@@ -1,7 -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 H_BITCOIN_SCRIPT
  #define H_BITCOIN_SCRIPT
  
  
  #include <boost/foreach.hpp>
  
 +typedef std::vector<unsigned char> valtype;
 +
  class CTransaction;
+ class CKeyStore;
  
+ /** Signature hash types/flags */
  enum
  {
      SIGHASH_ALL = 1,
diff --cc 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
  
diff --cc 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;
  
@@@ -174,12 -205,12 +210,10 @@@ inline int OutputDebugStringF(const cha
      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)
@@@ -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];
@@@ -759,82 -832,77 +848,77 @@@ boost::filesystem::path MyGetSpecialFol
  }
  #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,
      }
  }
  
- 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);
@@@ -1017,14 -1088,163 +1104,164 @@@ string FormatVersion(int nVersion
  
  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
  
  
  
diff --cc 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
  
@@@ -25,20 -31,13 +32,13 @@@ typedef int pid_t; /* define for window
  #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))
diff --cc 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 --cc 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 --cc 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;
  
@@@ -44,10 -60,15 +62,19 @@@ bool CWallet::AddCryptedKey(const vecto
      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())
@@@ -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)
@@@ -763,39 -877,7 +883,35 @@@ int64 CWallet::GetUnconfirmedBalance() 
      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;
@@@ -1052,7 -1130,8 +1167,7 @@@ bool CWallet::CreateTransaction(const v
  
                  // 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,97 -1156,6 +1192,94 @@@ 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)
  {
@@@ -1339,17 -1309,12 +1439,17 @@@ bool CWallet::DelAddressBookName(const 
  
  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");
@@@ -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)
diff --cc src/wallet.h
@@@ -1,17 -1,15 +1,18 @@@
  // 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;
@@@ -86,13 -145,9 +148,12 @@@ public
      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 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: