// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
- #include "cryptopp/sha.h"
#include "db.h"
#include "net.h"
#include "init.h"
typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable;
+ static std::string strRPCUserColonPass;
+
static int64 nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
}
- void PrintConsole(const char* format, ...)
+ void PrintConsole(const std::string &format, ...)
{
char buffer[50000];
int limit = sizeof(buffer);
va_list arg_ptr;
va_start(arg_ptr, format);
- int ret = _vsnprintf(buffer, limit, format, arg_ptr);
+ int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
buffer[limit-1] = 0;
}
printf("%s", buffer);
- #if defined(__WXMSW__) && defined(GUI)
- MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
- #else
fprintf(stdout, "%s", buffer);
- #endif
}
int64 AmountFromValue(const Value& value)
{
double dAmount = value.get_real();
- if (dAmount <= 0.0 || dAmount > 21000000.0)
+ if (dAmount <= 0.0 || dAmount > MAX_MONEY)
throw JSONRPCError(-3, "Invalid amount");
int64 nAmount = roundint64(dAmount * COIN);
if (!MoneyRange(nAmount))
// We already filter duplicates, but these deprecated screw up the sort order
if (strMethod == "getamountreceived" ||
strMethod == "getallreceived" ||
+ strMethod == "getblocknumber" || // deprecated
(strMethod.find("label") != string::npos))
continue;
if (strCommand != "" && strMethod != strCommand)
throw runtime_error(
"stop\n"
"Stop bitcoin server.");
-
+ #ifndef QT_GUI
// Shutdown will take long enough that the response should get back
CreateThread(Shutdown, NULL);
return "bitcoin server stopping";
+ #else
+ throw runtime_error("NYI: cannot shut down GUI with RPC command");
+ #endif
}
}
+ // deprecated
Value getblocknumber(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblocknumber\n"
- "Returns the block number of the latest block in the longest block chain.");
+ "Deprecated. Use getblockcount.");
return nBestHeight;
}
if (fHelp || params.size() < 1 || params.size() > 1)
throw runtime_error(
"settxfee <amount>\n"
- "<amount> is a real and is rounded to the nearest 0.00000001");
+ "<amount> is a real and is rounded to the nearest 0.0001\n"
+ "Minimum and default transaction fee is 1 coin");
// Amount
- int64 nAmount = 0;
- if (params[0].get_real() != 0.0)
- nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
+ int64 nAmount = MIN_TX_FEE;
+ if (params[0].get_real() != 0.0) // rejects 0.0 amounts
+ nAmount = max(nAmount, AmountFromValue(params[0]));
nTransactionFee = nAmount;
return true;
return wtx.GetHash().GetHex();
}
+ static const string strMessageMagic = "Bitcoin Signed Message:\n";
+
+ Value signmessage(const Array& params, bool fHelp)
+ {
+ if (fHelp || params.size() != 2)
+ throw runtime_error(
+ "signmessage <bitcoinaddress> <message>\n"
+ "Sign a message with the private key of an address");
+
+ if (pwalletMain->IsLocked())
+ throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
+
+ string strAddress = params[0].get_str();
+ string strMessage = params[1].get_str();
+
+ CBitcoinAddress addr(strAddress);
+ if (!addr.IsValid())
+ throw JSONRPCError(-3, "Invalid address");
+
+ CKey key;
+ if (!pwalletMain->GetKey(addr, key))
+ throw JSONRPCError(-4, "Private key not available");
+
+ CDataStream ss(SER_GETHASH);
+ ss << strMessageMagic;
+ ss << strMessage;
+
+ vector<unsigned char> vchSig;
+ if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
+ throw JSONRPCError(-5, "Sign failed");
+
+ return EncodeBase64(&vchSig[0], vchSig.size());
+ }
+
+ Value verifymessage(const Array& params, bool fHelp)
+ {
+ if (fHelp || params.size() != 3)
+ throw runtime_error(
+ "verifymessage <bitcoinaddress> <signature> <message>\n"
+ "Verify a signed message");
+
+ string strAddress = params[0].get_str();
+ string strSign = params[1].get_str();
+ string strMessage = params[2].get_str();
+
+ CBitcoinAddress addr(strAddress);
+ if (!addr.IsValid())
+ throw JSONRPCError(-3, "Invalid address");
+
+ bool fInvalid = false;
+ vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
+
+ if (fInvalid)
+ throw JSONRPCError(-5, "Malformed base64 encoding");
+
+ CDataStream ss(SER_GETHASH);
+ ss << strMessageMagic;
+ ss << strMessage;
+
+ CKey key;
+ if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
+ return false;
+
+ return (key.GetAddress() == addr);
+ }
+
Value getreceivedbyaddress(const Array& params, bool fHelp)
{
Object obj;
obj.push_back(Pair("address", address.ToString()));
obj.push_back(Pair("account", strAccount));
- obj.push_back(Pair("label", strAccount)); // deprecated
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj);
int nConf = (*it).second.nConf;
Object obj;
obj.push_back(Pair("account", (*it).first));
- obj.push_back(Pair("label", (*it).first)); // deprecated
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj);
return ret;
}
+ Value listsinceblock(const Array& params, bool fHelp)
+ {
+ if (fHelp)
+ throw runtime_error(
+ "listsinceblock [blockid] [target-confirmations]\n"
+ "Get all transactions in blocks since block [blockid], or all transactions if omitted");
+
+ CBlockIndex *pindex = NULL;
+ int target_confirms = 1;
+
+ if (params.size() > 0)
+ {
+ uint256 blockId = 0;
+
+ blockId.SetHex(params[0].get_str());
+ pindex = CBlockLocator(blockId).GetBlockIndex();
+ }
+
+ if (params.size() > 1)
+ {
+ target_confirms = params[1].get_int();
+
+ if (target_confirms < 1)
+ throw JSONRPCError(-8, "Invalid parameter");
+ }
+
+ int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
+
+ Array transactions;
+
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
+ {
+ CWalletTx tx = (*it).second;
+
+ if (depth == -1 || tx.GetDepthInMainChain() < depth)
+ ListTransactions(tx, "*", 0, true, transactions);
+ }
+
+ uint256 lastblock;
+
+ if (target_confirms == 1)
+ {
+ printf("oops!\n");
+ lastblock = hashBestChain;
+ }
+ else
+ {
+ int target_height = pindexBest->nHeight + 1 - target_confirms;
+
+ CBlockIndex *block;
+ for (block = pindexBest;
+ block && block->nHeight > target_height;
+ block = block->pprev);
+
+ lastblock = block ? block->GetBlockHash() : 0;
+ }
+
+ Object ret;
+ ret.push_back(Pair("transactions", transactions));
+ ret.push_back(Pair("lastblock", lastblock.GetHex()));
+
+ return ret;
+ }
+
Value gettransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
// Note that the walletpassphrase is stored in params[0] which is not mlock()ed
- string strWalletPass;
+ SecureString strWalletPass;
strWalletPass.reserve(100);
- mlock(&strWalletPass[0], strWalletPass.capacity());
- strWalletPass = params[0].get_str();
+ // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make params[0] mlock()'d to begin with.
+ strWalletPass = params[0].get_str().c_str();
if (strWalletPass.length() > 0)
{
if (!pwalletMain->Unlock(strWalletPass))
- {
- fill(strWalletPass.begin(), strWalletPass.end(), '\0');
- munlock(&strWalletPass[0], strWalletPass.capacity());
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
- }
- fill(strWalletPass.begin(), strWalletPass.end(), '\0');
- munlock(&strWalletPass[0], strWalletPass.capacity());
}
else
throw runtime_error(
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
- string strOldWalletPass;
+ // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make params[0] mlock()'d to begin with.
+ SecureString strOldWalletPass;
strOldWalletPass.reserve(100);
- mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
- strOldWalletPass = params[0].get_str();
+ strOldWalletPass = params[0].get_str().c_str();
- string strNewWalletPass;
+ SecureString strNewWalletPass;
strNewWalletPass.reserve(100);
- mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
- strNewWalletPass = params[1].get_str();
+ strNewWalletPass = params[1].get_str().c_str();
if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
throw runtime_error(
"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
- {
- fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
- fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
- munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
- munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
- }
- fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
- fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
- munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
- munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
return Value::null;
}
if (pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
- string strWalletPass;
+ #ifdef QT_GUI
+ // shutting down via RPC while the GUI is running does not work (yet):
+ throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
+ #endif
+
+ // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
+ // Alternately, find a way to make params[0] mlock()'d to begin with.
+ SecureString strWalletPass;
strWalletPass.reserve(100);
- mlock(&strWalletPass[0], strWalletPass.capacity());
- strWalletPass = params[0].get_str();
+ strWalletPass = params[0].get_str().c_str();
if (strWalletPass.length() < 1)
throw runtime_error(
"Encrypts the wallet with <passphrase>.");
if (!pwalletMain->EncryptWallet(strWalletPass))
- {
- fill(strWalletPass.begin(), strWalletPass.end(), '\0');
- munlock(&strWalletPass[0], strWalletPass.capacity());
throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
- }
- fill(strWalletPass.begin(), strWalletPass.end(), '\0');
- munlock(&strWalletPass[0], strWalletPass.capacity());
- 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);
+ return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
}
throw runtime_error(
"getwork [data]\n"
"If [data] is not specified, returns formatted hash data to work on:\n"
- " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
+ " \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
" \"data\" : block data\n"
- " \"hash1\" : formatted hash buffer for second hash\n"
+ " \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
" \"target\" : little endian hash target\n"
"If [data] is specified, tries to solve the block and returns true if it was successful.");
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
Object result;
- result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
+ result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
- result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
+ result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
return result;
}
// Byte reverse
for (int i = 0; i < 128/4; i++)
- ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
+ ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
// Get saved block
if (!mapNewBlock.count(pdata->hashMerkleRoot))
}
+ Value getmemorypool(const Array& params, bool fHelp)
+ {
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "getmemorypool [data]\n"
+ "If [data] is not specified, returns data needed to construct a block to work on:\n"
+ " \"version\" : block version\n"
+ " \"previousblockhash\" : hash of current highest block\n"
+ " \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
+ " \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
+ " \"time\" : timestamp appropriate for next block\n"
+ " \"bits\" : compressed target of next block\n"
+ "If [data] is specified, tries to solve the block and returns true if it was successful.");
+
+ if (params.size() == 0)
+ {
+ if (vNodes.empty())
+ throw JSONRPCError(-9, "Bitcoin is not connected!");
+
+ if (IsInitialBlockDownload())
+ throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
+
+ static CReserveKey reservekey(pwalletMain);
+
+ // Update block
+ static unsigned int nTransactionsUpdatedLast;
+ static CBlockIndex* pindexPrev;
+ static int64 nStart;
+ static CBlock* pblock;
+ if (pindexPrev != pindexBest ||
+ (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
+ {
+ nTransactionsUpdatedLast = nTransactionsUpdated;
+ pindexPrev = pindexBest;
+ nStart = GetTime();
+
+ // Create new block
+ if(pblock)
+ delete pblock;
+ pblock = CreateNewBlock(reservekey);
+ if (!pblock)
+ throw JSONRPCError(-7, "Out of memory");
+ }
+
+ // Update nTime
+ pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ pblock->nNonce = 0;
+
+ Array transactions;
+ BOOST_FOREACH(CTransaction tx, pblock->vtx) {
+ if(tx.IsCoinBase())
+ continue;
+
+ CDataStream ssTx;
+ ssTx << tx;
+
+ transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
+ }
+
+ Object result;
+ result.push_back(Pair("version", pblock->nVersion));
+ result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
+ result.push_back(Pair("transactions", transactions));
+ result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
+ result.push_back(Pair("time", (int64_t)pblock->nTime));
+
+ union {
+ int32_t nBits;
+ char cBits[4];
+ } uBits;
+ uBits.nBits = htonl((int32_t)pblock->nBits);
+ result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
+
+ return result;
+ }
+ else
+ {
+ // Parse parameters
+ CDataStream ssBlock(ParseHex(params[0].get_str()));
+ CBlock pblock;
+ ssBlock >> pblock;
+
+ return ProcessBlock(NULL, &pblock);
+ }
+ }
+
+
make_pair("getnewaddress", &getnewaddress),
make_pair("getaccountaddress", &getaccountaddress),
make_pair("setaccount", &setaccount),
- make_pair("setlabel", &setaccount), // deprecated
make_pair("getaccount", &getaccount),
- make_pair("getlabel", &getaccount), // deprecated
make_pair("getaddressesbyaccount", &getaddressesbyaccount),
- make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
make_pair("sendtoaddress", &sendtoaddress),
- make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
- make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbyaccount", &getreceivedbyaccount),
- make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbyaccount", &listreceivedbyaccount),
- make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
make_pair("backupwallet", &backupwallet),
make_pair("keypoolrefill", &keypoolrefill),
make_pair("walletpassphrase", &walletpassphrase),
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),
};
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
"help",
"stop",
"getblockcount",
- "getblocknumber",
+ "getblocknumber", // deprecated
"getconnectioncount",
"getdifficulty",
"getgenerate",
"getinfo",
"getnewaddress",
"getaccountaddress",
- "setlabel", // deprecated
"getaccount",
- "getlabel", // deprecated
"getaddressesbyaccount",
- "getaddressesbylabel", // deprecated
"backupwallet",
"keypoolrefill",
"walletpassphrase",
"walletlock",
"validateaddress",
"getwork",
+ "getmemorypool",
};
set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
<< "Host: 127.0.0.1\r\n"
<< "Content-Type: application/json\r\n"
<< "Content-Length: " << strMsg.size() << "\r\n"
+ << "Connection: close\r\n"
<< "Accept: application/json\r\n";
BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
s << item.first << ": " << item.second << "\r\n";
"</HEAD>\r\n"
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
- string strStatus;
- if (nStatus == 200) strStatus = "OK";
- else if (nStatus == 400) strStatus = "Bad Request";
- else if (nStatus == 403) strStatus = "Forbidden";
- else if (nStatus == 404) strStatus = "Not Found";
- else if (nStatus == 500) strStatus = "Internal Server Error";
+ const char *cStatus;
+ if (nStatus == 200) cStatus = "OK";
+ else if (nStatus == 400) cStatus = "Bad Request";
+ else if (nStatus == 403) cStatus = "Forbidden";
+ else if (nStatus == 404) cStatus = "Not Found";
+ else if (nStatus == 500) cStatus = "Internal Server Error";
+ else cStatus = "";
return strprintf(
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"\r\n"
"%s",
nStatus,
- strStatus.c_str(),
+ cStatus,
rfc1123Time().c_str(),
strMsg.size(),
FormatFullVersion().c_str(),
return nStatus;
}
- string EncodeBase64(string s)
- {
- BIO *b64, *bmem;
- BUF_MEM *bptr;
-
- b64 = BIO_new(BIO_f_base64());
- BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
- bmem = BIO_new(BIO_s_mem());
- b64 = BIO_push(b64, bmem);
- BIO_write(b64, s.c_str(), s.size());
- BIO_flush(b64);
- BIO_get_mem_ptr(b64, &bptr);
-
- string result(bptr->data, bptr->length);
- BIO_free_all(b64);
-
- return result;
- }
-
- string DecodeBase64(string s)
- {
- BIO *b64, *bmem;
-
- char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
-
- b64 = BIO_new(BIO_f_base64());
- BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
- bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
- bmem = BIO_push(b64, bmem);
- BIO_read(bmem, buffer, s.size());
- BIO_free_all(bmem);
-
- string result(buffer);
- free(buffer);
- return result;
- }
-
bool HTTPAuthorized(map<string, string>& mapHeaders)
{
string strAuth = mapHeaders["authorization"];
return false;
string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
string strUserPass = DecodeBase64(strUserPass64);
- string::size_type nColon = strUserPass.find(":");
- if (nColon == string::npos)
- return false;
- string strUser = strUserPass.substr(0, nColon);
- string strPassword = strUserPass.substr(nColon+1);
- return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
+ return strUserPass == strRPCUserColonPass;
}
//
{
printf("ThreadRPCServer started\n");
- if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
+ strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+ if (strRPCUserColonPass == ":")
{
string strWhatAmI = "To use bitcoind";
if (mapArgs.count("-server"))
else if (mapArgs.count("-daemon"))
strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
PrintConsole(
- _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
+ _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
"If the file does not exist, create it with owner-readable-only file permissions.\n"),
strWhatAmI.c_str(),
GetConfigFile().c_str());
+ #ifndef QT_GUI
CreateThread(Shutdown, NULL);
+ #endif
return;
}
if (valMethod.type() != str_type)
throw JSONRPCError(-32600, "Method must be a string");
string strMethod = valMethod.get_str();
- if (strMethod != "getwork")
+ if (strMethod != "getwork" && strMethod != "getmemorypool")
printf("ThreadRPCServer method=%s\n", strMethod.c_str());
// Parse params
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
- if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
- if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
- if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
- if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]); // deprecated
if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
- if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
- if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "walletpassphrase" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listsinceblock" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendmany" && n > 1)
{
string s = params[1].get_str();
if (strPrint != "")
{
- #if defined(__WXMSW__) && defined(GUI)
- // Windows GUI apps can't print to command line,
- // so settle for a message box yuck
- MyMessageBox(strPrint, "Bitcoin", wxOK);
- #else
fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
- #endif
}
return nRet;
}
--- /dev/null
+ // Copyright (c) 2011 The Bitcoin developers
+ // Distributed under the MIT/X11 software license, see the accompanying
+ // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+ #include <boost/assign/list_of.hpp> // for 'map_list_of()'
+ #include <boost/foreach.hpp>
+
+ #include "headers.h"
+ #include "checkpoints.h"
+
+ namespace Checkpoints
+ {
+ typedef std::map<int, uint256> MapCheckpoints;
+
+ //
+ // What makes a good checkpoint block?
+ // + Is surrounded by blocks with reasonable timestamps
+ // (no blocks before with a timestamp after, none after with
+ // timestamp before)
+ // + Contains no strange transactions
+ //
+ static MapCheckpoints mapCheckpoints =
+ boost::assign::map_list_of
- ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
- ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
- ( 68555, uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a"))
- ( 70567, uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a"))
- ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
- (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
- (118000, uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553"))
- (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
- (140700, uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd"))
- ;
++ ( 0, hashGenesisBlock )
++ ; // ppcoin: no checkpoint yet; to be created in future releases
+
+ bool CheckBlock(int nHeight, const uint256& hash)
+ {
+ if (fTestNet) return true; // Testnet has no checkpoints
+
+ MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight);
+ if (i == mapCheckpoints.end()) return true;
+ return hash == i->second;
+ }
+
+ int GetTotalBlocksEstimate()
+ {
+ if (fTestNet) return 0;
+
+ return mapCheckpoints.rbegin()->first;
+ }
+
+ CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
+ {
+ if (fTestNet) return NULL;
+
+ int64 nResult;
+ BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
+ {
+ const uint256& hash = i.second;
+ std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
+ if (t != mapBlockIndex.end())
+ return t->second;
+ }
+ return NULL;
+ }
+ }
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2011 The PPCoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
#include "db.h"
- #include "rpc.h"
+ #include "bitcoinrpc.h"
#include "net.h"
#include "init.h"
#include "strlcpy.h"
#include <boost/filesystem/fstream.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
+ #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
+ #define _BITCOIN_QT_PLUGINS_INCLUDED
+ #define __INSURE__
+ #include <QtPlugin>
+ Q_IMPORT_PLUGIN(qcncodecs)
+ Q_IMPORT_PLUGIN(qjpcodecs)
+ Q_IMPORT_PLUGIN(qtwcodecs)
+ Q_IMPORT_PLUGIN(qkrcodecs)
+ #endif
+
using namespace std;
using namespace boost;
void ExitTimeout(void* parg)
{
- #ifdef __WXMSW__
+ #ifdef WIN32
Sleep(5000);
ExitProcess(0);
#endif
{
static CCriticalSection cs_Shutdown;
static bool fTaken;
- bool fFirstThread;
- CRITICAL_BLOCK(cs_Shutdown)
+ bool fFirstThread = false;
+ TRY_CRITICAL_BLOCK(cs_Shutdown)
{
fFirstThread = !fTaken;
fTaken = true;
//
// Start
//
- #ifndef GUI
+ #if !defined(QT_GUI)
+#if !defined(PPCOIN_GENESIS)
int main(int argc, char* argv[])
{
bool fRet = false;
return 1;
}
#endif
+#endif
bool AppInit(int argc, char* argv[])
{
// Disable confusing "helpful" text message on abort, ctrl-c
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
- #ifndef __WXMSW__
+ #ifndef WIN32
umask(077);
#endif
- #ifndef __WXMSW__
+ #ifndef WIN32
// Clean shutdown on SIGTERM
struct sigaction sa;
sa.sa_handler = HandleSIGTERM;
string strUsage = string() +
_("Bitcoin version") + " " + FormatFullVersion() + "\n\n" +
_("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
- " bitcoin [options] \t " + "\n" +
- " bitcoin [options] <command> [params]\t " + _("Send command to -server or bitcoind\n") +
- " bitcoin [options] help \t\t " + _("List commands\n") +
- " bitcoin [options] help <command> \t\t " + _("Get help for a command\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") +
_("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") +
" -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") +
+ " -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") +
#ifdef USE_UPNP
#if USE_UPNP
" -noupnp \t " + _("Don't attempt to use UPnP to map the listening port\n") +
#ifdef GUI
" -server \t\t " + _("Accept command line and JSON-RPC commands\n") +
#endif
- #ifndef __WXMSW__
+ #ifndef WIN32
" -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") +
+ #ifdef WIN32
+ " -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: 8332)\n") +
strUsage += string() +
" -? \t\t " + _("This help message\n");
// Remove tabs
strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
fprintf(stderr, "%s", strUsage.c_str());
- #endif
return false;
}
fDebug = GetBoolArg("-debug");
fAllowDNS = GetBoolArg("-dns");
- #ifndef __WXMSW__
+ #ifndef WIN32
fDaemon = GetBoolArg("-daemon");
#else
fDaemon = false;
fServer = GetBoolArg("-server");
/* force fServer when running without GUI */
- #ifndef GUI
+ #if !defined(QT_GUI)
fServer = true;
#endif
-
fPrintToConsole = GetBoolArg("-printtoconsole");
fPrintToDebugger = GetBoolArg("-printtodebugger");
fNoListen = GetBoolArg("-nolisten") || fTOR;
fLogTimestamps = GetBoolArg("-logtimestamps");
+ #ifndef QT_GUI
for (int i = 1; i < argc; i++)
if (!IsSwitchChar(argv[i][0]))
fCommandLine = true;
int ret = CommandLineRPC(argc, argv);
exit(ret);
}
+ #endif
- #ifndef __WXMSW__
+ #ifndef WIN32
if (fDaemon)
{
// Daemonize
ShrinkDebugFile();
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
printf("Bitcoin version %s\n", FormatFullVersion().c_str());
- #ifdef GUI
- printf("OS version %s\n", ((string)wxGetOsDescription()).c_str());
- printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str());
- printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str());
- #endif
printf("Default data directory %s\n", GetDefaultDataDir().c_str());
if (GetBoolArg("-loadblockindextest"))
return false;
}
- //
- // Limit to single instance per user
- // Required to protect the database files if we're going to keep deleting log.*
- //
- #if defined(__WXMSW__) && defined(GUI)
- // wxSingleInstanceChecker doesn't work on Linux
- wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
- for (int i = 0; i < strMutexName.size(); i++)
- if (!isalnum(strMutexName[i]))
- strMutexName[i] = '.';
- wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
- if (psingleinstancechecker->IsAnotherRunning())
- {
- printf("Existing instance found\n");
- unsigned int nStart = GetTime();
- loop
- {
- // Show the previous instance and exit
- HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
- if (hwndPrev)
- {
- if (IsIconic(hwndPrev))
- ShowWindow(hwndPrev, SW_RESTORE);
- SetForegroundWindow(hwndPrev);
- return false;
- }
-
- if (GetTime() > nStart + 60)
- return false;
-
- // Resume this instance if the other exits
- delete psingleinstancechecker;
- Sleep(1000);
- psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
- if (!psingleinstancechecker->IsAnotherRunning())
- break;
- }
- }
- #endif
-
// 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.
strErrors = "";
int64 nStart;
+ InitMessage(_("Loading addresses..."));
printf("Loading addresses...\n");
nStart = GetTimeMillis();
if (!LoadAddresses())
strErrors += _("Error loading addr.dat \n");
printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+ InitMessage(_("Loading block index..."));
printf("Loading block index...\n");
nStart = GetTimeMillis();
if (!LoadBlockIndex())
strErrors += _("Error loading blkindex.dat \n");
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+ InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n");
nStart = GetTimeMillis();
bool fFirstRun;
strErrors += _("Error loading wallet.dat: Wallet corrupted \n");
else if (nLoadWalletRet == DB_TOO_NEW)
strErrors += _("Error loading wallet.dat: Wallet requires newer version of Bitcoin \n");
+ else if (nLoadWalletRet == DB_NEED_REWRITE)
+ {
+ strErrors += _("Wallet needed to be rewritten: restart Bitcoin to complete \n");
+ wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR);
+ return false;
+ }
else
strErrors += _("Error loading wallet.dat \n");
}
}
if (pindexBest != pindexRescan)
{
+ InitMessage(_("Rescanning..."));
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
}
+ InitMessage(_("Done loading"));
printf("Done loading\n");
//// debug print
}
}
- if (GetBoolArg("-nodnsseed"))
- printf("DNS seeding disabled\n");
- else
- DNSAddressSeed();
-
if (mapArgs.count("-paytxfee"))
{
if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
return false;
}
- if (nTransactionFee > 0.25 * COIN)
+ if (nTransactionFee >= 10 * COIN)
wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
}
}
//
- // Create the main window and start the node
+ // Start the node
//
- #ifdef GUI
- if (!fDaemon)
- CreateMainWindow();
- #endif
-
if (!CheckDiskSpace())
return false;
RandAddSeedPerfmon();
if (!CreateThread(StartNode, NULL))
- wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
+ wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
if (fServer)
CreateThread(ThreadRPCServer, NULL);
- #if defined(__WXMSW__) && defined(GUI)
- if (fFirstRun)
- SetStartOnSystemStartup(true);
- #endif
-
- #ifndef GUI
+ #if !defined(QT_GUI)
while (1)
Sleep(5000);
#endif
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2011 The PPCoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
+ #include "checkpoints.h"
#include "db.h"
#include "net.h"
#include "init.h"
- #include "cryptopp/sha.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
map<COutPoint, CInPoint> mapNextTx;
map<uint256, CBlockIndex*> mapBlockIndex;
-uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
+uint256 hashGenesisBlock("0x00000000e74ef41733382f8a94d41bf29f20c6c48a7ab489e1fab0ab719bf676");
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
- const int nTotalBlocksEstimate = 0; // Conservative estimate of total nr of blocks on main chain
const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
CBlockIndex* pindexBest = NULL;
int64 nTimeBestReceived = 0;
+ CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
+
map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
// Settings
int fGenerateBitcoins = false;
-int64 nTransactionFee = 0;
+int64 nTransactionFee = MIN_TX_FEE;
int fLimitProcessors = false;
int nLimitProcessors = 1;
int fMinimizeToTray = true;
#endif
-
-
-
-
-
//////////////////////////////////////////////////////////////////////////////
//
// dispatching functions
//
+ // These functions dispatch to one or all registered wallets
+
+
void RegisterWallet(CWallet* pwalletIn)
{
CRITICAL_BLOCK(cs_setpwalletRegistered)
}
}
+ // check whether the passed transaction is from us
bool static IsFromMe(CTransaction& tx)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
return false;
}
+ // get the wallet transaction with the given hash (if it exists)
bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
return false;
}
+ // erases transaction with the given hash from all wallets
void static EraseFromWallets(uint256 hash)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->EraseFromWallet(hash);
}
+ // make sure all wallets know about the given transaction, in the given block
void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
}
+ // notify wallets about a new best chain
void static SetBestChain(const CBlockLocator& loc)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->SetBestChain(loc);
}
+ // notify wallets about an updated transaction
void static UpdatedTransaction(const uint256& hashTx)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->UpdatedTransaction(hashTx);
}
+ // dump all wallets
void static PrintWallets(const CBlock& block)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->PrintWallet(block);
}
+ // notify wallets about an incoming inventory (for request counts)
void static Inventory(const uint256& hash)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->Inventory(hash);
}
+ // ask wallets to resend their transactions
void static ResendWalletTransactions()
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
{
// Basic checks that don't depend on any context
if (vin.empty())
- return error("CTransaction::CheckTransaction() : vin empty");
+ return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
if (vout.empty())
- return error("CTransaction::CheckTransaction() : vout empty");
+ return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
// Size limits
if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
- return error("CTransaction::CheckTransaction() : size limits failed");
+ return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values
int64 nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout)
{
if (txout.nValue < 0)
- return error("CTransaction::CheckTransaction() : txout.nValue negative");
+ return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
if (txout.nValue > MAX_MONEY)
- return error("CTransaction::CheckTransaction() : txout.nValue too high");
+ return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
- return error("CTransaction::CheckTransaction() : txout total out of range");
+ return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
}
// Check for duplicate inputs
if (IsCoinBase())
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
- return error("CTransaction::CheckTransaction() : coinbase script size");
+ return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
}
else
{
BOOST_FOREACH(const CTxIn& txin, vin)
if (txin.prevout.IsNull())
- return error("CTransaction::CheckTransaction() : prevout is null");
+ return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
}
return true;
// Coinbase is only valid in a block, not as a loose transaction
if (IsCoinBase())
- return error("AcceptToMemoryPool() : coinbase as individual tx");
+ return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
// To help v0.1.5 clients who would see it as a negative number
if ((int64)nLockTime > INT_MAX)
// 34 bytes because a TxOut is:
// 20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length
if (GetSigOpCount() > nSize / 34 || nSize < 100)
- return error("AcceptToMemoryPool() : nonstandard transaction");
+ return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
// Rather not work on nonstandard transactions (unless -testnet)
if (!fTestNet && !IsStandard())
}
// Don't accept it if it can't get into a block
- if (nFees < GetMinFee(1000, true, true))
+ if (nFees < GetMinFee(1000, false, true))
return error("AcceptToMemoryPool() : not enough fees");
// Continuously rate-limit free transactions
return nSubsidy + nFees;
}
- unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast)
-static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
++static const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week
+ static const int64 nTargetSpacing = 10 * 60;
+ static const int64 nInterval = nTargetTimespan / nTargetSpacing;
+
+ //
+ // minimum amount of work that could possibly be required nTime after
+ // minimum work required was nBase
+ //
+ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
{
- const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week
- const int64 nTargetSpacing = 10 * 60;
- const int64 nInterval = nTargetTimespan / nTargetSpacing;
+ CBigNum bnResult;
+ bnResult.SetCompact(nBase);
+ while (nTime > 0 && bnResult < bnProofOfWorkLimit)
+ {
+ // Maximum 400% adjustment...
+ bnResult *= 4;
+ // ... in best-case exactly 4-times-normal target time
+ nTime -= nTargetTimespan*4;
+ }
+ if (bnResult > bnProofOfWorkLimit)
+ bnResult = bnProofOfWorkLimit;
+ return bnResult.GetCompact();
+ }
+ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast)
+ {
-
- // Genesis block
- if (pindexLast == NULL)
+ // Genesis block and first block
+ if (pindexLast == NULL || pindexLast->pprev == NULL)
return bnProofOfWorkLimit.GetCompact();
- // Only change once per interval
- if ((pindexLast->nHeight+1) % nInterval != 0)
- return pindexLast->nBits;
-
- // Go back by what we want to be 14 days worth of blocks
- const CBlockIndex* pindexFirst = pindexLast;
- for (int i = 0; pindexFirst && i < nInterval-1; i++)
- pindexFirst = pindexFirst->pprev;
- assert(pindexFirst);
-
- // Limit adjustment step
- int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
- printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan);
- if (nActualTimespan < nTargetTimespan/4)
- nActualTimespan = nTargetTimespan/4;
- if (nActualTimespan > nTargetTimespan*4)
- nActualTimespan = nTargetTimespan*4;
-
- // Retarget
+ int64 nActualSpacing = pindexLast->GetBlockTime() - pindexLast->pprev->GetBlockTime();
+
+ // ppcoin: target change every block
+ // ppcoin: retarget with exponential moving toward target spacing
CBigNum bnNew;
bnNew.SetCompact(pindexLast->nBits);
- bnNew *= nActualTimespan;
- bnNew /= nTargetTimespan;
+ bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
+ bnNew /= ((nInterval + 1) * nTargetSpacing);
if (bnNew > bnProofOfWorkLimit)
bnNew = bnProofOfWorkLimit;
- /// debug print
- printf("GetNextWorkRequired RETARGET\n");
- printf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
- printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
- printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
-
return bnNew.GetCompact();
}
return true;
}
- // Return conservative estimate of total number of blocks, 0 if unknown
- int GetTotalBlocksEstimate()
+ // Return maximum amount of blocks that other nodes claim to have
+ int GetNumBlocksOfPeers()
{
- if(fTestNet)
- {
- return 0;
- }
- else
- {
- return nTotalBlocksEstimate;
- }
+ return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate());
}
bool IsInitialBlockDownload()
{
- if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold))
+ if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
return true;
static int64 nLastUpdate;
static CBlockIndex* pindexLastBest;
CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee)
{
// Take over previous transactions' spent pointers
+ // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
+ // fMiner is true when called from the internal bitcoin miner
+ // ... both are false when called from CTransaction::AcceptToMemoryPool
if (!IsCoinBase())
{
int64 nValueIn = 0;
}
if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
- return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str());
+ return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
// If prev is coinbase, check that it's matured
if (txPrev.IsCoinBase())
if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
- // Verify signature
- if (!VerifySignature(txPrev, *this, i))
- return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
-
- // Check for conflicts
+ // Skip ECDSA signature verification when connecting blocks (fBlock=true) 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 conflicts (double-spend)
+ // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
+ // for an attacker to attempt to split the network.
if (!txindex.vSpent[prevout.n].IsNull())
return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
// Check for negative or overflow input values
nValueIn += txPrev.vout[prevout.n].nValue;
if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
- return error("ConnectInputs() : txin values out of range");
+ return DoS(100, error("ConnectInputs() : txin values out of range"));
// Mark outpoints as spent
txindex.vSpent[prevout.n] = posThisTx;
}
if (nValueIn < GetValueOut())
- return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str());
+ return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
// Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0)
- return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str());
+ return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
if (nTxFee < nMinFee)
return false;
nFees += nTxFee;
if (!MoneyRange(nFees))
- return error("ConnectInputs() : nFees out of range");
+ return DoS(100, error("ConnectInputs() : nFees out of range"));
}
if (fBlock)
// Size limits
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
- return error("CheckBlock() : size limits failed");
+ return DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount
if (!CheckProofOfWork(GetHash(), nBits))
- return error("CheckBlock() : proof of work failed");
+ return DoS(50, error("CheckBlock() : proof of work failed"));
// Check timestamp
if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
// First transaction must be coinbase, the rest must not be
if (vtx.empty() || !vtx[0].IsCoinBase())
- return error("CheckBlock() : first tx is not coinbase");
+ return DoS(100, error("CheckBlock() : first tx is not coinbase"));
for (int i = 1; i < vtx.size(); i++)
if (vtx[i].IsCoinBase())
- return error("CheckBlock() : more than one coinbase");
+ return DoS(100, error("CheckBlock() : more than one coinbase"));
// Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.CheckTransaction())
- return error("CheckBlock() : CheckTransaction failed");
+ return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
// Check that it's not full of nonstandard transactions
if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
- return error("CheckBlock() : too many nonstandard transactions");
+ return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkleroot
if (hashMerkleRoot != BuildMerkleTree())
- return error("CheckBlock() : hashMerkleRoot mismatch");
+ return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
return true;
}
// Get prev block index
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
if (mi == mapBlockIndex.end())
- return error("AcceptBlock() : prev block not found");
+ return DoS(10, error("AcceptBlock() : prev block not found"));
CBlockIndex* pindexPrev = (*mi).second;
int nHeight = pindexPrev->nHeight+1;
// Check proof of work
if (nBits != GetNextWorkRequired(pindexPrev))
- return error("AcceptBlock() : incorrect proof of work");
+ return DoS(100, error("AcceptBlock() : incorrect proof of work"));
// Check timestamp against prev
if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.IsFinal(nHeight, GetBlockTime()))
- return error("AcceptBlock() : contains a non-final transaction");
+ return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
// Check that the block chain matches the known block chain up to a checkpoint
- if (!fTestNet)
- // ppcoin: no checkpoint yet; to be created after beta
- if ((nHeight == -1 && hash != uint256("0x83f760b87b13d7002eaccc4a5a154aaea0f861e52b6eb481d30a344f55605c01")))
- return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
+ if (!Checkpoints::CheckBlock(nHeight, hash))
+ return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
// Write block to history file
if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
return true;
}
- bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
+ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
{
// Check for duplicate
uint256 hash = pblock->GetHash();
if (!pblock->CheckBlock())
return error("ProcessBlock() : CheckBlock FAILED");
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
+ if (pcheckpoint && pblock->hashPrevBlock != hashBestChain)
+ {
+ // Extra checks to prevent "fill up memory by spamming with bogus blocks"
+ int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
+ if (deltaTime < 0)
+ {
+ pfrom->Misbehaving(100);
+ return error("ProcessBlock() : block with timestamp before last checkpoint");
+ }
+ CBigNum bnNewBlock;
+ bnNewBlock.SetCompact(pblock->nBits);
+ CBigNum bnRequired;
+ bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
+ if (bnNewBlock > bnRequired)
+ {
+ pfrom->Misbehaving(100);
+ return error("ProcessBlock() : block with too little proof-of-work");
+ }
+ }
+
+
// If don't already have its previous block, shunt it off to holding area until we get it
if (!mapBlockIndex.count(pblock->hashPrevBlock))
{
// vMerkleTree: 4a5e1e
// Genesis block
- const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
+ const char* pszTimestamp = "MarketWatch 07/Nov/2011 Gold tops $1,790 to end at over six-week high";
CTransaction txNew;
txNew.vin.resize(1);
txNew.vout.resize(1);
block.hashPrevBlock = 0;
block.hashMerkleRoot = block.BuildMerkleTree();
block.nVersion = 1;
- block.nTime = 1231006505;
+ block.nTime = 1320941849;
block.nBits = 0x1d00ffff;
- block.nNonce = 2083236893;
+ block.nNonce = 725069208;
if (fTestNet)
{
printf("%s\n", block.GetHash().ToString().c_str());
printf("%s\n", hashGenesisBlock.ToString().c_str());
printf("%s\n", block.hashMerkleRoot.ToString().c_str());
- assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+ assert(block.hashMerkleRoot == uint256("0x09cc647316c90e7e14f225113eec3539e80284695c91e7262a65c72c5d75a868"));
block.print();
assert(block.GetHash() == hashGenesisBlock);
{
// Each connection can only send one version message
if (pfrom->nVersion != 0)
+ {
+ pfrom->Misbehaving(1);
return false;
+ }
int64 nTime;
CAddress addrMe;
pfrom->fSuccessfullyConnected = true;
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
+
+ cPeerBlockCounts.input(pfrom->nStartingHeight);
}
else if (pfrom->nVersion == 0)
{
// Must have a version message before anything else
+ pfrom->Misbehaving(1);
return false;
}
if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
return true;
if (vAddr.size() > 1000)
+ {
+ pfrom->Misbehaving(20);
return error("message addr size() = %d", vAddr.size());
+ }
// Store the new addresses
CAddrDB addrDB;
vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > 50000)
+ {
+ pfrom->Misbehaving(20);
return error("message inv size() = %d", vInv.size());
+ }
CTxDB txdb("r");
BOOST_FOREACH(const CInv& inv, vInv)
vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > 50000)
+ {
+ pfrom->Misbehaving(20);
return error("message getdata size() = %d", vInv.size());
+ }
BOOST_FOREACH(const CInv& inv, vInv)
{
printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
AddOrphanTx(vMsg);
}
+ if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
}
if (ProcessBlock(pfrom, &block))
mapAlreadyAskedFor.erase(inv);
+ if (block.nDoS) pfrom->Misbehaving(block.nDoS);
}
return blocks;
}
static const unsigned int pSHA256InitState[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
- inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
+ void SHA256Transform(void* pstate, void* pinput, const void* pinit)
{
- memcpy(pstate, pinit, 32);
- CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput);
+ SHA256_CTX ctx;
+ unsigned char data[64];
+
+ SHA256_Init(&ctx);
+
+ for (int i = 0; i < 16; i++)
+ ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]);
+
+ for (int i = 0; i < 8; i++)
+ ctx.h[i] = ((uint32_t*)pinit)[i];
+
+ SHA256_Update(&ctx, data, sizeof(data));
+ for (int i = 0; i < 8; i++)
+ ((uint32_t*)pstate)[i] = ctx.h[i];
}
//
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, true);
+ // ppcoin: simplify transaction fee - allow free = false
+ int64 nMinFee = tx.GetMinFee(nBlockSize, false, true);
// Connecting shouldn't fail due to dependency on other memory pool transactions
// because we're already processing them in order of dependency
return error("BitcoinMiner : ProcessBlock, block not accepted");
}
- Sleep(2000);
return true;
}
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2011 The PPCoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_MAIN_H
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 = 100000000;
-static const int64 CENT = 1000000;
-static const int64 MIN_TX_FEE = 50000;
+static const int64 COIN = 10000;
+static const int64 CENT = 100;
+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 = 800000000000000 * 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.
void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn);
+ bool ProcessBlock(CNode* pfrom, CBlock* pblock);
bool CheckDiskSpace(uint64 nAdditionalBytes=0);
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
FILE* AppendBlockFile(unsigned int& nFileRet);
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
- int GetTotalBlocksEstimate();
+ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
+ int GetNumBlocksOfPeers();
bool IsInitialBlockDownload();
std::string GetWarnings(std::string strFor);
{
if (scriptPubKey.size() < 6)
return "CTxOut(error)";
- return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
+ return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().substr(0,30).c_str());
}
void print() const
std::vector<CTxOut> vout;
unsigned int nLockTime;
+ // Denial-of-service detection:
+ mutable int nDoS;
+ bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
CTransaction()
{
vin.clear();
vout.clear();
nLockTime = 0;
+ nDoS = 0; // Denial-of-service prevention
}
bool IsNull() const
unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
unsigned int nNewBlockSize = nBlockSize + nBytes;
- int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
+ int64 nMinFee = nBaseFee; // ppcoin: simplify transaction fee
if (fAllowFree)
{
// memory only
mutable std::vector<uint256> vMerkleTree;
+ // Denial-of-service detection:
+ mutable int nDoS;
+ bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
CBlock()
{
nNonce = 0;
vtx.clear();
vMerkleTree.clear();
+ nDoS = 0;
}
bool IsNull() const
fflush(fileout);
if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
{
- #ifdef __WXMSW__
+ #ifdef WIN32
_commit(_fileno(fileout));
#else
fsync(fileno(fileout));
# Copyright (c) 2009-2010 Satoshi Nakamoto
+# Copyright (c) 2011 The PPCoin developers
# Distributed under the MIT/X11 software license, see the accompanying
# file license.txt or http://www.opensource.org/licenses/mit-license.php.
- CXX=g++
-
- WXINCLUDEPATHS=$(shell wx-config --cxxflags)
+ USE_UPNP:=0
- WXLIBS=$(shell wx-config --libs)
+ DEFS=-DNOPCH
- USE_UPNP:=0
+ DEFS += $(addprefix -I,$(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
+ LIBS += $(addprefix -l,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
- DEFS=-DNOPCH -DUSE_SSL
+ LMODE = dynamic
+ LMODE2 = dynamic
+ ifdef STATIC
+ LMODE = static
+ ifeq (${STATIC}, all)
+ LMODE2 = static
+ endif
+ endif
# for boost 1.37, add -mt to the boost libraries
LIBS= \
- -Wl,-Bstatic \
- -l boost_system \
- -l boost_filesystem \
- -l boost_program_options \
- -l boost_thread \
- -l db_cxx \
+ -Wl,-B$(LMODE) \
+ -l boost_system$(BOOST_LIB_SUFFIX) \
+ -l boost_filesystem$(BOOST_LIB_SUFFIX) \
+ -l boost_program_options$(BOOST_LIB_SUFFIX) \
+ -l boost_thread$(BOOST_LIB_SUFFIX) \
+ -l db_cxx$(BDB_LIB_SUFFIX) \
-l ssl \
-l crypto
- ifdef USE_UPNP
+ ifndef USE_UPNP
+ override USE_UPNP = -
+ endif
+ ifneq (${USE_UPNP}, -)
LIBS += -l miniupnpc
DEFS += -DUSE_UPNP=$(USE_UPNP)
endif
+ ifneq (${USE_SSL}, 0)
+ DEFS += -DUSE_SSL
+ endif
+
LIBS+= \
- -Wl,-Bdynamic \
- -l gthread-2.0 \
+ -Wl,-B$(LMODE2) \
-l z \
-l dl \
-l pthread
- DEBUGFLAGS=-g -D__WXDEBUG__
- CXXFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS)
+ # Hardening
+ # Make some classes of vulnerabilities unexploitable in case one is discovered.
+ #
+ # This is a workaround for Ubuntu bug #691722, the default -fstack-protector causes
+ # -fstack-protector-all to be ignored unless -fno-stack-protector is used first.
+ # see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722
+ HARDENING=-fno-stack-protector
+
+ # Stack Canaries
+ # Put numbers at the beginning of each stack frame and check that they are the same.
+ # If a stack buffer if overflowed, it writes over the canary number and then on return
+ # when that number is checked, it won't be the same and the program will exit with
+ # a "Stack smashing detected" error instead of being exploited.
+ HARDENING+=-fstack-protector-all -Wstack-protector
+
+ # Make some important things such as the global offset table read only as soon as
+ # the dynamic linker is finished building it. This will prevent overwriting of addresses
+ # which would later be jumped to.
+ HARDENING+=-Wl,-z,relro -Wl,-z,now
+
+ # Build position independent code to take advantage of Address Space Layout Randomization
+ # offered by some kernels.
+ # see doc/build-unix.txt for more information.
+ ifdef PIE
+ HARDENING+=-fPIE -pie
+ endif
+
+ # -D_FORTIFY_SOURCE=2 does some checking for potentially exploitable code patterns in
+ # the source such overflowing a statically defined buffer.
+ HARDENING+=-D_FORTIFY_SOURCE=2
+ #
+
+
+ DEBUGFLAGS=-g
+ CXXFLAGS=-O2
+ xCXXFLAGS=-pthread -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
HEADERS = \
base58.h \
bignum.h \
+ checkpoints.h \
crypter.h \
db.h \
headers.h \
net.h \
noui.h \
protocol.h \
- rpc.h \
+ bitcoinrpc.h \
script.h \
serialize.h \
strlcpy.h \
- ui.h \
- uibase.h \
uint256.h \
util.h \
wallet.h
OBJS= \
+ obj/checkpoints.o \
obj/crypter.o \
obj/db.o \
obj/init.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
- obj/rpc.o \
+ obj/bitcoinrpc.o \
obj/script.o \
obj/util.o \
- obj/wallet.o \
- cryptopp/obj/sha.o \
- cryptopp/obj/cpu.o
+ obj/wallet.o
- all: bitcoin
+ all: bitcoind
+ # auto-generated dependencies:
+ -include obj/nogui/*.P
+ -include obj/test/*.P
- obj/%.o: %.cpp $(HEADERS)
- $(CXX) -c $(CXXFLAGS) $(WXINCLUDEPATHS) -DGUI -o $@ $<
-
- cryptopp/obj/%.o: cryptopp/%.cpp
- $(CXX) -c $(CXXFLAGS) -O3 -o $@ $<
-
- bitcoin: $(OBJS) obj/ui.o obj/uibase.o
- $(CXX) $(CXXFLAGS) -o $@ $^ $(WXLIBS) $(LIBS)
-
-
- obj/nogui/%.o: %.cpp $(HEADERS)
- $(CXX) -c $(CXXFLAGS) -o $@ $<
+ obj/nogui/%.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)
bitcoind: $(OBJS:obj/%=obj/nogui/%)
- $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS)
+ $(CXX) $(xCXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
- obj/test/test_bitcoin.o: $(wildcard test/*.cpp) $(HEADERS)
- $(CXX) -c $(CFLAGS) -o $@ test/test_bitcoin.cpp
+ obj/test/%.o: test/%.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)
test_bitcoin: obj/test/test_bitcoin.o $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%))
- $(CXX) $(CXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LIBS)
+ $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LDFLAGS) $(LIBS)
clean:
- -rm -f bitcoin bitcoind test_bitcoin genesis
- -rm -f bitcoind test_bitcoin
++ -rm -f bitcoind test_bitcoin genesis
-rm -f obj/*.o
-rm -f obj/nogui/*.o
-rm -f obj/test/*.o
- -rm -f cryptopp/obj/*.o
- -rm -f headers.h.gch
+ -rm -f obj/*.P
+ -rm -f obj/nogui/*.P
+ -rm -f obj/test/*.P
+ -rm -f ppcoin/obj/*.o
+
+ppcoin/obj/genesis.o: ppcoin/genesis.cpp
+ $(CXX) -c $(CXXFLAGS) -o $@ $<
+ $(CXX) -c $(CXXFLAGS) -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.o
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2011 The PPCoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "init.h"
#include "strlcpy.h"
- #ifdef __WXMSW__
+ #ifdef WIN32
#include <string.h>
#endif
#ifdef USE_UPNP
void ThreadMapPort2(void* parg);
#endif
+ void ThreadDNSAddressSeed2(void* parg);
bool OpenNetworkConnection(const CAddress& addrConnect);
bool fProxy = (fUseProxy && addrConnect.IsRoutable());
struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
- #ifdef __WXMSW__
+ #ifdef WIN32
u_long fNonblock = 1;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
#else
return false;
}
socklen_t nRetSize = sizeof(nRet);
- #ifdef __WXMSW__
+ #ifdef WIN32
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
#else
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
return false;
}
}
- #ifdef __WXMSW__
+ #ifdef WIN32
else if (WSAGetLastError() != WSAEISCONN)
#else
else
CNode::ConnectNode immediately turns the socket back to non-blocking
but we'll turn it back to blocking just in case
*/
- #ifdef __WXMSW__
+ #ifdef WIN32
fNonblock = 0;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
#else
printf("connected %s\n", addrConnect.ToString().c_str());
// Set to nonblocking
- #ifdef __WXMSW__
+ #ifdef WIN32
u_long nOne = 1;
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
}
+ std::map<unsigned int, int64> CNode::setBanned;
+ CCriticalSection CNode::cs_setBanned;
+
+ void CNode::ClearBanned()
+ {
+ setBanned.clear();
+ }
+
+ bool CNode::IsBanned(unsigned int ip)
+ {
+ bool fResult = false;
+ CRITICAL_BLOCK(cs_setBanned)
+ {
+ std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
+ if (i != setBanned.end())
+ {
+ int64 t = (*i).second;
+ if (GetTime() < t)
+ fResult = true;
+ }
+ }
+ return fResult;
+ }
+
+ bool CNode::Misbehaving(int howmuch)
+ {
+ if (addr.IsLocal())
+ {
+ printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
+ return false;
+ }
+
+ nMisbehavior += howmuch;
+ if (nMisbehavior >= GetArg("-banscore", 100))
+ {
+ int64 banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
+ CRITICAL_BLOCK(cs_setBanned)
+ if (setBanned[addr.ip] < banTime)
+ setBanned[addr.ip] = banTime;
+ CloseSocketDisconnect();
+ printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
+ return true;
+ }
+ return false;
+ }
+
{
closesocket(hSocket);
}
+ else if (CNode::IsBanned(addr.ip))
+ {
+ printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
+ closesocket(hSocket);
+ }
else
{
printf("accepted connection %s\n", addr.ToString().c_str());
const char * rootdescurl = 0;
const char * multicastif = 0;
const char * minissdpdpath = 0;
struct UPNPDev * devlist = 0;
char lanaddr[64];
+ #ifndef UPNPDISCOVER_SUCCESS
+ /* miniupnpc 1.5 */
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
+ #else
+ /* miniupnpc 1.6 */
+ int error = 0;
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
+ #endif
struct UPNPUrls urls;
struct IGDdatas data;
char intClient[16];
char intPort[6];
string strDesc = "Bitcoin " + FormatFullVersion();
+ #ifndef UPNPDISCOVER_SUCCESS
+ /* miniupnpc 1.5 */
+ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
+ port, port, lanaddr, strDesc.c_str(), "TCP", 0);
+ #else
+ /* miniupnpc 1.6 */
r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
+ #endif
if(r!=UPNPCOMMAND_SUCCESS)
printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
static const char *strDNSSeed[] = {
- "bitseed.xf2.org",
- "dnsseed.bluematt.me",
+ // "seeds.ppcoin.org"
};
- void DNSAddressSeed()
+ void ThreadDNSAddressSeed(void* parg)
{
+ IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg));
+ try
+ {
+ vnThreadsRunning[6]++;
+ ThreadDNSAddressSeed2(parg);
+ vnThreadsRunning[6]--;
+ }
+ catch (std::exception& e) {
+ vnThreadsRunning[6]--;
+ PrintException(&e, "ThreadDNSAddressSeed()");
+ } catch (...) {
+ vnThreadsRunning[6]--;
+ throw; // support pthread_cancel()
+ }
+ printf("ThreadDNSAddressSeed exiting\n");
+ }
+
+ void ThreadDNSAddressSeed2(void* parg)
+ {
+ printf("ThreadDNSAddressSeed started\n");
int found = 0;
if (!fTestNet)
+
+
+
+
+
+
+
+
+
unsigned int pnSeed[] =
{
- 0x6884ac63, 0x3ffecead, 0x2919b953, 0x0942fe50, 0x7a1d922e, 0xcdd6734a, 0x953a5bb6, 0x2c46922e,
- 0xe2a5f143, 0xaa39103a, 0xa06afa5c, 0x135ffd59, 0xe8e82863, 0xf61ef029, 0xf75f042e, 0x2b363532,
- 0x29b2df42, 0x16b1f64e, 0xd46e281b, 0x5280bf58, 0x60372229, 0x1be58e4f, 0xa8496f45, 0x1fb1a057,
- 0x756b3844, 0x3bb79445, 0x0b375518, 0xcccb0102, 0xb682bf2e, 0x46431c02, 0x3a81073a, 0xa3771f1f,
- 0x213a121f, 0x85dc2c1b, 0x56b4323b, 0xb34e8945, 0x3c40b33d, 0xfa276418, 0x1f818d29, 0xebe1e344,
- 0xf6160a18, 0xf4fa384a, 0x34b09558, 0xb882b543, 0xe3ce2253, 0x6abf56d8, 0xe91b1155, 0x688ee6ad,
- 0x2efc6058, 0x4792cd47, 0x0c32f757, 0x4c813a46, 0x8c93644a, 0x37507444, 0x813ad218, 0xdac06d4a,
- 0xe4c63e4b, 0x21a1ea3c, 0x8d88556f, 0x30e9173a, 0x041f681b, 0xdc77ba50, 0xc0072753, 0xceddd44f,
- 0x052d1743, 0xe3c77a4a, 0x13981c3a, 0x5685d918, 0x3c0e4e70, 0x3e56fb54, 0xb676ae0c, 0xac93c859,
- 0x22279f43, 0x975a4542, 0xe527f071, 0xea162f2e, 0x3c65a32e, 0x5be5713b, 0x961ec418, 0xb202922e,
- 0x5ef7be50, 0xce49f53e, 0x05803b47, 0x8463b055, 0x78576153, 0x3ec2ae3a, 0x4bbd7118, 0xafcee043,
- 0x56a3e8ba, 0x6174de4d, 0x8d01ba4b, 0xc9af564e, 0xdbc9c547, 0xa627474d, 0xdada9244, 0xd3b3083a,
- 0x523e071f, 0xd6b96f18, 0xbd527c46, 0xdf2bbb4d, 0xd37b4a4b, 0x3a6a2158, 0xc064b055, 0x18a8e055,
- 0xec4dae3b, 0x0540416c, 0x475b4fbe, 0x064803b2, 0x48e9f062, 0x2898524b, 0xd315ff43, 0xf786d247,
- 0xc7ea2f3e, 0xc087f043, 0xc163354b, 0x8250284d, 0xed300029, 0xbf36e05c, 0x8eb3ae4c, 0xe7aa623e,
- 0x7ced0274, 0xdd362c1b, 0x362b995a, 0xca26b629, 0x3fc41618, 0xb97b364e, 0xa05b8729, 0x0f5e3c43,
- 0xdf942618, 0x6aeb9b5b, 0xbf04762e, 0xfaaeb118, 0x87579958, 0x76520044, 0xc2660c5b, 0x628b201b,
- 0xf193932e, 0x1c0ad045, 0xff908346, 0x8da9d4da, 0xed201c1f, 0xa47a2b1b, 0x330007d4, 0x8ba1ed47,
- 0xb2f02d44, 0x7db62c1b, 0x781c454b, 0xc0300029, 0xb7062a45, 0x88b52e3a, 0x78dd6b63, 0x1cb9b718,
- 0x5d358e47, 0x59912c3b, 0x79607544, 0x5197f759, 0xc023be48, 0xd1013743, 0x0f354057, 0x8e3aac3b,
- 0x4114693e, 0x22316318, 0xe27dda50, 0x878eac3b, 0x4948a21f, 0x5db7f24c, 0x8ccb6157, 0x26a5de18,
- 0x0a11bd43, 0x27bb1e41, 0x60a7a951, 0x3e16b35e, 0x07888b53, 0x5648a853, 0x0149fe50, 0xd070a34f,
- 0x6454c96d, 0xd6e54758, 0xa96dc152, 0x65447861, 0xf6bdf95e, 0x10400202, 0x2c29d483, 0x18174732,
- 0x1d840618, 0x12e61818, 0x089d3f3c, 0x917e931f, 0xd1b0c90e, 0x25bd3c42, 0xeb05775b, 0x7d550c59,
- 0x6cfacb01, 0xe4224444, 0xa41dd943, 0x0f5aa643, 0x5e33731b, 0x81036d50, 0x6f46a0d1, 0x7731be43,
- 0x14840e18, 0xf1e8d059, 0x661d2b1f, 0x40a3201b, 0x9407b843, 0xedf0254d, 0x7bd1a5bc, 0x073dbe51,
- 0xe864a97b, 0x2efd947b, 0xb9ca0e45, 0x4e2113ad, 0xcc305731, 0xd39ca63c, 0x733df918, 0xda172b1f,
- 0xaa03b34d, 0x7230fd4d, 0xf1ce6e3a, 0x2e9fab43, 0xa4010750, 0xa928bd18, 0x6809be42, 0xb19de348,
- 0xff956270, 0x0d795f51, 0xd2dec247, 0x6df5774b, 0xbac11f79, 0xdfb05c75, 0x887683d8, 0xa1e83632,
- 0x2c0f7671, 0x28bcb65d, 0xac2a7545, 0x3eebfc60, 0x304ad7c4, 0xa215a462, 0xc86f0f58, 0xcfb92ebe,
- 0x5e23ed82, 0xf506184b, 0xec0f19b7, 0x060c59ad, 0x86ee3174, 0x85380774, 0xa199a562, 0x02b507ae,
- 0x33eb2163, 0xf2112b1f, 0xb702ba50, 0x131b9618, 0x90ccd04a, 0x08f3273b, 0xecb61718, 0x64b8b44d,
- 0x182bf4dc, 0xc7b68286, 0x6e318d5f, 0xfdb03654, 0xb3272e54, 0xe014ad4b, 0x274e4a31, 0x7806375c,
- 0xbc34a748, 0x1b5ad94a, 0x6b54d10e, 0x73e2ae6e, 0x5529d483, 0x8455a76d, 0x99c13f47, 0x1d811741,
- 0xa9782a78, 0x0b00464d, 0x7266ea50, 0x532dab46, 0x33e1413e, 0x780d0c18, 0x0fb0854e, 0x03370155,
- 0x2693042e, 0xfa3d824a, 0x2bb1681b, 0x37ea2a18, 0x7fb8414b, 0x32e0713b, 0xacf38d3f, 0xa282716f,
- 0xb1a09d7b, 0xa04b764b, 0x83c94d18, 0x05ee4c6d, 0x0e795f51, 0x46984352, 0xf80fc247, 0x3fccb946,
- 0xd7ae244b, 0x0a8e0a4c, 0x57b141bc, 0x3647bed1, 0x1431b052, 0x803a8bbb, 0xfc69056b, 0xf5991862,
- 0x14963b2e, 0xd35d5dda, 0xc6c73574, 0xc8f1405b, 0x0ca4224d, 0xecd36071, 0xa9461754, 0xe7a0ed72,
- 0x559e8346, 0x1c9beec1, 0xc786ea4a, 0x9561b44d, 0x9788074d, 0x1a69934f, 0x23c5614c, 0x07c79d4b,
- 0xc7ee52db, 0xc72df351, 0xcb135e44, 0xa0988346, 0xc211fc4c, 0x87dec34b, 0x1381074d, 0x04a65cb7,
- 0x4409083a, 0x4a407a4c, 0x92b8d37d, 0xacf50b4d, 0xa58aa5bc, 0x448f801f, 0x9c83762e, 0x6fd5734a,
- 0xfe2d454b, 0x84144c55, 0x05190e4c, 0xb2151448, 0x63867a3e, 0x16099018, 0x9c010d3c, 0x962d8f3d,
- 0xd51ee453, 0x9d86801f, 0x68e87b47, 0x6bf7bb73, 0x5fc7910e, 0x10d90118, 0x3db04442, 0x729d3e4b,
- 0xc397d842, 0x57bb15ad, 0x72f31f4e, 0xc9380043, 0x2bb24e18, 0xd9b8ab50, 0xb786801f, 0xf4dc4847,
- 0x85f4bb51, 0x4435995b, 0x5ba07e40, 0x2c57392e, 0x3628124b, 0x9839b64b, 0x6fe8b24d, 0xaddce847,
- 0x75260e45, 0x0c572a43, 0xfea21902, 0xb9f9742e, 0x5a70d443, 0x8fc5910e, 0x868d4744, 0x56245e02,
- 0xd7eb5f02, 0x35c12c1b, 0x4373034b, 0x8786554c, 0xa6facf18, 0x4b11a31f, 0x3570664e, 0x5a64bc42,
- 0x0b03983f, 0x8f457e4c, 0x0fd874c3, 0xb6cf31b2, 0x2bbc2d4e, 0x146ca5b2, 0x9d00b150, 0x048a4153,
- 0xca4dcd43, 0xc1607cca, 0x8234cf57, 0x9c7daead, 0x3dc07658, 0xea5c6e4c, 0xf1a0084e, 0x16d2ee53,
- 0x1b849418, 0xfe913a47, 0x1e988f62, 0x208b644c, 0xc55ee980, 0xbdbce747, 0xf59a384e, 0x0f56091b,
- 0x7417b745, 0x0c37344e, 0x2c62ab47, 0xf8533a4d, 0x8030084d, 0x76b93c4b, 0xda6ea0ad, 0x3c54f618,
- 0x63b0de1f, 0x7370d858, 0x1a70bb4c, 0xdda63b2e, 0x60b2ba50, 0x1ba7d048, 0xbe1b2c1b, 0xabea5747,
- 0x29ad2e4d, 0xe8cd7642, 0x66c80e18, 0x138bf34a, 0xc6145e44, 0x2586794c, 0x07bc5478, 0x0da0b14d,
- 0x8f95354e, 0x9eb11c62, 0xa1545e46, 0x2e7a2602, 0x408c9c3d, 0x59065d55, 0xf51d1a4c, 0x3bbc6a4e,
- 0xc71b2a2e, 0xcdaaa545, 0x17d659d0, 0x5202e7ad, 0xf1b68445, 0x93375961, 0xbd88a043, 0x066ad655,
- 0x890f6318, 0x7b7dca47, 0x99bdd662, 0x3bb4fc53, 0x1231efdc, 0xc0a99444, 0x96bbea47, 0x61ed8748,
- 0x27dfa73b, 0x8d4d1754, 0x3460042e, 0x551f0c4c, 0x8d0e0718, 0x162ddc53, 0x53231718, 0x1ecd65d0,
- 0x944d28bc, 0x3b79d058, 0xaff97fbc, 0x4860006c, 0xc101c90e, 0xace41743, 0xa5975d4c, 0x5cc2703e,
- 0xb55a4450, 0x02d18840, 0xee2765ae, 0xd6012fd5, 0x24c94d7d, 0x8c6eec47, 0x7520ba5d, 0x9e15e460,
- 0x8510b04c, 0x75ec3847, 0x1dfa6661, 0xe172b3ad, 0x5744c90e, 0x52a0a152, 0x8d6fad18, 0x67b74b6d,
- 0x93a089b2, 0x0f3ac5d5, 0xe5de1855, 0x43d25747, 0x4bad804a, 0x55b408d8, 0x60a36441, 0xf553e860,
- 0xdb2fa2c8, 0x03152b32, 0xdd27a7d5, 0x3116a8b8, 0x0a1d708c, 0xeee2f13c, 0x6acf436f, 0xce6eb4ca,
- 0x101cd3d9, 0x1c48a6b8, 0xe57d6f44, 0x93dcf562,
+ 0xfc01a8c0
};
BOOST_FOREACH(CNode* pnode, vNodes)
setConnected.insert(pnode->addr.ip & 0x0000ffff);
+ int64 nANow = GetAdjustedTime();
+
CRITICAL_BLOCK(cs_mapAddresses)
{
BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
const CAddress& addr = item.second;
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
continue;
- int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
- int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
+ int64 nSinceLastSeen = nANow - addr.nTime;
+ int64 nSinceLastTry = nANow - addr.nLastTry;
// Randomize the order in a deterministic way, putting the standard port first
int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
//
if (fShutdown)
return false;
- if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
+ if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
+ FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
return false;
vnThreadsRunning[1]--;
int nOne = 1;
addrLocalHost.port = htons(GetListenPort());
- #ifdef __WXMSW__
+ #ifdef WIN32
// Initialize Windows Sockets
WSADATA wsadata;
int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
- #ifndef __WXMSW__
+ #ifndef WIN32
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted. Not an issue on windows.
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif
- #ifdef __WXMSW__
+ #ifdef WIN32
// Set to nonblocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
#else
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
- #ifdef __WXMSW__
+ #ifdef WIN32
// Get local host ip
char pszHostName[1000] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
// Start threads
//
+ if (GetBoolArg("-nodnsseed"))
+ printf("DNS seeding disabled\n");
+ else
+ if (!CreateThread(ThreadDNSAddressSeed, NULL))
+ printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n");
+
// Map ports with UPnP
if (fHaveUPnP)
MapPort(fUseUPnP);
printf("Error: CreateThread(ThreadIRCSeed) failed\n");
// Send and receive from sockets, accept connections
- CreateThread(ThreadSocketHandler, NULL);
+ if (!CreateThread(ThreadSocketHandler, NULL))
+ printf("Error: CreateThread(ThreadSocketHandler) failed\n");
// Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL))
if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n");
+ if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n");
while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
Sleep(20);
Sleep(50);
if (closesocket(hListenSocket) == SOCKET_ERROR)
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
- #ifdef __WXMSW__
+ #ifdef WIN32
// Shutdown Windows Sockets
WSACleanup();
#endif
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2011 The PPCoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex();
CRYPTO_set_locking_callback(locking_callback);
- #ifdef __WXMSW__
+ #ifdef WIN32
// Seed random number generator with screen scrape and other hardware sources
RAND_screen();
#endif
return;
nLastPerfmon = GetTime();
- #ifdef __WXMSW__
+ #ifdef WIN32
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// Seed with the entire set of perfmon data
unsigned char pdata[250000];
}
}
- #ifdef __WXMSW__
+ #ifdef WIN32
if (fPrintToDebugger)
{
static CCriticalSection cs_OutputDebugStringF;
return ret;
}
-
- string strprintf(const char* format, ...)
+ string strprintf(const std::string &format, ...)
{
char buffer[50000];
char* p = buffer;
{
va_list arg_ptr;
va_start(arg_ptr, format);
- ret = _vsnprintf(p, limit, format, arg_ptr);
+ ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret >= 0 && ret < limit)
break;
return str;
}
-
- bool error(const char* format, ...)
+ bool error(const std::string &format, ...)
{
char buffer[50000];
int limit = sizeof(buffer);
va_list arg_ptr;
va_start(arg_ptr, format);
- int ret = _vsnprintf(buffer, limit, format, arg_ptr);
+ int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
int64 n_abs = (n > 0 ? n : -n);
int64 quotient = n_abs/COIN;
int64 remainder = n_abs%COIN;
- string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder);
+ string str = strprintf("%"PRI64d".%04"PRI64d, quotient, remainder);
// Right-trim excess 0's before the decimal point:
int nTrim = 0;
for (; *p; p++)
if (!isspace(*p))
return false;
- if (strWhole.size() > 14)
+ if (strWhole.size() > 10) // guard against 63 bit overflow
return false;
if (nUnits < 0 || nUnits > COIN)
return false;
return ParseHex(str.c_str());
}
-
void ParseParameters(int argc, char* argv[])
{
mapArgs.clear();
pszValue = strchr(psz, '=');
*pszValue++ = '\0';
}
- #ifdef __WXMSW__
+ #ifdef WIN32
_strlwr(psz);
if (psz[0] == '/')
psz[0] = '-';
}
}
+ string EncodeBase64(const unsigned char* pch, size_t len)
+ {
+ static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ string strRet="";
+ strRet.reserve((len+2)/3*4);
+
+ int mode=0, left=0;
+ const unsigned char *pchEnd = pch+len;
- const char* wxGetTranslation(const char* pszEnglish)
+ while (pch<pchEnd)
+ {
+ int enc = *(pch++);
+ switch (mode)
+ {
+ case 0: // we have no bits
+ strRet += pbase64[enc >> 2];
+ left = (enc & 3) << 4;
+ mode = 1;
+ break;
+
+ case 1: // we have two bits
+ strRet += pbase64[left | (enc >> 4)];
+ left = (enc & 15) << 2;
+ mode = 2;
+ break;
+
+ case 2: // we have four bits
+ strRet += pbase64[left | (enc >> 6)];
+ strRet += pbase64[enc & 63];
+ mode = 0;
+ break;
+ }
+ }
+
+ if (mode)
+ {
+ strRet += pbase64[left];
+ strRet += '=';
+ if (mode == 1)
+ strRet += '=';
+ }
+
+ return strRet;
+ }
+
+ string EncodeBase64(const string& str)
{
- #ifdef GUI
- // Wrapper of wxGetTranslation returning the same const char* type as was passed in
- static CCriticalSection cs;
- CRITICAL_BLOCK(cs)
+ return EncodeBase64((const unsigned char*)str.c_str(), str.size());
+ }
+
+ vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
+ {
+ static const int decode64_table[256] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
+ -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+
+ if (pfInvalid)
+ *pfInvalid = false;
+
+ vector<unsigned char> vchRet;
+ vchRet.reserve(strlen(p)*3/4);
+
+ int mode = 0;
+ int left = 0;
+
+ while (1)
{
- // Look in cache
- static map<string, char*> mapCache;
- map<string, char*>::iterator mi = mapCache.find(pszEnglish);
- if (mi != mapCache.end())
- return (*mi).second;
-
- // wxWidgets translation
- wxString strTranslated = wxGetTranslation(wxString(pszEnglish, wxConvUTF8));
-
- // We don't cache unknown strings because caller might be passing in a
- // dynamic string and we would keep allocating memory for each variation.
- if (strcmp(pszEnglish, strTranslated.utf8_str()) == 0)
- return pszEnglish;
-
- // Add to cache, memory doesn't need to be freed. We only cache because
- // we must pass back a pointer to permanently allocated memory.
- char* pszCached = new char[strlen(strTranslated.utf8_str())+1];
- strcpy(pszCached, strTranslated.utf8_str());
- mapCache[pszEnglish] = pszCached;
- return pszCached;
+ int dec = decode64_table[*p];
+ if (dec == -1) break;
+ p++;
+ switch (mode)
+ {
+ case 0: // we have no bits and get 6
+ left = dec;
+ mode = 1;
+ break;
+
+ case 1: // we have 6 bits and keep 4
+ vchRet.push_back((left<<2) | (dec>>4));
+ left = dec & 15;
+ mode = 2;
+ break;
+
+ case 2: // we have 4 bits and get 6, we keep 2
+ vchRet.push_back((left<<4) | (dec>>2));
+ left = dec & 3;
+ mode = 3;
+ break;
+
+ case 3: // we have 2 bits and get 6
+ vchRet.push_back((left<<6) | dec);
+ mode = 0;
+ break;
+ }
}
- return NULL;
- #else
- return pszEnglish;
- #endif
+
+ if (pfInvalid)
+ switch (mode)
+ {
+ case 0: // 4n base64 characters processed: ok
+ break;
+
+ case 1: // 4n+1 base64 character processed: impossible
+ *pfInvalid = true;
+ break;
+
+ case 2: // 4n+2 base64 characters processed: require '=='
+ if (left || p[0] != '=' || p[1] != '=' || decode64_table[p[2]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 3: // 4n+3 base64 characters processed: require '='
+ if (left || p[0] != '=' || decode64_table[p[1]] != -1)
+ *pfInvalid = true;
+ break;
+ }
+
+ return vchRet;
+ }
+
+ string DecodeBase64(const string& str)
+ {
+ vector<unsigned char> vchRet = DecodeBase64(str.c_str());
+ return string((const char*)&vchRet[0], vchRet.size());
}
void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
{
- #ifdef __WXMSW__
+ #ifdef WIN32
char pszModule[MAX_PATH];
pszModule[0] = '\0';
GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
printf("\n\n************************\n%s\n", pszMessage);
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
strMiscWarning = pszMessage;
- #ifdef GUI
- if (wxTheApp && !fDaemon)
- MyMessageBox(pszMessage, "Bitcoin", wxOK | wxICON_ERROR);
- #endif
throw;
}
printf("\n\n************************\n%s\n", pszMessage);
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
strMiscWarning = pszMessage;
- #ifdef GUI
- if (wxTheApp && !fDaemon)
- boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
- #endif
}
- #ifdef __WXMSW__
+ #ifdef WIN32
typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
string MyGetSpecialFolderPath(int nFolder, bool fCreate)
string GetDefaultDataDir()
{
- // 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 __WXMSW__
+ #ifdef WIN32
// Windows
- return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
+ return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\PPCoin";
#else
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
string strHome = pszHome;
if (strHome[strHome.size()-1] != '/')
strHome += '/';
- #ifdef __WXMAC_OSX__
+ #ifdef MAC_OSX
// Mac
strHome += "Library/Application Support/";
filesystem::create_directory(strHome.c_str());
- return strHome + "Bitcoin";
+ return strHome + "PPCoin";
#else
// Unix
- return strHome + ".bitcoin";
+ return strHome + ".ppcoin";
#endif
#endif
}
string GetConfigFile()
{
namespace fs = boost::filesystem;
- fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
+ fs::path pathConfig(GetArg("-conf", "ppcoin.conf"));
if (!pathConfig.is_complete())
pathConfig = fs::path(GetDataDir()) / pathConfig;
return pathConfig.string();
string GetPidFile()
{
namespace fs = boost::filesystem;
- fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
+ fs::path pathConfig(GetArg("-pid", "ppcoind.pid"));
if (!pathConfig.is_complete())
pathConfig = fs::path(GetDataDir()) / pathConfig;
return pathConfig.string();
// - Median of other nodes's clocks
// - The user (asking the user to fix the system clock if the first two disagree)
//
+ static int64 nMockTime = 0; // For unit testing
+
int64 GetTime()
{
+ if (nMockTime) return nMockTime;
+
return time(NULL);
}
+ void SetMockTime(int64 nMockTimeIn)
+ {
+ nMockTime = nMockTimeIn;
+ }
+
static int64 nTimeOffset = 0;
int64 GetAdjustedTime()
-// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2011 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2011 The PPCoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
#include "db.h"
- #include "cryptopp/sha.h"
#include "crypter.h"
using namespace std;
else
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
}
+ return false;
}
- bool CWallet::Unlock(const string& strWalletPassphrase)
+ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
if (!IsLocked())
return false;
return false;
}
- bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
+ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
{
bool fWasLocked = IsLocked();
)
};
- bool CWallet::EncryptWallet(const string& strWalletPassphrase)
+ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
if (IsCrypted())
return false;
}
Lock();
+ Unlock(strWalletPassphrase);
+ NewKeyPool();
+ Lock();
+
+ // Need to completely rewrite the wallet file; if we don't, bdb might keep
+ // bits of the unencrypted private key in slack space in the database file.
+ CDB::Rewrite(strWalletFile);
}
return true;
if (fInsertedNew || fUpdated)
if (!wtx.WriteToDisk())
return false;
-
+ #ifndef QT_GUI
// If default receiving address gets used, replace it with a new one
CScript scriptDefaultKey;
scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
}
}
}
-
+ #endif
// Notify UI
vWalletUpdated.push_back(hash);
return true;
}
+ // Add a transaction to the wallet, or update it.
+ // pblock is optional, but should be provided if the transaction is known to be in a block.
+ // If fUpdate is true, existing transactions will be updated.
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{
uint256 hash = tx.GetHash();
return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
}
+ // Scan the block chain (starting in pindexStart) for transactions
+ // from or to us. If fUpdate is true, found transactions that already
+ // exist in the wallet will be updated.
int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
{
int ret = 0;
return nTotal;
}
+ int64 CWallet::GetUnconfirmedBalance() const
+ {
+ int64 nTotal = 0;
+ CRITICAL_BLOCK(cs_wallet)
+ {
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ if (pcoin->IsFinal() && pcoin->IsConfirmed())
+ continue;
+ nTotal += pcoin->GetAvailableCredit();
+ }
+ }
+ return nTotal;
+ }
bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
{
dPriority /= nBytes;
// Check that enough fee is included
- int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
- bool fAllowFree = CTransaction::AllowFree(dPriority);
- int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
+ int64 nPayFee = nTransactionFee; // ppcoin: simplify tx fee
+ int64 nMinFee = wtxNew.GetMinFee(1, false);
if (nFeeRet < max(nPayFee, nMinFee))
{
nFeeRet = max(nPayFee, nMinFee);
return false;
fFirstRunRet = false;
int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
+ if (nLoadWalletRet == DB_NEED_REWRITE)
+ {
+ if (CDB::Rewrite(strWalletFile, "\x04pool"))
+ {
+ setKeyPool.clear();
+ // Note: can't top-up keypool here, because wallet is locked.
+ // User will be prompted to unlock wallet the next operation
+ // the requires a new key.
+ }
+ nLoadWalletRet = DB_NEED_REWRITE;
+ }
+
if (nLoadWalletRet != DB_LOAD_OK)
return nLoadWalletRet;
fFirstRunRet = vchDefaultKey.empty();
return true;
}
+ //
+ // Mark old keypool keys as used,
+ // and generate all new keys
+ //
+ bool CWallet::NewKeyPool()
+ {
+ CRITICAL_BLOCK(cs_wallet)
+ {
+ CWalletDB walletdb(strWalletFile);
+ BOOST_FOREACH(int64 nIndex, setKeyPool)
+ walletdb.ErasePool(nIndex);
+ setKeyPool.clear();
+
+ if (IsLocked())
+ return false;
+
+ int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
+ for (int i = 0; i < nKeys; i++)
+ {
+ int64 nIndex = i+1;
+ walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
+ setKeyPool.insert(nIndex);
+ }
+ printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys);
+ }
+ return true;
+ }
+
bool CWallet::TopUpKeyPool()
{
CRITICAL_BLOCK(cs_wallet)