// 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.
//
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;
}
// 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>
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;
}
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
}
"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()));
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();
"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;
}
// 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";
}
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
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)
{
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"]);
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);
- // 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;
}
- // 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
// 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>
}
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))
// 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
// 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"
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
{
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);
// 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"
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;
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
}
// 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);
}
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
// 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);
}
}
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());
+ }
+
}
- 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;
}
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)
{
}
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;
if (vtx[i].IsCoinBase())
return DoS(100, error("CheckBlock() : more than one coinbase"));
+ // ppcoin: only the second transaction can be the optional coinstake
+ for (int i = 2; i < vtx.size(); i++)
+ if (vtx[i].IsCoinStake())
+ return DoS(100, error("CheckBlock() : coinstake in wrong position"));
+
+ // ppcoin: coinbase output should be empty if proof-of-stake block
+ if (IsProofOfStake() && !vtx[0].vout[0].IsEmpty())
+ return error("CheckBlock() : coinbase output not empty for proof-of-stake block");
+
+ // Check coinbase timestamp
+ if (GetBlockTime() > (int64)vtx[0].nTime + nMaxClockDrift)
+ return DoS(50, error("CheckBlock() : coinbase timestamp is too early"));
+
+ // Check coinstake timestamp
+ if (IsProofOfStake() && GetBlockTime() > (int64)vtx[1].nTime + nMaxClockDrift)
+ return DoS(50, error("CheckBlock() : coinstake timestamp is too early"));
+
// Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx)
+ {
if (!tx.CheckTransaction())
return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
+ // ppcoin: check transaction timestamp
+ if (GetBlockTime() < (int64)tx.nTime)
+ return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp"));
+ }
- // Check that it's not full of nonstandard transactions
- if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
+ // Check for duplicate txids. This is caught by ConnectInputs(),
+ // but catching it earlier avoids a potential DoS attack:
+ set<uint256> uniqueTx;
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ {
+ uniqueTx.insert(tx.GetHash());
+ }
+ if (uniqueTx.size() != vtx.size())
+ return DoS(100, error("CheckBlock() : duplicate transaction"));
+
+ unsigned int nSigOps = 0;
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ {
+ nSigOps += tx.GetLegacySigOpCount();
+ }
+ if (nSigOps > MAX_BLOCK_SIGOPS)
return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkleroot
if (!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;
}
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;
++}
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;
}
// 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
{
};
+ 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();
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
}
}
}
// 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;
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.
static const int fHaveUPnP = false;
#endif
+static const uint256 hashGenesisBlockOfficial("0x000000007c82d1f0aa2896b01bf533a8cc26a1f44790be4ceb4ecde7bee24add");
+static const uint256 hashGenesisBlockTestNet("0x00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
+ extern CScript COINBASE_FLAGS;
+
+
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;
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);
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;
};
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);
};
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
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
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:
// 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"
//
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;
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++)
{
+ // 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)
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)
{
// 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
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;
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)
#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];
// 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;
// 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,
// 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
// 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;
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)
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];
}
#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);
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
// Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2011 The Bitcoin developers
+ // Copyright (c) 2009-2012 The Bitcoin developers
+// Copyright (c) 2012 The PPCoin developers
// Distributed under the MIT/X11 software license, see the accompanying
- // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
#include <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))
--- /dev/null
+ // 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);
--- /dev/null
+ // 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
- // 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;
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())
{
// 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)
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;
// 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);
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)
{
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");
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)
// 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;
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: