Page MenuHomePhabricator

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/doc/coding.txt b/doc/coding.txt
index b3c812a486..21fcfaf766 100644
--- a/doc/coding.txt
+++ b/doc/coding.txt
@@ -1,99 +1,99 @@
Please be consistent with the existing coding style.
Block style:
bool Function(char* psz, int n)
{
// Comment summarising what this section of code does
for (int i = 0; i < n; i++)
{
// When something fails, return early
if (!Something())
return false;
...
}
// Success return is usually at the end
return true;
}
- ANSI/Allman block style
- 4 space indenting, no tabs
- No extra spaces inside parenthesis; please don't do ( this )
- No space after function names, one space after if, for and while
Variable names begin with the type in lowercase, like nSomeVariable.
Please don't put the first word of the variable name in lowercase like
someVariable.
Common types:
n integer number: short, unsigned short, int, unsigned int,
- int64, uint64, sometimes char if used as a number
+ int64_t, uint64_t, sometimes char if used as a number
d double, float
f flag
hash uint256
p pointer or array, one p for each level of indirection
psz pointer to null terminated string
str string object
v vector or similar list objects
map map or multimap
set set or multiset
bn CBigNum
-------------------------
Locking/mutex usage notes
The code is multi-threaded, and uses mutexes and the
CRITICAL_BLOCK/TRY_CRITICAL_BLOCK macros to protect data structures.
Deadlocks due to inconsistent lock ordering (thread 1 locks cs_main
and then cs_wallet, while thread 2 locks them in the opposite order:
result, deadlock as each waits for the other to release its lock) are
a problem. Compile with -DDEBUG_LOCKORDER to get lock order
inconsistencies reported in the debug.log file.
Re-architecting the core code so there are better-defined interfaces
between the various components is a goal, with any necessary locking
done by the components (e.g. see the self-contained CKeyStore class
and its cs_KeyStore lock for example).
-------
Threads
StartNode : Starts other threads.
ThreadGetMyExternalIP : Determines outside-the-firewall IP address,
sends addr message to connected peers when it determines it.
ThreadIRCSeed : Joins IRC bootstrapping channel, watching for new
peers and advertising this node's IP address.
ThreadSocketHandler : Sends/Receives data from peers on port 8333.
ThreadMessageHandler : Higher-level message handling (sending and
receiving).
ThreadOpenConnections : Initiates new connections to peers.
ThreadTopUpKeyPool : replenishes the keystore's keypool.
ThreadCleanWalletPassphrase : re-locks an encrypted wallet after user
has unlocked it for a period of time.
SendingDialogStartTransfer : used by pay-via-ip-address code (obsolete)
ThreadDelayedRepaint : repaint the gui
ThreadFlushWalletDB : Close the wallet.dat file if it hasn't been used
in 500ms.
ThreadRPCServer : Remote procedure call handler, listens on port 8332
for connections and services them.
ThreadBitcoinMiner : Generates bitcoins
ThreadMapPort : Universal plug-and-play startup/shutdown
Shutdown : Does an orderly shutdown of everything
ExitTimeout : Windows-only, sleeps 5 seconds then exits application
diff --git a/src/base58.h b/src/base58.h
index cba638f4e0..3f2d82f11b 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -1,406 +1,408 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
//
// Why base-58 instead of standard base-64 encoding?
// - Don't want 0OIl characters that look the same in some fonts and
// could be used to create visually identical looking account numbers.
// - A string with non-alphanumeric characters is not as easily accepted as an account number.
// - E-mail usually won't line-break if there's no punctuation to break at.
// - Doubleclicking selects the whole number as one word if it's all alphanumeric.
//
#ifndef BITCOIN_BASE58_H
#define BITCOIN_BASE58_H
+#include <stdint.h>
+
#include <string>
#include <vector>
#include "bignum.h"
#include "key.h"
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
// Encode a byte sequence as a base58-encoded string
inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{
CAutoBN_CTX pctx;
CBigNum bn58 = 58;
CBigNum bn0 = 0;
// Convert big endian data to little endian
// Extra zero at the end make sure bignum will interpret as a positive number
std::vector<unsigned char> vchTmp(pend-pbegin+1, 0);
reverse_copy(pbegin, pend, vchTmp.begin());
// Convert little endian data to bignum
CBigNum bn;
bn.setvch(vchTmp);
// Convert bignum to std::string
std::string str;
// Expected size increase from base58 conversion is approximately 137%
// use 138% to be safe
str.reserve((pend - pbegin) * 138 / 100 + 1);
CBigNum dv;
CBigNum rem;
while (bn > bn0)
{
if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
throw bignum_error("EncodeBase58 : BN_div failed");
bn = dv;
unsigned int c = rem.getulong();
str += pszBase58[c];
}
// Leading zeroes encoded as base58 zeros
for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
str += pszBase58[0];
// Convert little endian std::string to big endian
reverse(str.begin(), str.end());
return str;
}
// Encode a byte vector as a base58-encoded string
inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
{
return EncodeBase58(&vch[0], &vch[0] + vch.size());
}
// Decode a base58-encoded string psz into byte vector vchRet
// returns true if decoding is succesful
inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
{
CAutoBN_CTX pctx;
vchRet.clear();
CBigNum bn58 = 58;
CBigNum bn = 0;
CBigNum bnChar;
while (isspace(*psz))
psz++;
// Convert big endian string to bignum
for (const char* p = psz; *p; p++)
{
const char* p1 = strchr(pszBase58, *p);
if (p1 == NULL)
{
while (isspace(*p))
p++;
if (*p != '\0')
return false;
break;
}
bnChar.setulong(p1 - pszBase58);
if (!BN_mul(&bn, &bn, &bn58, pctx))
throw bignum_error("DecodeBase58 : BN_mul failed");
bn += bnChar;
}
// Get bignum as little endian data
std::vector<unsigned char> vchTmp = bn.getvch();
// Trim off sign byte if present
if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80)
vchTmp.erase(vchTmp.end()-1);
// Restore leading zeros
int nLeadingZeros = 0;
for (const char* p = psz; *p == pszBase58[0]; p++)
nLeadingZeros++;
vchRet.assign(nLeadingZeros + vchTmp.size(), 0);
// Convert little endian data to big endian
reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size());
return true;
}
// Decode a base58-encoded string str into byte vector vchRet
// returns true if decoding is succesful
inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
{
return DecodeBase58(str.c_str(), vchRet);
}
// Encode a byte vector to a base58-encoded string, including checksum
inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
{
// add 4-byte hash check to the end
std::vector<unsigned char> vch(vchIn);
uint256 hash = Hash(vch.begin(), vch.end());
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
return EncodeBase58(vch);
}
// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet
// returns true if decoding is succesful
inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
{
if (!DecodeBase58(psz, vchRet))
return false;
if (vchRet.size() < 4)
{
vchRet.clear();
return false;
}
uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)
{
vchRet.clear();
return false;
}
vchRet.resize(vchRet.size()-4);
return true;
}
// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet
// returns true if decoding is succesful
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
{
return DecodeBase58Check(str.c_str(), vchRet);
}
// Base class for all base58-encoded data
class CBase58Data
{
protected:
// the version byte
unsigned char nVersion;
// the actually encoded data
std::vector<unsigned char> vchData;
CBase58Data()
{
nVersion = 0;
vchData.clear();
}
~CBase58Data()
{
// zero the memory, as it may contain sensitive data
if (!vchData.empty())
memset(&vchData[0], 0, vchData.size());
}
void SetData(int nVersionIn, const void* pdata, size_t nSize)
{
nVersion = nVersionIn;
vchData.resize(nSize);
if (!vchData.empty())
memcpy(&vchData[0], pdata, nSize);
}
void SetData(int nVersionIn, const unsigned char *pbegin, const unsigned char *pend)
{
SetData(nVersionIn, (void*)pbegin, pend - pbegin);
}
public:
bool SetString(const char* psz)
{
std::vector<unsigned char> vchTemp;
DecodeBase58Check(psz, vchTemp);
if (vchTemp.empty())
{
vchData.clear();
nVersion = 0;
return false;
}
nVersion = vchTemp[0];
vchData.resize(vchTemp.size() - 1);
if (!vchData.empty())
memcpy(&vchData[0], &vchTemp[1], vchData.size());
memset(&vchTemp[0], 0, vchTemp.size());
return true;
}
bool SetString(const std::string& str)
{
return SetString(str.c_str());
}
std::string ToString() const
{
std::vector<unsigned char> vch(1, nVersion);
vch.insert(vch.end(), vchData.begin(), vchData.end());
return EncodeBase58Check(vch);
}
int CompareTo(const CBase58Data& b58) const
{
if (nVersion < b58.nVersion) return -1;
if (nVersion > b58.nVersion) return 1;
if (vchData < b58.vchData) return -1;
if (vchData > b58.vchData) return 1;
return 0;
}
bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; }
bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; }
bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; }
bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; }
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};
// base58-encoded bitcoin addresses
// Public-key-hash-addresses have version 0 (or 192 testnet)
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key
// Script-hash-addresses (OP_EVAL) have version 5 (or 196 testnet)
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script
class CBitcoinAddress : public CBase58Data
{
public:
enum
{
PUBKEY_ADDRESS = 0,
SCRIPT_ADDRESS = 5,
PUBKEY_ADDRESS_TEST = 192,
PUBKEY_ADDRESS_TEST_LEGACY = 111, // Deprecated: old testnet address
SCRIPT_ADDRESS_TEST = 196,
};
bool SetHash160(const uint160& hash160)
{
SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &hash160, 20);
return true;
}
void SetPubKey(const std::vector<unsigned char>& vchPubKey)
{
SetHash160(Hash160(vchPubKey));
}
bool SetScriptHash160(const uint160& hash160)
{
SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &hash160, 20);
return true;
}
bool IsValid() const
{
int nExpectedSize = 20;
bool fExpectTestNet = false;
switch(nVersion)
{
case PUBKEY_ADDRESS:
nExpectedSize = 20; // Hash of public key
fExpectTestNet = false;
break;
case SCRIPT_ADDRESS:
nExpectedSize = 20; // OP_EVAL, hash of CScript
fExpectTestNet = false;
break;
case PUBKEY_ADDRESS_TEST_LEGACY:
case PUBKEY_ADDRESS_TEST:
nExpectedSize = 20;
fExpectTestNet = true;
break;
case SCRIPT_ADDRESS_TEST:
nExpectedSize = 20;
fExpectTestNet = true;
break;
default:
return false;
}
return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize;
}
bool IsScript() const
{
if (!IsValid())
return false;
if (fTestNet)
return nVersion == SCRIPT_ADDRESS_TEST;
return nVersion == SCRIPT_ADDRESS;
}
CBitcoinAddress()
{
}
CBitcoinAddress(uint160 hash160In)
{
SetHash160(hash160In);
}
CBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
{
SetPubKey(vchPubKey);
}
CBitcoinAddress(const std::string& strAddress)
{
SetString(strAddress);
}
CBitcoinAddress(const char* pszAddress)
{
SetString(pszAddress);
}
uint160 GetHash160() const
{
assert(vchData.size() == 20);
uint160 hash160;
memcpy(&hash160, &vchData[0], 20);
return hash160;
}
};
class CBitcoinSecret : public CBase58Data
{
public:
void SetSecret(const CSecret& vchSecret)
{
SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size());
}
CSecret GetSecret()
{
CSecret vchSecret;
vchSecret.resize(vchData.size());
memcpy(&vchSecret[0], &vchData[0], vchData.size());
return vchSecret;
}
bool IsValid() const
{
int nExpectedSize = 32;
bool fExpectTestNet = false;
switch(nVersion)
{
case 128:
break;
case 239:
fExpectTestNet = true;
break;
default:
return false;
}
return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize;
}
CBitcoinSecret(const CSecret& vchSecret)
{
SetSecret(vchSecret);
}
CBitcoinSecret()
{
}
};
#endif
diff --git a/src/bignum.h b/src/bignum.h
index 135eade679..baa9cb55da 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -1,538 +1,540 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_BIGNUM_H
#define BITCOIN_BIGNUM_H
+#include <stdint.h>
+
#include <stdexcept>
#include <vector>
#include <openssl/bn.h>
#include "util.h"
class bignum_error : public std::runtime_error
{
public:
explicit bignum_error(const std::string& str) : std::runtime_error(str) {}
};
class CAutoBN_CTX
{
protected:
BN_CTX* pctx;
BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; }
public:
CAutoBN_CTX()
{
pctx = BN_CTX_new();
if (pctx == NULL)
throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL");
}
~CAutoBN_CTX()
{
if (pctx != NULL)
BN_CTX_free(pctx);
}
operator BN_CTX*() { return pctx; }
BN_CTX& operator*() { return *pctx; }
BN_CTX** operator&() { return &pctx; }
bool operator!() { return (pctx == NULL); }
};
class CBigNum : public BIGNUM
{
public:
CBigNum()
{
BN_init(this);
}
CBigNum(const CBigNum& b)
{
BN_init(this);
if (!BN_copy(this, &b))
{
BN_clear_free(this);
throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed");
}
}
CBigNum& operator=(const CBigNum& b)
{
if (!BN_copy(this, &b))
throw bignum_error("CBigNum::operator= : BN_copy failed");
return (*this);
}
~CBigNum()
{
BN_clear_free(this);
}
CBigNum(char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
- CBigNum(int64 n) { BN_init(this); setint64(n); }
+ CBigNum(int64_t n) { BN_init(this); setint64(n); }
CBigNum(unsigned char n) { BN_init(this); setulong(n); }
CBigNum(unsigned short n) { BN_init(this); setulong(n); }
CBigNum(unsigned int n) { BN_init(this); setulong(n); }
CBigNum(unsigned long n) { BN_init(this); setulong(n); }
- CBigNum(uint64 n) { BN_init(this); setuint64(n); }
+ CBigNum(uint64_t n) { BN_init(this); setuint64(n); }
explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); }
explicit CBigNum(const std::vector<unsigned char>& vch)
{
BN_init(this);
setvch(vch);
}
void setulong(unsigned long n)
{
if (!BN_set_word(this, n))
throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed");
}
unsigned long getulong() const
{
return BN_get_word(this);
}
unsigned int getuint() const
{
return BN_get_word(this);
}
int getint() const
{
unsigned long n = BN_get_word(this);
if (!BN_is_negative(this))
return (n > std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
else
return (n > std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
}
- void setint64(int64 n)
+ void setint64(int64_t n)
{
unsigned char pch[sizeof(n) + 6];
unsigned char* p = pch + 4;
bool fNegative = false;
- if (n < (int64)0)
+ if (n < (int64_t)0)
{
n = -n;
fNegative = true;
}
bool fLeadingZeroes = true;
for (int i = 0; i < 8; i++)
{
unsigned char c = (n >> 56) & 0xff;
n <<= 8;
if (fLeadingZeroes)
{
if (c == 0)
continue;
if (c & 0x80)
*p++ = (fNegative ? 0x80 : 0);
else if (fNegative)
c |= 0x80;
fLeadingZeroes = false;
}
*p++ = c;
}
unsigned int nSize = p - (pch + 4);
pch[0] = (nSize >> 24) & 0xff;
pch[1] = (nSize >> 16) & 0xff;
pch[2] = (nSize >> 8) & 0xff;
pch[3] = (nSize) & 0xff;
BN_mpi2bn(pch, p - pch, this);
}
- void setuint64(uint64 n)
+ void setuint64(uint64_t n)
{
unsigned char pch[sizeof(n) + 6];
unsigned char* p = pch + 4;
bool fLeadingZeroes = true;
for (int i = 0; i < 8; i++)
{
unsigned char c = (n >> 56) & 0xff;
n <<= 8;
if (fLeadingZeroes)
{
if (c == 0)
continue;
if (c & 0x80)
*p++ = 0;
fLeadingZeroes = false;
}
*p++ = c;
}
unsigned int nSize = p - (pch + 4);
pch[0] = (nSize >> 24) & 0xff;
pch[1] = (nSize >> 16) & 0xff;
pch[2] = (nSize >> 8) & 0xff;
pch[3] = (nSize) & 0xff;
BN_mpi2bn(pch, p - pch, this);
}
void setuint256(uint256 n)
{
unsigned char pch[sizeof(n) + 6];
unsigned char* p = pch + 4;
bool fLeadingZeroes = true;
unsigned char* pbegin = (unsigned char*)&n;
unsigned char* psrc = pbegin + sizeof(n);
while (psrc != pbegin)
{
unsigned char c = *(--psrc);
if (fLeadingZeroes)
{
if (c == 0)
continue;
if (c & 0x80)
*p++ = 0;
fLeadingZeroes = false;
}
*p++ = c;
}
unsigned int nSize = p - (pch + 4);
pch[0] = (nSize >> 24) & 0xff;
pch[1] = (nSize >> 16) & 0xff;
pch[2] = (nSize >> 8) & 0xff;
pch[3] = (nSize >> 0) & 0xff;
BN_mpi2bn(pch, p - pch, this);
}
uint256 getuint256()
{
unsigned int nSize = BN_bn2mpi(this, NULL);
if (nSize < 4)
return 0;
std::vector<unsigned char> vch(nSize);
BN_bn2mpi(this, &vch[0]);
if (vch.size() > 4)
vch[4] &= 0x7f;
uint256 n = 0;
for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
((unsigned char*)&n)[i] = vch[j];
return n;
}
void setvch(const std::vector<unsigned char>& vch)
{
std::vector<unsigned char> vch2(vch.size() + 4);
unsigned int nSize = vch.size();
// BIGNUM's byte stream format expects 4 bytes of
// big endian size data info at the front
vch2[0] = (nSize >> 24) & 0xff;
vch2[1] = (nSize >> 16) & 0xff;
vch2[2] = (nSize >> 8) & 0xff;
vch2[3] = (nSize >> 0) & 0xff;
// swap data to big endian
reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4);
BN_mpi2bn(&vch2[0], vch2.size(), this);
}
std::vector<unsigned char> getvch() const
{
unsigned int nSize = BN_bn2mpi(this, NULL);
if (nSize < 4)
return std::vector<unsigned char>();
std::vector<unsigned char> vch(nSize);
BN_bn2mpi(this, &vch[0]);
vch.erase(vch.begin(), vch.begin() + 4);
reverse(vch.begin(), vch.end());
return vch;
}
CBigNum& SetCompact(unsigned int nCompact)
{
unsigned int nSize = nCompact >> 24;
std::vector<unsigned char> vch(4 + nSize);
vch[3] = nSize;
if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff;
if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff;
if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff;
BN_mpi2bn(&vch[0], vch.size(), this);
return *this;
}
unsigned int GetCompact() const
{
unsigned int nSize = BN_bn2mpi(this, NULL);
std::vector<unsigned char> vch(nSize);
nSize -= 4;
BN_bn2mpi(this, &vch[0]);
unsigned int nCompact = nSize << 24;
if (nSize >= 1) nCompact |= (vch[4] << 16);
if (nSize >= 2) nCompact |= (vch[5] << 8);
if (nSize >= 3) nCompact |= (vch[6] << 0);
return nCompact;
}
void SetHex(const std::string& str)
{
// skip 0x
const char* psz = str.c_str();
while (isspace(*psz))
psz++;
bool fNegative = false;
if (*psz == '-')
{
fNegative = true;
psz++;
}
if (psz[0] == '0' && tolower(psz[1]) == 'x')
psz += 2;
while (isspace(*psz))
psz++;
// hex string to bignum
static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
*this = 0;
while (isxdigit(*psz))
{
*this <<= 4;
int n = phexdigit[*psz++];
*this += n;
}
if (fNegative)
*this = 0 - *this;
}
std::string ToString(int nBase=10) const
{
CAutoBN_CTX pctx;
CBigNum bnBase = nBase;
CBigNum bn0 = 0;
std::string str;
CBigNum bn = *this;
BN_set_negative(&bn, false);
CBigNum dv;
CBigNum rem;
if (BN_cmp(&bn, &bn0) == 0)
return "0";
while (BN_cmp(&bn, &bn0) > 0)
{
if (!BN_div(&dv, &rem, &bn, &bnBase, pctx))
throw bignum_error("CBigNum::ToString() : BN_div failed");
bn = dv;
unsigned int c = rem.getulong();
str += "0123456789abcdef"[c];
}
if (BN_is_negative(this))
str += "-";
reverse(str.begin(), str.end());
return str;
}
std::string GetHex() const
{
return ToString(16);
}
unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
{
return ::GetSerializeSize(getvch(), nType, nVersion);
}
template<typename Stream>
void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
{
::Serialize(s, getvch(), nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
{
std::vector<unsigned char> vch;
::Unserialize(s, vch, nType, nVersion);
setvch(vch);
}
bool operator!() const
{
return BN_is_zero(this);
}
CBigNum& operator+=(const CBigNum& b)
{
if (!BN_add(this, this, &b))
throw bignum_error("CBigNum::operator+= : BN_add failed");
return *this;
}
CBigNum& operator-=(const CBigNum& b)
{
*this = *this - b;
return *this;
}
CBigNum& operator*=(const CBigNum& b)
{
CAutoBN_CTX pctx;
if (!BN_mul(this, this, &b, pctx))
throw bignum_error("CBigNum::operator*= : BN_mul failed");
return *this;
}
CBigNum& operator/=(const CBigNum& b)
{
*this = *this / b;
return *this;
}
CBigNum& operator%=(const CBigNum& b)
{
*this = *this % b;
return *this;
}
CBigNum& operator<<=(unsigned int shift)
{
if (!BN_lshift(this, this, shift))
throw bignum_error("CBigNum:operator<<= : BN_lshift failed");
return *this;
}
CBigNum& operator>>=(unsigned int shift)
{
// Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
// if built on ubuntu 9.04 or 9.10, probably depends on version of openssl
CBigNum a = 1;
a <<= shift;
if (BN_cmp(&a, this) > 0)
{
*this = 0;
return *this;
}
if (!BN_rshift(this, this, shift))
throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
return *this;
}
CBigNum& operator++()
{
// prefix operator
if (!BN_add(this, this, BN_value_one()))
throw bignum_error("CBigNum::operator++ : BN_add failed");
return *this;
}
const CBigNum operator++(int)
{
// postfix operator
const CBigNum ret = *this;
++(*this);
return ret;
}
CBigNum& operator--()
{
// prefix operator
CBigNum r;
if (!BN_sub(&r, this, BN_value_one()))
throw bignum_error("CBigNum::operator-- : BN_sub failed");
*this = r;
return *this;
}
const CBigNum operator--(int)
{
// postfix operator
const CBigNum ret = *this;
--(*this);
return ret;
}
friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b);
friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b);
};
inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
{
CBigNum r;
if (!BN_add(&r, &a, &b))
throw bignum_error("CBigNum::operator+ : BN_add failed");
return r;
}
inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
{
CBigNum r;
if (!BN_sub(&r, &a, &b))
throw bignum_error("CBigNum::operator- : BN_sub failed");
return r;
}
inline const CBigNum operator-(const CBigNum& a)
{
CBigNum r(a);
BN_set_negative(&r, !BN_is_negative(&r));
return r;
}
inline const CBigNum operator*(const CBigNum& a, const CBigNum& b)
{
CAutoBN_CTX pctx;
CBigNum r;
if (!BN_mul(&r, &a, &b, pctx))
throw bignum_error("CBigNum::operator* : BN_mul failed");
return r;
}
inline const CBigNum operator/(const CBigNum& a, const CBigNum& b)
{
CAutoBN_CTX pctx;
CBigNum r;
if (!BN_div(&r, NULL, &a, &b, pctx))
throw bignum_error("CBigNum::operator/ : BN_div failed");
return r;
}
inline const CBigNum operator%(const CBigNum& a, const CBigNum& b)
{
CAutoBN_CTX pctx;
CBigNum r;
if (!BN_mod(&r, &a, &b, pctx))
throw bignum_error("CBigNum::operator% : BN_div failed");
return r;
}
inline const CBigNum operator<<(const CBigNum& a, unsigned int shift)
{
CBigNum r;
if (!BN_lshift(&r, &a, shift))
throw bignum_error("CBigNum:operator<< : BN_lshift failed");
return r;
}
inline const CBigNum operator>>(const CBigNum& a, unsigned int shift)
{
CBigNum r = a;
r >>= shift;
return r;
}
inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); }
inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); }
inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); }
inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); }
inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); }
inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); }
#endif
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index bed90d4f6c..0c22e0bb8b 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -1,2670 +1,2672 @@
// Copyright (c) 2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "db.h"
#include "net.h"
#include "init.h"
#undef printf
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#ifdef USE_SSL
#include <boost/asio/ssl.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
#endif
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"
#define printf OutputDebugStringF
// MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
// precompiled in headers.h. The problem might be when the pch file goes over
// a certain size around 145MB. If we need access to json_spirit outside this
// file, we could use the compiled json_spirit option.
using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace json_spirit;
void ThreadRPCServer2(void* parg);
typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable;
static std::string strRPCUserColonPass;
-static int64 nWalletUnlockTime;
+static int64_t nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
extern Value dumpprivkey(const Array& params, bool fHelp);
extern Value importprivkey(const Array& params, bool fHelp);
Object JSONRPCError(int code, const string& message)
{
Object error;
error.push_back(Pair("code", code));
error.push_back(Pair("message", message));
return error;
}
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.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
ret = limit - 1;
buffer[limit-1] = 0;
}
printf("%s", buffer);
fprintf(stdout, "%s", buffer);
}
-int64 AmountFromValue(const Value& value)
+int64_t AmountFromValue(const Value& value)
{
double dAmount = value.get_real();
if (dAmount <= 0.0 || dAmount > 21000000.0)
throw JSONRPCError(-3, "Invalid amount");
- int64 nAmount = roundint64(dAmount * COIN);
+ int64_t nAmount = roundint64(dAmount * COIN);
if (!MoneyRange(nAmount))
throw JSONRPCError(-3, "Invalid amount");
return nAmount;
}
-Value ValueFromAmount(int64 amount)
+Value ValueFromAmount(int64_t amount)
{
return (double)amount / (double)COIN;
}
void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
{
int confirms = wtx.GetDepthInMainChain();
entry.push_back(Pair("confirmations", confirms));
if (confirms)
{
entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
entry.push_back(Pair("blockindex", wtx.nIndex));
}
entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
entry.push_back(Pair(item.first, item.second));
}
string AccountFromValue(const Value& value)
{
string strAccount = value.get_str();
if (strAccount == "*")
throw JSONRPCError(-11, "Invalid account name");
return strAccount;
}
///
/// Note: This interface may still be subject to change.
///
Value help(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"help [command]\n"
"List commands, or get help for a command.");
string strCommand;
if (params.size() > 0)
strCommand = params[0].get_str();
string strRet;
set<rpcfn_type> setDone;
for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
{
string strMethod = (*mi).first;
// 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)
continue;
try
{
Array params;
rpcfn_type pfn = (*mi).second;
if (setDone.insert(pfn).second)
(*pfn)(params, true);
}
catch (std::exception& e)
{
// Help text is returned in an exception
string strHelp = string(e.what());
if (strCommand == "")
if (strHelp.find('\n') != -1)
strHelp = strHelp.substr(0, strHelp.find('\n'));
strRet += strHelp + "\n";
}
}
if (strRet == "")
strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
strRet = strRet.substr(0,strRet.size()-1);
return strRet;
}
Value stop(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
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
}
Value getblockcount(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblockcount\n"
"Returns the number of blocks in the longest block chain.");
return nBestHeight;
}
// deprecated
Value getblocknumber(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblocknumber\n"
"Deprecated. Use getblockcount.");
return nBestHeight;
}
Value getconnectioncount(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getconnectioncount\n"
"Returns the number of connections to other nodes.");
return (int)vNodes.size();
}
double GetDifficulty()
{
// Floating point number that is a multiple of the minimum difficulty,
// minimum difficulty = 1.0.
if (pindexBest == NULL)
return 1.0;
int nShift = (pindexBest->nBits >> 24) & 0xff;
double dDiff =
(double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
while (nShift < 29)
{
dDiff *= 256.0;
nShift++;
}
while (nShift > 29)
{
dDiff /= 256.0;
nShift--;
}
return dDiff;
}
Value getdifficulty(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getdifficulty\n"
"Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
return GetDifficulty();
}
Value getgenerate(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getgenerate\n"
"Returns true or false.");
return (bool)fGenerateBitcoins;
}
Value setgenerate(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"setgenerate <generate> [genproclimit]\n"
"<generate> is true or false to turn generation on or off.\n"
"Generation is limited to [genproclimit] processors, -1 is unlimited.");
bool fGenerate = true;
if (params.size() > 0)
fGenerate = params[0].get_bool();
if (params.size() > 1)
{
int nGenProcLimit = params[1].get_int();
fLimitProcessors = (nGenProcLimit != -1);
WriteSetting("fLimitProcessors", fLimitProcessors);
if (nGenProcLimit != -1)
WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
if (nGenProcLimit == 0)
fGenerate = false;
}
GenerateBitcoins(fGenerate, pwalletMain);
return Value::null;
}
Value gethashespersec(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"gethashespersec\n"
"Returns a recent hashes per second performance measurement while generating.");
if (GetTimeMillis() - nHPSTimerStart > 8000)
return (boost::int64_t)0;
return (boost::int64_t)dHashesPerSec;
}
Value getinfo(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getinfo\n"
"Returns an object containing various state info.");
Object obj;
obj.push_back(Pair("version", (int)CLIENT_VERSION));
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("blocks", (int)nBestHeight));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
obj.push_back(Pair("testnet", fTestNet));
obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize()));
obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
if (pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
}
Value getnewaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"getnewaddress [account]\n"
"Returns a new bitcoin address for receiving payments. "
"If [account] is specified (recommended), it is added to the address book "
"so payments received with the address will be credited to [account].");
// Parse the account first so we don't generate a key if there's an error
string strAccount;
if (params.size() > 0)
strAccount = AccountFromValue(params[0]);
if (!pwalletMain->IsLocked())
pwalletMain->TopUpKeyPool();
// Generate a new key that is added to wallet
std::vector<unsigned char> newKey;
if (!pwalletMain->GetKeyFromPool(newKey, false))
throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
CBitcoinAddress address(newKey);
pwalletMain->SetAddressBookName(address, strAccount);
return address.ToString();
}
CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
{
CWalletDB walletdb(pwalletMain->strWalletFile);
CAccount account;
walletdb.ReadAccount(strAccount, account);
bool bKeyUsed = false;
// Check if the current key has been used
if (!account.vchPubKey.empty())
{
CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(account.vchPubKey);
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
++it)
{
const CWalletTx& wtx = (*it).second;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (txout.scriptPubKey == scriptPubKey)
bKeyUsed = true;
}
}
// Generate a new key
if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
{
if (!pwalletMain->GetKeyFromPool(account.vchPubKey, false))
throw JSONRPCError(-12, "Error: Keypool ran out, please call keypoolrefill first");
pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
walletdb.WriteAccount(strAccount, account);
}
return CBitcoinAddress(account.vchPubKey);
}
Value getaccountaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getaccountaddress <account>\n"
"Returns the current bitcoin address for receiving payments to this account.");
// Parse the account first so we don't generate a key if there's an error
string strAccount = AccountFromValue(params[0]);
Value ret;
ret = GetAccountAddress(strAccount).ToString();
return ret;
}
Value setaccount(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"setaccount <bitcoinaddress> <account>\n"
"Sets the account associated with the given address.");
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(-5, "Invalid bitcoin address");
string strAccount;
if (params.size() > 1)
strAccount = AccountFromValue(params[1]);
// Detect when changing the account of an address that is the 'unused current key' of another account:
if (pwalletMain->mapAddressBook.count(address))
{
string strOldAccount = pwalletMain->mapAddressBook[address];
if (address == GetAccountAddress(strOldAccount))
GetAccountAddress(strOldAccount, true);
}
pwalletMain->SetAddressBookName(address, strAccount);
return Value::null;
}
Value getaccount(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getaccount <bitcoinaddress>\n"
"Returns the account associated with the given address.");
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(-5, "Invalid bitcoin address");
string strAccount;
map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
strAccount = (*mi).second;
return strAccount;
}
Value getaddressesbyaccount(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getaddressesbyaccount <account>\n"
"Returns the list of addresses for the given account.");
string strAccount = AccountFromValue(params[0]);
// Find all addresses that have the given account
Array ret;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
const string& strName = item.second;
if (strName == strAccount)
ret.push_back(address.ToString());
}
return ret;
}
Value settxfee(const Array& params, bool fHelp)
{
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
- int64 nAmount = 0;
+ int64_t nAmount = 0;
if (params[0].get_real() != 0.0)
nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
nTransactionFee = nAmount;
return true;
}
Value sendtoaddress(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
"sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001\n"
"requires wallet passphrase to be set with walletpassphrase first");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
"sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001");
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(-5, "Invalid bitcoin address");
// Amount
- int64 nAmount = AmountFromValue(params[1]);
+ int64_t nAmount = AmountFromValue(params[1]);
// Wallet comments
CWalletTx wtx;
if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
wtx.mapValue["comment"] = params[2].get_str();
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str();
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
if (strError != "")
throw JSONRPCError(-4, strError);
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 (CBitcoinAddress(key.GetPubKey()) == addr);
}
Value getreceivedbyaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
"Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
// Bitcoin address
CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
CScript scriptPubKey;
if (!address.IsValid())
throw JSONRPCError(-5, "Invalid bitcoin address");
scriptPubKey.SetBitcoinAddress(address);
if (!IsMine(*pwalletMain,scriptPubKey))
return (double)0.0;
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 1)
nMinDepth = params[1].get_int();
// Tally
- int64 nAmount = 0;
+ int64_t nAmount = 0;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (txout.scriptPubKey == scriptPubKey)
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
}
return ValueFromAmount(nAmount);
}
void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
{
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
const string& strName = item.second;
if (strName == strAccount)
setAddress.insert(address);
}
}
Value getreceivedbyaccount(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbyaccount <account> [minconf=1]\n"
"Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 1)
nMinDepth = params[1].get_int();
// Get the set of pub keys assigned to account
string strAccount = AccountFromValue(params[0]);
set<CBitcoinAddress> setAddress;
GetAccountAddresses(strAccount, setAddress);
// Tally
- int64 nAmount = 0;
+ int64_t nAmount = 0;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
CBitcoinAddress address;
if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
}
}
return (double)nAmount / (double)COIN;
}
-int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
+int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
{
- int64 nBalance = 0;
+ int64_t nBalance = 0;
// Tally wallet transactions
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (!wtx.IsFinal())
continue;
- int64 nGenerated, nReceived, nSent, nFee;
+ int64_t nGenerated, nReceived, nSent, nFee;
wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
nBalance += nReceived;
nBalance += nGenerated - nSent - nFee;
}
// Tally internal accounting entries
nBalance += walletdb.GetAccountCreditDebit(strAccount);
return nBalance;
}
-int64 GetAccountBalance(const string& strAccount, int nMinDepth)
+int64_t GetAccountBalance(const string& strAccount, int nMinDepth)
{
CWalletDB walletdb(pwalletMain->strWalletFile);
return GetAccountBalance(walletdb, strAccount, nMinDepth);
}
Value getbalance(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
"getbalance [account] [minconf=1]\n"
"If [account] is not specified, returns the server's total available balance.\n"
"If [account] is specified, returns the balance in the account.");
if (params.size() == 0)
return ValueFromAmount(pwalletMain->GetBalance());
int nMinDepth = 1;
if (params.size() > 1)
nMinDepth = params[1].get_int();
if (params[0].get_str() == "*") {
// Calculate total balance a different way from GetBalance()
// (GetBalance() sums up all unspent TxOuts)
// getbalance and getbalance '*' should always return the same number.
- int64 nBalance = 0;
+ int64_t nBalance = 0;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (!wtx.IsFinal())
continue;
- int64 allGeneratedImmature, allGeneratedMature, allFee;
+ int64_t allGeneratedImmature, allGeneratedMature, allFee;
allGeneratedImmature = allGeneratedMature = allFee = 0;
string strSentAccount;
- list<pair<CBitcoinAddress, int64> > listReceived;
- list<pair<CBitcoinAddress, int64> > listSent;
+ list<pair<CBitcoinAddress, int64_t> > listReceived;
+ list<pair<CBitcoinAddress, int64_t> > listSent;
wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
if (wtx.GetDepthInMainChain() >= nMinDepth)
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listReceived)
nBalance += r.second;
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listSent)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listSent)
nBalance -= r.second;
nBalance -= allFee;
nBalance += allGeneratedMature;
}
return ValueFromAmount(nBalance);
}
string strAccount = AccountFromValue(params[0]);
- int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
+ int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
return ValueFromAmount(nBalance);
}
Value movecmd(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 3 || params.size() > 5)
throw runtime_error(
"move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
"Move from one account in your wallet to another.");
string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]);
- int64 nAmount = AmountFromValue(params[2]);
+ int64_t nAmount = AmountFromValue(params[2]);
if (params.size() > 3)
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)params[3].get_int();
string strComment;
if (params.size() > 4)
strComment = params[4].get_str();
CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin();
- int64 nNow = GetAdjustedTime();
+ int64_t nNow = GetAdjustedTime();
// Debit
CAccountingEntry debit;
debit.strAccount = strFrom;
debit.nCreditDebit = -nAmount;
debit.nTime = nNow;
debit.strOtherAccount = strTo;
debit.strComment = strComment;
walletdb.WriteAccountingEntry(debit);
// Credit
CAccountingEntry credit;
credit.strAccount = strTo;
credit.nCreditDebit = nAmount;
credit.nTime = nNow;
credit.strOtherAccount = strFrom;
credit.strComment = strComment;
walletdb.WriteAccountingEntry(credit);
walletdb.TxnCommit();
return true;
}
Value sendfrom(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
throw runtime_error(
"sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001\n"
"requires wallet passphrase to be set with walletpassphrase first");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 3 || params.size() > 6))
throw runtime_error(
"sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.00000001");
string strAccount = AccountFromValue(params[0]);
CBitcoinAddress address(params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(-5, "Invalid bitcoin address");
- int64 nAmount = AmountFromValue(params[2]);
+ int64_t nAmount = AmountFromValue(params[2]);
int nMinDepth = 1;
if (params.size() > 3)
nMinDepth = params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
wtx.mapValue["comment"] = params[4].get_str();
if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
wtx.mapValue["to"] = params[5].get_str();
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
// Check funds
- int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
+ int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
if (nAmount > nBalance)
throw JSONRPCError(-6, "Account has insufficient funds");
// Send
string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
if (strError != "")
throw JSONRPCError(-4, strError);
return wtx.GetHash().GetHex();
}
Value sendmany(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
"sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
"amounts are double-precision floating point numbers\n"
"requires wallet passphrase to be set with walletpassphrase first");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4))
throw runtime_error(
"sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
"amounts are double-precision floating point numbers");
string strAccount = AccountFromValue(params[0]);
Object sendTo = params[1].get_obj();
int nMinDepth = 1;
if (params.size() > 2)
nMinDepth = params[2].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
wtx.mapValue["comment"] = params[3].get_str();
set<CBitcoinAddress> setAddress;
- vector<pair<CScript, int64> > vecSend;
+ vector<pair<CScript, int64_t> > vecSend;
- int64 totalAmount = 0;
+ int64_t totalAmount = 0;
BOOST_FOREACH(const Pair& s, sendTo)
{
CBitcoinAddress address(s.name_);
if (!address.IsValid())
throw JSONRPCError(-5, string("Invalid bitcoin address:")+s.name_);
if (setAddress.count(address))
throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
setAddress.insert(address);
CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(address);
- int64 nAmount = AmountFromValue(s.value_);
+ int64_t nAmount = AmountFromValue(s.value_);
totalAmount += nAmount;
vecSend.push_back(make_pair(scriptPubKey, nAmount));
}
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
// Check funds
- int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
+ int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
if (totalAmount > nBalance)
throw JSONRPCError(-6, "Account has insufficient funds");
// Send
CReserveKey keyChange(pwalletMain);
- int64 nFeeRequired = 0;
+ int64_t nFeeRequired = 0;
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
if (!fCreated)
{
if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
throw JSONRPCError(-6, "Insufficient funds");
throw JSONRPCError(-4, "Transaction creation failed");
}
if (!pwalletMain->CommitTransaction(wtx, keyChange))
throw JSONRPCError(-4, "Transaction commit failed");
return wtx.GetHash().GetHex();
}
Value addmultisigaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 3)
{
string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
"Add a nrequired-to-sign multisignature address to the wallet\"\n"
"each key is a bitcoin address, hex or base58 public key\n"
"If [account] is specified, assign address to [account].";
throw runtime_error(msg);
}
if (!fTestNet)
throw runtime_error("addmultisigaddress available only when running -testnet\n");
int nRequired = params[0].get_int();
const Array& keys = params[1].get_array();
string strAccount;
if (params.size() > 2)
strAccount = AccountFromValue(params[2]);
// Gather public keys
if (keys.size() < nRequired)
throw runtime_error(
strprintf("addmultisigaddress: wrong number of keys (got %d, need at least %d)", keys.size(), nRequired));
std::vector<CKey> pubkeys;
pubkeys.resize(keys.size());
for (int i = 0; i < keys.size(); i++)
{
const std::string& ks = keys[i].get_str();
if (ks.size() == 130) // hex public key
pubkeys[i].SetPubKey(ParseHex(ks));
else if (ks.size() > 34) // base58-encoded
{
std::vector<unsigned char> vchPubKey;
if (DecodeBase58(ks, vchPubKey))
pubkeys[i].SetPubKey(vchPubKey);
else
throw runtime_error("Error base58 decoding key: "+ks);
}
else // bitcoin address for key in this wallet
{
CBitcoinAddress address(ks);
if (!pwalletMain->GetKey(address, pubkeys[i]))
throw runtime_error(
strprintf("addmultisigaddress: unknown address: %s",ks.c_str()));
}
}
// Construct using OP_EVAL
CScript inner;
inner.SetMultisig(nRequired, pubkeys);
uint160 scriptHash = Hash160(inner);
CScript scriptPubKey;
scriptPubKey.SetEval(inner);
pwalletMain->AddCScript(scriptHash, inner);
CBitcoinAddress address;
address.SetScriptHash160(scriptHash);
pwalletMain->SetAddressBookName(address, strAccount);
return address.ToString();
}
struct tallyitem
{
- int64 nAmount;
+ int64_t nAmount;
int nConf;
tallyitem()
{
nAmount = 0;
nConf = std::numeric_limits<int>::max();
}
};
Value ListReceived(const Array& params, bool fByAccounts)
{
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
// Whether to include empty accounts
bool fIncludeEmpty = false;
if (params.size() > 1)
fIncludeEmpty = params[1].get_bool();
// Tally
map<CBitcoinAddress, tallyitem> mapTally;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < nMinDepth)
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
CBitcoinAddress address;
if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
continue;
tallyitem& item = mapTally[address];
item.nAmount += txout.nValue;
item.nConf = min(item.nConf, nDepth);
}
}
// Reply
Array ret;
map<string, tallyitem> mapAccountTally;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
const string& strAccount = item.second;
map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
- int64 nAmount = 0;
+ int64_t nAmount = 0;
int nConf = std::numeric_limits<int>::max();
if (it != mapTally.end())
{
nAmount = (*it).second.nAmount;
nConf = (*it).second.nConf;
}
if (fByAccounts)
{
tallyitem& item = mapAccountTally[strAccount];
item.nAmount += nAmount;
item.nConf = min(item.nConf, nConf);
}
else
{
Object obj;
obj.push_back(Pair("address", address.ToString()));
obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
ret.push_back(obj);
}
}
if (fByAccounts)
{
for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
{
- int64 nAmount = (*it).second.nAmount;
+ int64_t nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
Object obj;
obj.push_back(Pair("account", (*it).first));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
ret.push_back(obj);
}
}
return ret;
}
Value listreceivedbyaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
"listreceivedbyaddress [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include addresses that haven't received any payments.\n"
"Returns an array of objects containing:\n"
" \"address\" : receiving address\n"
" \"account\" : the account of the receiving address\n"
" \"amount\" : total amount received by the address\n"
" \"confirmations\" : number of confirmations of the most recent transaction included");
return ListReceived(params, false);
}
Value listreceivedbyaccount(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
"listreceivedbyaccount [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include accounts that haven't received any payments.\n"
"Returns an array of objects containing:\n"
" \"account\" : the account of the receiving addresses\n"
" \"amount\" : total amount received by addresses with this account\n"
" \"confirmations\" : number of confirmations of the most recent transaction included");
return ListReceived(params, true);
}
void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
{
- int64 nGeneratedImmature, nGeneratedMature, nFee;
+ int64_t nGeneratedImmature, nGeneratedMature, nFee;
string strSentAccount;
- list<pair<CBitcoinAddress, int64> > listReceived;
- list<pair<CBitcoinAddress, int64> > listSent;
+ list<pair<CBitcoinAddress, int64_t> > listReceived;
+ list<pair<CBitcoinAddress, int64_t> > listSent;
wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
bool fAllAccounts = (strAccount == string("*"));
// Generated blocks assigned to account ""
if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
{
Object entry;
entry.push_back(Pair("account", string("")));
if (nGeneratedImmature)
{
entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
}
else
{
entry.push_back(Pair("category", "generate"));
entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
}
if (fLong)
WalletTxToJSON(wtx, entry);
ret.push_back(entry);
}
// Sent
if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& s, listSent)
{
Object entry;
entry.push_back(Pair("account", strSentAccount));
entry.push_back(Pair("address", s.first.ToString()));
entry.push_back(Pair("category", "send"));
entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
if (fLong)
WalletTxToJSON(wtx, entry);
ret.push_back(entry);
}
}
// Received
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& r, listReceived)
{
string account;
if (pwalletMain->mapAddressBook.count(r.first))
account = pwalletMain->mapAddressBook[r.first];
if (fAllAccounts || (account == strAccount))
{
Object entry;
entry.push_back(Pair("account", account));
entry.push_back(Pair("address", r.first.ToString()));
entry.push_back(Pair("category", "receive"));
entry.push_back(Pair("amount", ValueFromAmount(r.second)));
if (fLong)
WalletTxToJSON(wtx, entry);
ret.push_back(entry);
}
}
}
void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
{
bool fAllAccounts = (strAccount == string("*"));
if (fAllAccounts || acentry.strAccount == strAccount)
{
Object entry;
entry.push_back(Pair("account", acentry.strAccount));
entry.push_back(Pair("category", "move"));
entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
entry.push_back(Pair("comment", acentry.strComment));
ret.push_back(entry);
}
}
Value listtransactions(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 3)
throw runtime_error(
"listtransactions [account] [count=10] [from=0]\n"
"Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
string strAccount = "*";
if (params.size() > 0)
strAccount = params[0].get_str();
int nCount = 10;
if (params.size() > 1)
nCount = params[1].get_int();
int nFrom = 0;
if (params.size() > 2)
nFrom = params[2].get_int();
Array ret;
CWalletDB walletdb(pwalletMain->strWalletFile);
// Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
- typedef multimap<int64, TxPair > TxItems;
+ typedef multimap<int64_t, TxPair > TxItems;
TxItems txByTime;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
CWalletTx* wtx = &((*it).second);
txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
}
list<CAccountingEntry> acentries;
walletdb.ListAccountCreditDebit(strAccount, acentries);
BOOST_FOREACH(CAccountingEntry& entry, acentries)
{
txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
}
// Now: iterate backwards until we have nCount items to return:
TxItems::reverse_iterator it = txByTime.rbegin();
if (txByTime.size() > nFrom) std::advance(it, nFrom);
for (; it != txByTime.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
if (pwtx != 0)
ListTransactions(*pwtx, strAccount, 0, true, ret);
CAccountingEntry *const pacentry = (*it).second.second;
if (pacentry != 0)
AcentryToJSON(*pacentry, strAccount, ret);
if (ret.size() >= nCount) break;
}
// ret is now newest to oldest
// Make sure we return only last nCount items (sends-to-self might give us an extra):
if (ret.size() > nCount)
{
Array::iterator last = ret.begin();
std::advance(last, nCount);
ret.erase(last, ret.end());
}
std::reverse(ret.begin(), ret.end()); // oldest to newest
return ret;
}
Value listaccounts(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"listaccounts [minconf=1]\n"
"Returns Object that has account names as keys, account balances as values.");
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
- map<string, int64> mapAccountBalances;
+ map<string, int64_t> mapAccountBalances;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
mapAccountBalances[entry.second] = 0;
}
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- int64 nGeneratedImmature, nGeneratedMature, nFee;
+ int64_t nGeneratedImmature, nGeneratedMature, nFee;
string strSentAccount;
- list<pair<CBitcoinAddress, int64> > listReceived;
- list<pair<CBitcoinAddress, int64> > listSent;
+ list<pair<CBitcoinAddress, int64_t> > listReceived;
+ list<pair<CBitcoinAddress, int64_t> > listSent;
wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
mapAccountBalances[strSentAccount] -= nFee;
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& s, listSent)
mapAccountBalances[strSentAccount] -= s.second;
if (wtx.GetDepthInMainChain() >= nMinDepth)
{
mapAccountBalances[""] += nGeneratedMature;
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& r, listReceived)
if (pwalletMain->mapAddressBook.count(r.first))
mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
else
mapAccountBalances[""] += r.second;
}
}
list<CAccountingEntry> acentries;
CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
Object ret;
- BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
+ BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
}
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 runtime_error(
"gettransaction <txid>\n"
"Get detailed information about <txid>");
uint256 hash;
hash.SetHex(params[0].get_str());
Object entry;
if (!pwalletMain->mapWallet.count(hash))
throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
const CWalletTx& wtx = pwalletMain->mapWallet[hash];
- int64 nCredit = wtx.GetCredit();
- int64 nDebit = wtx.GetDebit();
- int64 nNet = nCredit - nDebit;
- int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
+ int64_t nCredit = wtx.GetCredit();
+ int64_t nDebit = wtx.GetDebit();
+ int64_t nNet = nCredit - nDebit;
+ int64_t nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
if (wtx.IsFromMe())
entry.push_back(Pair("fee", ValueFromAmount(nFee)));
WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
Array details;
ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
entry.push_back(Pair("details", details));
return entry;
}
Value backupwallet(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"backupwallet <destination>\n"
"Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
string strDest = params[0].get_str();
BackupWallet(*pwalletMain, strDest);
return Value::null;
}
Value keypoolrefill(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
throw runtime_error(
"keypoolrefill\n"
"Fills the keypool, requires wallet passphrase to be set.");
if (!pwalletMain->IsCrypted() && (fHelp || params.size() > 0))
throw runtime_error(
"keypoolrefill\n"
"Fills the keypool.");
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
pwalletMain->TopUpKeyPool();
if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
throw JSONRPCError(-4, "Error refreshing keypool.");
return Value::null;
}
void ThreadTopUpKeyPool(void* parg)
{
pwalletMain->TopUpKeyPool();
}
void ThreadCleanWalletPassphrase(void* parg)
{
- int64 nMyWakeTime = GetTime() + *((int*)parg);
+ int64_t nMyWakeTime = GetTime() + *((int*)parg);
if (nWalletUnlockTime == 0)
{
CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
nWalletUnlockTime = nMyWakeTime;
}
while (GetTime() < nWalletUnlockTime)
Sleep(GetTime() - nWalletUnlockTime);
CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
nWalletUnlockTime = 0;
}
}
else
{
CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
if (nWalletUnlockTime < nMyWakeTime)
nWalletUnlockTime = nMyWakeTime;
}
free(parg);
return;
}
pwalletMain->Lock();
delete (int*)parg;
}
Value walletpassphrase(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
if (!pwalletMain->IsLocked())
throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
// Note that the walletpassphrase is stored in params[0] which is not mlock()ed
SecureString strWalletPass;
strWalletPass.reserve(100);
// 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))
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
}
else
throw runtime_error(
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
CreateThread(ThreadTopUpKeyPool, NULL);
int* pnSleepTime = new int(params[1].get_int());
CreateThread(ThreadCleanWalletPassphrase, pnSleepTime);
return Value::null;
}
Value walletpassphrasechange(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
"walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
// 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);
strOldWalletPass = params[0].get_str().c_str();
SecureString strNewWalletPass;
strNewWalletPass.reserve(100);
strNewWalletPass = params[1].get_str().c_str();
if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
throw runtime_error(
"walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
return Value::null;
}
Value walletlock(const Array& params, bool fHelp)
{
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
throw runtime_error(
"walletlock\n"
"Removes the wallet encryption key from memory, locking the wallet.\n"
"After calling this method, you will need to call walletpassphrase again\n"
"before being able to call any methods which require the wallet to be unlocked.");
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
pwalletMain->Lock();
CRITICAL_BLOCK(cs_nWalletUnlockTime)
{
nWalletUnlockTime = 0;
}
return Value::null;
}
Value encryptwallet(const Array& params, bool fHelp)
{
if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
throw runtime_error(
"encryptwallet <passphrase>\n"
"Encrypts the wallet with <passphrase>.");
if (fHelp)
return true;
if (pwalletMain->IsCrypted())
throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
#ifdef QT_GUI
// shutting down via RPC while the GUI is running does not work (yet):
throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
#endif
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
// Alternately, find a way to make params[0] mlock()'d to begin with.
SecureString strWalletPass;
strWalletPass.reserve(100);
strWalletPass = params[0].get_str().c_str();
if (strWalletPass.length() < 1)
throw runtime_error(
"encryptwallet <passphrase>\n"
"Encrypts the wallet with <passphrase>.");
if (!pwalletMain->EncryptWallet(strWalletPass))
throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
// 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";
}
Value validateaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"validateaddress <bitcoinaddress>\n"
"Return information about <bitcoinaddress>.");
CBitcoinAddress address(params[0].get_str());
bool isValid = address.IsValid();
Object ret;
ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
// Call Hash160ToAddress() so we always return current ADDRESSVERSION
// version of the address:
string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress));
if (pwalletMain->HaveKey(address))
{
ret.push_back(Pair("ismine", true));
std::vector<unsigned char> vchPubKey;
pwalletMain->GetPubKey(address, vchPubKey);
ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
std::string strPubKey(vchPubKey.begin(), vchPubKey.end());
ret.push_back(Pair("pubkey58", EncodeBase58(vchPubKey)));
}
else if (pwalletMain->HaveCScript(address.GetHash160()))
{
ret.push_back(Pair("isscript", true));
CScript subscript;
pwalletMain->GetCScript(address.GetHash160(), subscript);
ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
std::vector<CBitcoinAddress> addresses;
txnouttype whichType;
int nRequired;
ExtractAddresses(subscript, pwalletMain, whichType, addresses, nRequired);
ret.push_back(Pair("script", GetTxnOutputType(whichType)));
Array a;
BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
a.push_back(addr.ToString());
ret.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
ret.push_back(Pair("sigsrequired", nRequired));
}
else
ret.push_back(Pair("ismine", false));
if (pwalletMain->mapAddressBook.count(address))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
}
return ret;
}
Value getwork(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
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 (DEPRECATED)\n" // deprecated
" \"data\" : block data\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.");
if (vNodes.empty())
throw JSONRPCError(-9, "Bitcoin is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
static mapNewBlock_t mapNewBlock;
static vector<CBlock*> vNewBlock;
static CReserveKey reservekey(pwalletMain);
if (params.size() == 0)
{
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
- static int64 nStart;
+ static int64_t nStart;
static CBlock* pblock;
if (pindexPrev != pindexBest ||
(nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
{
if (pindexPrev != pindexBest)
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
BOOST_FOREACH(CBlock* pblock, vNewBlock)
delete pblock;
vNewBlock.clear();
}
nTransactionsUpdatedLast = nTransactionsUpdated;
pindexPrev = pindexBest;
nStart = GetTime();
// Create new block
pblock = CreateNewBlock(reservekey);
if (!pblock)
throw JSONRPCError(-7, "Out of memory");
vNewBlock.push_back(pblock);
}
// Update nTime
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
pblock->nNonce = 0;
// Update nExtraNonce
static unsigned int nExtraNonce = 0;
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
// Save
mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
// Prebuild hash buffers
char pmidstate[32];
char pdata[128];
char phash1[64];
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
Object result;
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)))); // deprecated
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
return result;
}
else
{
// Parse parameters
vector<unsigned char> vchData = ParseHex(params[0].get_str());
if (vchData.size() != 128)
throw JSONRPCError(-8, "Invalid parameter");
CBlock* pdata = (CBlock*)&vchData[0];
// Byte reverse
for (int i = 0; i < 128/4; i++)
((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
// Get saved block
if (!mapNewBlock.count(pdata->hashMerkleRoot))
return false;
CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
pblock->nTime = pdata->nTime;
pblock->nNonce = pdata->nNonce;
pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
return CheckWork(pblock, *pwalletMain, reservekey);
}
}
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 int64_t 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);
}
}
//
// Call Table
//
pair<string, rpcfn_type> pCallTable[] =
{
make_pair("help", &help),
make_pair("stop", &stop),
make_pair("getblockcount", &getblockcount),
make_pair("getblocknumber", &getblocknumber),
make_pair("getconnectioncount", &getconnectioncount),
make_pair("getdifficulty", &getdifficulty),
make_pair("getgenerate", &getgenerate),
make_pair("setgenerate", &setgenerate),
make_pair("gethashespersec", &gethashespersec),
make_pair("getinfo", &getinfo),
make_pair("getnewaddress", &getnewaddress),
make_pair("getaccountaddress", &getaccountaddress),
make_pair("setaccount", &setaccount),
make_pair("getaccount", &getaccount),
make_pair("getaddressesbyaccount", &getaddressesbyaccount),
make_pair("sendtoaddress", &sendtoaddress),
make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbyaccount", &getreceivedbyaccount),
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbyaccount", &listreceivedbyaccount),
make_pair("backupwallet", &backupwallet),
make_pair("keypoolrefill", &keypoolrefill),
make_pair("walletpassphrase", &walletpassphrase),
make_pair("walletpassphrasechange", &walletpassphrasechange),
make_pair("walletlock", &walletlock),
make_pair("encryptwallet", &encryptwallet),
make_pair("validateaddress", &validateaddress),
make_pair("getbalance", &getbalance),
make_pair("move", &movecmd),
make_pair("sendfrom", &sendfrom),
make_pair("sendmany", &sendmany),
make_pair("addmultisigaddress", &addmultisigaddress),
make_pair("gettransaction", &gettransaction),
make_pair("listtransactions", &listtransactions),
make_pair("signmessage", &signmessage),
make_pair("verifymessage", &verifymessage),
make_pair("getwork", &getwork),
make_pair("listaccounts", &listaccounts),
make_pair("settxfee", &settxfee),
make_pair("getmemorypool", &getmemorypool),
make_pair("listsinceblock", &listsinceblock),
make_pair("dumpprivkey", &dumpprivkey),
make_pair("importprivkey", &importprivkey)
};
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
string pAllowInSafeMode[] =
{
"help",
"stop",
"getblockcount",
"getblocknumber", // deprecated
"getconnectioncount",
"getdifficulty",
"getgenerate",
"setgenerate",
"gethashespersec",
"getinfo",
"getnewaddress",
"getaccountaddress",
"getaccount",
"getaddressesbyaccount",
"backupwallet",
"keypoolrefill",
"walletpassphrase",
"walletlock",
"validateaddress",
"getwork",
"getmemorypool",
};
set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
//
// HTTP protocol
//
// This ain't Apache. We're just using HTTP header for the length field
// and to be compatible with other JSON-RPC implementations.
//
string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
{
ostringstream s;
s << "POST / HTTP/1.1\r\n"
<< "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
<< "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";
s << "\r\n" << strMsg;
return s.str();
}
string rfc1123Time()
{
char buffer[64];
time_t now;
time(&now);
struct tm* now_gmt = gmtime(&now);
string locale(setlocale(LC_TIME, NULL));
setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
setlocale(LC_TIME, locale.c_str());
return string(buffer);
}
static string HTTPReply(int nStatus, const string& strMsg)
{
if (nStatus == 401)
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
"Date: %s\r\n"
"Server: bitcoin-json-rpc/%s\r\n"
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 296\r\n"
"\r\n"
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
"\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
"<HTML>\r\n"
"<HEAD>\r\n"
"<TITLE>Error</TITLE>\r\n"
"<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
"</HEAD>\r\n"
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
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"
"Connection: close\r\n"
"Content-Length: %d\r\n"
"Content-Type: application/json\r\n"
"Server: bitcoin-json-rpc/%s\r\n"
"\r\n"
"%s",
nStatus,
cStatus,
rfc1123Time().c_str(),
strMsg.size(),
FormatFullVersion().c_str(),
strMsg.c_str());
}
int ReadHTTPStatus(std::basic_istream<char>& stream)
{
string str;
getline(stream, str);
vector<string> vWords;
boost::split(vWords, str, boost::is_any_of(" "));
if (vWords.size() < 2)
return 500;
return atoi(vWords[1].c_str());
}
int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
{
int nLen = 0;
loop
{
string str;
std::getline(stream, str);
if (str.empty() || str == "\r")
break;
string::size_type nColon = str.find(":");
if (nColon != string::npos)
{
string strHeader = str.substr(0, nColon);
boost::trim(strHeader);
boost::to_lower(strHeader);
string strValue = str.substr(nColon+1);
boost::trim(strValue);
mapHeadersRet[strHeader] = strValue;
if (strHeader == "content-length")
nLen = atoi(strValue.c_str());
}
}
return nLen;
}
int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
{
mapHeadersRet.clear();
strMessageRet = "";
// Read status
int nStatus = ReadHTTPStatus(stream);
// Read header
int nLen = ReadHTTPHeader(stream, mapHeadersRet);
if (nLen < 0 || nLen > MAX_SIZE)
return 500;
// Read message
if (nLen > 0)
{
vector<char> vch(nLen);
stream.read(&vch[0], nLen);
strMessageRet = string(vch.begin(), vch.end());
}
return nStatus;
}
bool HTTPAuthorized(map<string, string>& mapHeaders)
{
string strAuth = mapHeaders["authorization"];
if (strAuth.substr(0,6) != "Basic ")
return false;
string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
string strUserPass = DecodeBase64(strUserPass64);
return strUserPass == strRPCUserColonPass;
}
//
// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
// unspecified (HTTP errors and contents of 'error').
//
// 1.0 spec: http://json-rpc.org/wiki/specification
// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
//
string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
{
Object request;
request.push_back(Pair("method", strMethod));
request.push_back(Pair("params", params));
request.push_back(Pair("id", id));
return write_string(Value(request), false) + "\n";
}
string JSONRPCReply(const Value& result, const Value& error, const Value& id)
{
Object reply;
if (error.type() != null_type)
reply.push_back(Pair("result", Value::null));
else
reply.push_back(Pair("result", result));
reply.push_back(Pair("error", error));
reply.push_back(Pair("id", id));
return write_string(Value(reply), false) + "\n";
}
void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
{
// Send error reply from json-rpc error object
int nStatus = 500;
int code = find_value(objError, "code").get_int();
if (code == -32600) nStatus = 400;
else if (code == -32601) nStatus = 404;
string strReply = JSONRPCReply(Value::null, objError, id);
stream << HTTPReply(nStatus, strReply) << std::flush;
}
bool ClientAllowed(const string& strAddress)
{
if (strAddress == asio::ip::address_v4::loopback().to_string())
return true;
const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
BOOST_FOREACH(string strAllow, vAllow)
if (WildcardMatch(strAddress, strAllow))
return true;
return false;
}
#ifdef USE_SSL
//
// IOStream device that speaks SSL but can also speak non-SSL
//
class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
public:
SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
{
fUseSSL = fUseSSLIn;
fNeedHandshake = fUseSSLIn;
}
void handshake(ssl::stream_base::handshake_type role)
{
if (!fNeedHandshake) return;
fNeedHandshake = false;
stream.handshake(role);
}
std::streamsize read(char* s, std::streamsize n)
{
handshake(ssl::stream_base::server); // HTTPS servers read first
if (fUseSSL) return stream.read_some(asio::buffer(s, n));
return stream.next_layer().read_some(asio::buffer(s, n));
}
std::streamsize write(const char* s, std::streamsize n)
{
handshake(ssl::stream_base::client); // HTTPS clients write first
if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
return asio::write(stream.next_layer(), asio::buffer(s, n));
}
bool connect(const std::string& server, const std::string& port)
{
ip::tcp::resolver resolver(stream.get_io_service());
ip::tcp::resolver::query query(server.c_str(), port.c_str());
ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
ip::tcp::resolver::iterator end;
boost::system::error_code error = asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
stream.lowest_layer().close();
stream.lowest_layer().connect(*endpoint_iterator++, error);
}
if (error)
return false;
return true;
}
private:
bool fNeedHandshake;
bool fUseSSL;
SSLStream& stream;
};
#endif
void ThreadRPCServer(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
try
{
vnThreadsRunning[4]++;
ThreadRPCServer2(parg);
vnThreadsRunning[4]--;
}
catch (std::exception& e) {
vnThreadsRunning[4]--;
PrintException(&e, "ThreadRPCServer()");
} catch (...) {
vnThreadsRunning[4]--;
PrintException(NULL, "ThreadRPCServer()");
}
printf("ThreadRPCServer exiting\n");
}
void ThreadRPCServer2(void* parg)
{
printf("ThreadRPCServer started\n");
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
if (strRPCUserColonPass == ":")
{
string strWhatAmI = "To use bitcoind";
if (mapArgs.count("-server"))
strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
else if (mapArgs.count("-daemon"))
strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
PrintConsole(
_("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
"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;
}
bool fUseSSL = GetBoolArg("-rpcssl");
asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
asio::io_service io_service;
ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
ip::tcp::acceptor acceptor(io_service, endpoint);
acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
#ifdef USE_SSL
ssl::context context(io_service, ssl::context::sslv23);
if (fUseSSL)
{
context.set_options(ssl::context::no_sslv2);
filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
string ciphers = GetArg("-rpcsslciphers",
"TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
}
#else
if (fUseSSL)
throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
#endif
loop
{
// Accept connection
#ifdef USE_SSL
SSLStream sslStream(io_service, context);
SSLIOStreamDevice d(sslStream, fUseSSL);
iostreams::stream<SSLIOStreamDevice> stream(d);
#else
ip::tcp::iostream stream;
#endif
ip::tcp::endpoint peer;
vnThreadsRunning[4]--;
#ifdef USE_SSL
acceptor.accept(sslStream.lowest_layer(), peer);
#else
acceptor.accept(*stream.rdbuf(), peer);
#endif
vnThreadsRunning[4]++;
if (fShutdown)
return;
// Restrict callers by IP
if (!ClientAllowed(peer.address().to_string()))
{
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
if (!fUseSSL)
stream << HTTPReply(403, "") << std::flush;
continue;
}
map<string, string> mapHeaders;
string strRequest;
boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
{ // Timed out:
acceptor.cancel();
printf("ThreadRPCServer ReadHTTP timeout\n");
continue;
}
// Check authorization
if (mapHeaders.count("authorization") == 0)
{
stream << HTTPReply(401, "") << std::flush;
continue;
}
if (!HTTPAuthorized(mapHeaders))
{
// Deter brute-forcing short passwords
if (mapArgs["-rpcpassword"].size() < 15)
Sleep(50);
stream << HTTPReply(401, "") << std::flush;
printf("ThreadRPCServer incorrect password attempt\n");
continue;
}
Value id = Value::null;
try
{
// Parse request
Value valRequest;
if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
throw JSONRPCError(-32700, "Parse error");
const Object& request = valRequest.get_obj();
// Parse id now so errors from here on will have the id
id = find_value(request, "id");
// Parse method
Value valMethod = find_value(request, "method");
if (valMethod.type() == null_type)
throw JSONRPCError(-32600, "Missing method");
if (valMethod.type() != str_type)
throw JSONRPCError(-32600, "Method must be a string");
string strMethod = valMethod.get_str();
if (strMethod != "getwork" && strMethod != "getmemorypool")
printf("ThreadRPCServer method=%s\n", strMethod.c_str());
// Parse params
Value valParams = find_value(request, "params");
Array params;
if (valParams.type() == array_type)
params = valParams.get_array();
else if (valParams.type() == null_type)
params = Array();
else
throw JSONRPCError(-32600, "Params must be an array");
// Find method
map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
if (mi == mapCallTable.end())
throw JSONRPCError(-32601, "Method not found");
// Observe safe mode
string strWarning = GetWarnings("rpc");
if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
try
{
// Execute
Value result;
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_wallet)
result = (*(*mi).second)(params, false);
// Send reply
string strReply = JSONRPCReply(result, Value::null, id);
stream << HTTPReply(200, strReply) << std::flush;
}
catch (std::exception& e)
{
ErrorReply(stream, JSONRPCError(-1, e.what()), id);
}
}
catch (Object& objError)
{
ErrorReply(stream, objError, id);
}
catch (std::exception& e)
{
ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
}
}
}
Object CallRPC(const string& strMethod, const Array& params)
{
if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
throw runtime_error(strprintf(
_("You must set rpcpassword=<password> in the configuration file:\n%s\n"
"If the file does not exist, create it with owner-readable-only file permissions."),
GetConfigFile().c_str()));
// Connect to localhost
bool fUseSSL = GetBoolArg("-rpcssl");
#ifdef USE_SSL
asio::io_service io_service;
ssl::context context(io_service, ssl::context::sslv23);
context.set_options(ssl::context::no_sslv2);
SSLStream sslStream(io_service, context);
SSLIOStreamDevice d(sslStream, fUseSSL);
iostreams::stream<SSLIOStreamDevice> stream(d);
if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
throw runtime_error("couldn't connect to server");
#else
if (fUseSSL)
throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
if (stream.fail())
throw runtime_error("couldn't connect to server");
#endif
// HTTP basic authentication
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
map<string, string> mapRequestHeaders;
mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
// Send request
string strRequest = JSONRPCRequest(strMethod, params, 1);
string strPost = HTTPPost(strRequest, mapRequestHeaders);
stream << strPost << std::flush;
// Receive reply
map<string, string> mapHeaders;
string strReply;
int nStatus = ReadHTTP(stream, mapHeaders, strReply);
if (nStatus == 401)
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
else if (strReply.empty())
throw runtime_error("no response from server");
// Parse reply
Value valReply;
if (!read_string(strReply, valReply))
throw runtime_error("couldn't parse reply from server");
const Object& reply = valReply.get_obj();
if (reply.empty())
throw runtime_error("expected reply to have result, error and id properties");
return reply;
}
template<typename T>
void ConvertTo(Value& value)
{
if (value.type() == str_type)
{
// reinterpret string as unquoted json value
Value value2;
if (!read_string(value.get_str(), value2))
throw runtime_error("type mismatch");
value = value2.get_value<T>();
}
else
{
value = value.get_value<T>();
}
}
int CommandLineRPC(int argc, char *argv[])
{
string strPrint;
int nRet = 0;
try
{
// Skip switches
while (argc > 1 && IsSwitchChar(argv[1][0]))
{
argc--;
argv++;
}
// Method
if (argc < 2)
throw runtime_error("too few parameters");
string strMethod = argv[1];
// Parameters default to strings
Array params;
for (int i = 2; i < argc; i++)
params.push_back(argv[i]);
int n = params.size();
//
// Special case non-string parameter types
//
if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
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 == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
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 == "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 == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
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();
Value v;
if (!read_string(s, v) || v.type() != obj_type)
throw runtime_error("type mismatch");
params[1] = v.get_obj();
}
if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "addmultisigaddress" && n > 1)
{
string s = params[1].get_str();
Value v;
if (!read_string(s, v) || v.type() != array_type)
throw runtime_error("addmultisigaddress: type mismatch "+s);
params[1] = v.get_array();
}
// Execute
Object reply = CallRPC(strMethod, params);
// Parse reply
const Value& result = find_value(reply, "result");
const Value& error = find_value(reply, "error");
if (error.type() != null_type)
{
// Error
strPrint = "error: " + write_string(error, false);
int code = find_value(error.get_obj(), "code").get_int();
nRet = abs(code);
}
else
{
// Result
if (result.type() == null_type)
strPrint = "";
else if (result.type() == str_type)
strPrint = result.get_str();
else
strPrint = write_string(result, true);
}
}
catch (std::exception& e)
{
strPrint = string("error: ") + e.what();
nRet = 87;
}
catch (...)
{
PrintException(NULL, "CommandLineRPC()");
}
if (strPrint != "")
{
fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
}
return nRet;
}
#ifdef TEST
int main(int argc, char *argv[])
{
#ifdef _MSC_VER
// Turn off microsoft heap dump noise
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
#endif
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
try
{
if (argc >= 2 && string(argv[1]) == "-server")
{
printf("server ready\n");
ThreadRPCServer(NULL);
}
else
{
return CommandLineRPC(argc, argv);
}
}
catch (std::exception& e) {
PrintException(&e, "main()");
} catch (...) {
PrintException(NULL, "main()");
}
return 0;
}
#endif
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index c7e054df37..578742e309 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -1,65 +1,67 @@
// 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 <stdint.h>
+
#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"))
;
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;
+ int64_t 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;
}
}
diff --git a/src/db.cpp b/src/db.cpp
index f43b2a5656..af2ae834dd 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -1,1074 +1,1076 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "db.h"
#include "net.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace std;
using namespace boost;
unsigned int nWalletDBUpdated;
-uint64 nAccountingEntryNumber = 0;
+uint64_t nAccountingEntryNumber = 0;
//
// CDB
//
static CCriticalSection cs_db;
static bool fDbEnvInit = false;
DbEnv dbenv(0);
static map<string, int> mapFileUseCount;
static map<string, Db*> mapDb;
static void EnvShutdown()
{
if (!fDbEnvInit)
return;
fDbEnvInit = false;
try
{
dbenv.close(0);
}
catch (const DbException& e)
{
printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno());
}
DbEnv(0).remove(GetDataDir().c_str(), 0);
}
class CDBInit
{
public:
CDBInit()
{
}
~CDBInit()
{
EnvShutdown();
}
}
instance_of_cdbinit;
CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
{
int ret;
if (pszFile == NULL)
return;
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
bool fCreate = strchr(pszMode, 'c');
unsigned int nFlags = DB_THREAD;
if (fCreate)
nFlags |= DB_CREATE;
CRITICAL_BLOCK(cs_db)
{
if (!fDbEnvInit)
{
if (fShutdown)
return;
string strDataDir = GetDataDir();
string strLogDir = strDataDir + "/database";
filesystem::create_directory(strLogDir.c_str());
string strErrorFile = strDataDir + "/db.log";
printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
dbenv.set_lg_dir(strLogDir.c_str());
dbenv.set_lg_max(10000000);
dbenv.set_lk_max_locks(10000);
dbenv.set_lk_max_objects(10000);
dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
dbenv.set_flags(DB_AUTO_COMMIT, 1);
ret = dbenv.open(strDataDir.c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
DB_INIT_MPOOL |
DB_INIT_TXN |
DB_THREAD |
DB_RECOVER,
S_IRUSR | S_IWUSR);
if (ret > 0)
throw runtime_error(strprintf("CDB() : error %d opening database environment", ret));
fDbEnvInit = true;
}
strFile = pszFile;
++mapFileUseCount[strFile];
pdb = mapDb[strFile];
if (pdb == NULL)
{
pdb = new Db(&dbenv, 0);
ret = pdb->open(NULL, // Txn pointer
pszFile, // Filename
"main", // Logical db name
DB_BTREE, // Database type
nFlags, // Flags
0);
if (ret > 0)
{
delete pdb;
pdb = NULL;
CRITICAL_BLOCK(cs_db)
--mapFileUseCount[strFile];
strFile = "";
throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
}
if (fCreate && !Exists(string("version")))
{
bool fTmp = fReadOnly;
fReadOnly = false;
WriteVersion(CLIENT_VERSION);
fReadOnly = fTmp;
}
mapDb[strFile] = pdb;
}
}
}
void CDB::Close()
{
if (!pdb)
return;
if (!vTxn.empty())
vTxn.front()->abort();
vTxn.clear();
pdb = NULL;
// Flush database activity from memory pool to disk log
unsigned int nMinutes = 0;
if (fReadOnly)
nMinutes = 1;
if (strFile == "addr.dat")
nMinutes = 2;
if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
nMinutes = 1;
dbenv.txn_checkpoint(0, nMinutes, 0);
CRITICAL_BLOCK(cs_db)
--mapFileUseCount[strFile];
}
void static CloseDb(const string& strFile)
{
CRITICAL_BLOCK(cs_db)
{
if (mapDb[strFile] != NULL)
{
// Close the database handle
Db* pdb = mapDb[strFile];
pdb->close(0);
delete pdb;
mapDb[strFile] = NULL;
}
}
}
bool CDB::Rewrite(const string& strFile, const char* pszSkip)
{
while (!fShutdown)
{
CRITICAL_BLOCK(cs_db)
{
if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
{
// Flush log data to the dat file
CloseDb(strFile);
dbenv.txn_checkpoint(0, 0, 0);
dbenv.lsn_reset(strFile.c_str(), 0);
mapFileUseCount.erase(strFile);
bool fSuccess = true;
printf("Rewriting %s...\n", strFile.c_str());
string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {}
CDB db(strFile.c_str(), "r");
Db* pdbCopy = new Db(&dbenv, 0);
int ret = pdbCopy->open(NULL, // Txn pointer
strFileRes.c_str(), // Filename
"main", // Logical db name
DB_BTREE, // Database type
DB_CREATE, // Flags
0);
if (ret > 0)
{
printf("Cannot create database file %s\n", strFileRes.c_str());
fSuccess = false;
}
Dbc* pcursor = db.GetCursor();
if (pcursor)
while (fSuccess)
{
CDataStream ssKey;
CDataStream ssValue;
int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
if (ret == DB_NOTFOUND)
{
pcursor->close();
break;
}
else if (ret != 0)
{
pcursor->close();
fSuccess = false;
break;
}
if (pszSkip &&
strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
continue;
if (strncmp(&ssKey[0], "\x07version", 8) == 0)
{
// Update version:
ssValue.clear();
ssValue << CLIENT_VERSION;
}
Dbt datKey(&ssKey[0], ssKey.size());
Dbt datValue(&ssValue[0], ssValue.size());
int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
if (ret2 > 0)
fSuccess = false;
}
if (fSuccess)
{
db.Close();
CloseDb(strFile);
if (pdbCopy->close(0))
fSuccess = false;
delete pdbCopy;
}
}
if (fSuccess)
{
Db dbA(&dbenv, 0);
if (dbA.remove(strFile.c_str(), NULL, 0))
fSuccess = false;
Db dbB(&dbenv, 0);
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
fSuccess = false;
}
if (!fSuccess)
printf("Rewriting of %s FAILED!\n", strFileRes.c_str());
return fSuccess;
}
}
Sleep(100);
}
return false;
}
void DBFlush(bool fShutdown)
{
// Flush log data to the actual data file
// on all files that are not in use
printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
if (!fDbEnvInit)
return;
CRITICAL_BLOCK(cs_db)
{
map<string, int>::iterator mi = mapFileUseCount.begin();
while (mi != mapFileUseCount.end())
{
string strFile = (*mi).first;
int nRefCount = (*mi).second;
printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
if (nRefCount == 0)
{
// Move log data to the dat file
CloseDb(strFile);
dbenv.txn_checkpoint(0, 0, 0);
printf("%s flush\n", strFile.c_str());
dbenv.lsn_reset(strFile.c_str(), 0);
mapFileUseCount.erase(mi++);
}
else
mi++;
}
if (fShutdown)
{
char** listp;
if (mapFileUseCount.empty())
{
dbenv.log_archive(&listp, DB_ARCH_REMOVE);
EnvShutdown();
}
}
}
}
//
// CTxDB
//
bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
{
assert(!fClient);
txindex.SetNull();
return Read(make_pair(string("tx"), hash), txindex);
}
bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
{
assert(!fClient);
return Write(make_pair(string("tx"), hash), txindex);
}
bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
{
assert(!fClient);
// Add to tx index
uint256 hash = tx.GetHash();
CTxIndex txindex(pos, tx.vout.size());
return Write(make_pair(string("tx"), hash), txindex);
}
bool CTxDB::EraseTxIndex(const CTransaction& tx)
{
assert(!fClient);
uint256 hash = tx.GetHash();
return Erase(make_pair(string("tx"), hash));
}
bool CTxDB::ContainsTx(uint256 hash)
{
assert(!fClient);
return Exists(make_pair(string("tx"), hash));
}
bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
{
assert(!fClient);
vtx.clear();
// Get cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
return false;
unsigned int fFlags = DB_SET_RANGE;
loop
{
// Read next record
CDataStream ssKey;
if (fFlags == DB_SET_RANGE)
ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
CDataStream ssValue;
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
fFlags = DB_NEXT;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
{
pcursor->close();
return false;
}
// Unserialize
string strType;
uint160 hashItem;
CDiskTxPos pos;
ssKey >> strType >> hashItem >> pos;
int nItemHeight;
ssValue >> nItemHeight;
// Read transaction
if (strType != "owner" || hashItem != hash160)
break;
if (nItemHeight >= nMinHeight)
{
vtx.resize(vtx.size()+1);
if (!vtx.back().ReadFromDisk(pos))
{
pcursor->close();
return false;
}
}
}
pcursor->close();
return true;
}
bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
{
assert(!fClient);
tx.SetNull();
if (!ReadTxIndex(hash, txindex))
return false;
return (tx.ReadFromDisk(txindex.pos));
}
bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
{
CTxIndex txindex;
return ReadDiskTx(hash, tx, txindex);
}
bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
{
return ReadDiskTx(outpoint.hash, tx, txindex);
}
bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
{
CTxIndex txindex;
return ReadDiskTx(outpoint.hash, tx, txindex);
}
bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
{
return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
}
bool CTxDB::EraseBlockIndex(uint256 hash)
{
return Erase(make_pair(string("blockindex"), hash));
}
bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
{
return Read(string("hashBestChain"), hashBestChain);
}
bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
{
return Write(string("hashBestChain"), hashBestChain);
}
bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
{
return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
}
bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
{
return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
}
CBlockIndex static * InsertBlockIndex(uint256 hash)
{
if (hash == 0)
return NULL;
// Return existing
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
return (*mi).second;
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
if (!pindexNew)
throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
return pindexNew;
}
bool CTxDB::LoadBlockIndex()
{
// Get database cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
return false;
// Load mapBlockIndex
unsigned int fFlags = DB_SET_RANGE;
loop
{
// Read next record
CDataStream ssKey;
if (fFlags == DB_SET_RANGE)
ssKey << make_pair(string("blockindex"), uint256(0));
CDataStream ssValue;
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
fFlags = DB_NEXT;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
return false;
// Unserialize
string strType;
ssKey >> strType;
if (strType == "blockindex")
{
CDiskBlockIndex diskindex;
ssValue >> diskindex;
// Construct block index object
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
pindexNew->pnext = InsertBlockIndex(diskindex.hashNext);
pindexNew->nFile = diskindex.nFile;
pindexNew->nBlockPos = diskindex.nBlockPos;
pindexNew->nHeight = diskindex.nHeight;
pindexNew->nVersion = diskindex.nVersion;
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
pindexNew->nTime = diskindex.nTime;
pindexNew->nBits = diskindex.nBits;
pindexNew->nNonce = diskindex.nNonce;
// Watch for genesis block
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
pindexGenesisBlock = pindexNew;
if (!pindexNew->CheckIndex())
return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
}
else
{
break;
}
}
pcursor->close();
// Calculate bnChainWork
vector<pair<int, CBlockIndex*> > vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size());
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
{
CBlockIndex* pindex = item.second;
vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
}
sort(vSortedByHeight.begin(), vSortedByHeight.end());
BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
{
CBlockIndex* pindex = item.second;
pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
}
// Load hashBestChain pointer to end of best chain
if (!ReadHashBestChain(hashBestChain))
{
if (pindexGenesisBlock == NULL)
return true;
return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
}
if (!mapBlockIndex.count(hashBestChain))
return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
pindexBest = mapBlockIndex[hashBestChain];
nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexBest->bnChainWork;
printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);
// Load bnBestInvalidWork, OK if it doesn't exist
ReadBestInvalidWork(bnBestInvalidWork);
// Verify blocks in the best chain
CBlockIndex* pindexFork = NULL;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{
if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
break;
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("LoadBlockIndex() : block.ReadFromDisk failed");
if (!block.CheckBlock())
{
printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
pindexFork = pindex->pprev;
}
}
if (pindexFork)
{
// Reorg back to the fork
printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
CBlock block;
if (!block.ReadFromDisk(pindexFork))
return error("LoadBlockIndex() : block.ReadFromDisk failed");
CTxDB txdb;
block.SetBestChain(txdb, pindexFork);
}
return true;
}
//
// CAddrDB
//
bool CAddrDB::WriteAddress(const CAddress& addr)
{
return Write(make_pair(string("addr"), addr.GetKey()), addr);
}
bool CAddrDB::EraseAddress(const CAddress& addr)
{
return Erase(make_pair(string("addr"), addr.GetKey()));
}
bool CAddrDB::LoadAddresses()
{
CRITICAL_BLOCK(cs_mapAddresses)
{
// Get cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
return false;
loop
{
// Read next record
CDataStream ssKey;
CDataStream ssValue;
int ret = ReadAtCursor(pcursor, ssKey, ssValue);
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
return false;
// Unserialize
string strType;
ssKey >> strType;
if (strType == "addr")
{
CAddress addr;
ssValue >> addr;
mapAddresses.insert(make_pair(addr.GetKey(), addr));
}
}
pcursor->close();
printf("Loaded %d addresses\n", mapAddresses.size());
}
return true;
}
bool LoadAddresses()
{
return CAddrDB("cr+").LoadAddresses();
}
//
// CWalletDB
//
bool CWalletDB::WriteName(const string& strAddress, const string& strName)
{
nWalletDBUpdated++;
return Write(make_pair(string("name"), strAddress), strName);
}
bool CWalletDB::EraseName(const string& strAddress)
{
// This should only be used for sending addresses, never for receiving addresses,
// receiving addresses must always have an address book entry if they're not change return.
nWalletDBUpdated++;
return Erase(make_pair(string("name"), strAddress));
}
bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
{
account.SetNull();
return Read(make_pair(string("acc"), strAccount), account);
}
bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
{
return Write(make_pair(string("acc"), strAccount), account);
}
bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
{
return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
}
-int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
+int64_t CWalletDB::GetAccountCreditDebit(const string& strAccount)
{
list<CAccountingEntry> entries;
ListAccountCreditDebit(strAccount, entries);
- int64 nCreditDebit = 0;
+ int64_t nCreditDebit = 0;
BOOST_FOREACH (const CAccountingEntry& entry, entries)
nCreditDebit += entry.nCreditDebit;
return nCreditDebit;
}
void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
{
bool fAllAccounts = (strAccount == "*");
Dbc* pcursor = GetCursor();
if (!pcursor)
throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
unsigned int fFlags = DB_SET_RANGE;
loop
{
// Read next record
CDataStream ssKey;
if (fFlags == DB_SET_RANGE)
- ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
+ ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64_t(0));
CDataStream ssValue;
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
fFlags = DB_NEXT;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
{
pcursor->close();
throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
}
// Unserialize
string strType;
ssKey >> strType;
if (strType != "acentry")
break;
CAccountingEntry acentry;
ssKey >> acentry.strAccount;
if (!fAllAccounts && acentry.strAccount != strAccount)
break;
ssValue >> acentry;
entries.push_back(acentry);
}
pcursor->close();
}
int CWalletDB::LoadWallet(CWallet* pwallet)
{
pwallet->vchDefaultKey.clear();
int nFileVersion = 0;
vector<uint256> vWalletUpgrade;
bool fIsEncrypted = false;
// Modify defaults
#ifndef WIN32
// Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
fMinimizeToTray = false;
fMinimizeOnClose = false;
#endif
//// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(pwallet->cs_wallet)
{
// Get cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
return DB_CORRUPT;
loop
{
// Read next record
CDataStream ssKey;
CDataStream ssValue;
int ret = ReadAtCursor(pcursor, ssKey, ssValue);
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
return DB_CORRUPT;
// Unserialize
// Taking advantage of the fact that pair serialization
// is just the two items serialized one after the other
string strType;
ssKey >> strType;
if (strType == "name")
{
string strAddress;
ssKey >> strAddress;
ssValue >> pwallet->mapAddressBook[strAddress];
}
else if (strType == "tx")
{
uint256 hash;
ssKey >> hash;
CWalletTx& wtx = pwallet->mapWallet[hash];
ssValue >> wtx;
wtx.BindWallet(pwallet);
if (wtx.GetHash() != hash)
printf("Error in wallet.dat, hash mismatch\n");
// Undo serialize changes in 31600
if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
{
if (!ssValue.empty())
{
char fTmp;
char fUnused;
ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
wtx.fTimeReceivedIsTxTime = fTmp;
}
else
{
printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
wtx.fTimeReceivedIsTxTime = 0;
}
vWalletUpgrade.push_back(hash);
}
//// debug print
//printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
//printf(" %12I64d %s %s %s\n",
// wtx.vout[0].nValue,
// DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
// wtx.hashBlock.ToString().substr(0,20).c_str(),
// wtx.mapValue["message"].c_str());
}
else if (strType == "acentry")
{
string strAccount;
ssKey >> strAccount;
- uint64 nNumber;
+ uint64_t nNumber;
ssKey >> nNumber;
if (nNumber > nAccountingEntryNumber)
nAccountingEntryNumber = nNumber;
}
else if (strType == "key" || strType == "wkey")
{
vector<unsigned char> vchPubKey;
ssKey >> vchPubKey;
CKey key;
if (strType == "key")
{
CPrivKey pkey;
ssValue >> pkey;
key.SetPrivKey(pkey);
}
else
{
CWalletKey wkey;
ssValue >> wkey;
key.SetPrivKey(wkey.vchPrivKey);
}
if (!pwallet->LoadKey(key))
return DB_CORRUPT;
}
else if (strType == "mkey")
{
unsigned int nID;
ssKey >> nID;
CMasterKey kMasterKey;
ssValue >> kMasterKey;
if(pwallet->mapMasterKeys.count(nID) != 0)
return DB_CORRUPT;
pwallet->mapMasterKeys[nID] = kMasterKey;
if (pwallet->nMasterKeyMaxID < nID)
pwallet->nMasterKeyMaxID = nID;
}
else if (strType == "ckey")
{
vector<unsigned char> vchPubKey;
ssKey >> vchPubKey;
vector<unsigned char> vchPrivKey;
ssValue >> vchPrivKey;
if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
return DB_CORRUPT;
fIsEncrypted = true;
}
else if (strType == "defaultkey")
{
ssValue >> pwallet->vchDefaultKey;
}
else if (strType == "pool")
{
- int64 nIndex;
+ int64_t nIndex;
ssKey >> nIndex;
pwallet->setKeyPool.insert(nIndex);
}
else if (strType == "version")
{
ssValue >> nFileVersion;
if (nFileVersion == 10300)
nFileVersion = 300;
}
else if (strType == "setting")
{
string strKey;
ssKey >> strKey;
// Options
#ifndef QT_GUI
if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins;
#endif
if (strKey == "nTransactionFee") ssValue >> nTransactionFee;
if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors;
if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors;
if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray;
if (strKey == "fMinimizeOnClose") ssValue >> fMinimizeOnClose;
if (strKey == "fUseProxy") ssValue >> fUseProxy;
if (strKey == "addrProxy") ssValue >> addrProxy;
if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP;
}
else if (strType == "minversion")
{
int nMinVersion = 0;
ssValue >> nMinVersion;
if (nMinVersion > CLIENT_VERSION)
return DB_TOO_NEW;
}
else if (strType == "cscript")
{
uint160 hash;
ssKey >> hash;
CScript script;
ssValue >> script;
if (!pwallet->LoadCScript(hash, script))
return DB_CORRUPT;
}
}
pcursor->close();
}
BOOST_FOREACH(uint256 hash, vWalletUpgrade)
WriteTx(hash, pwallet->mapWallet[hash]);
printf("nFileVersion = %d\n", nFileVersion);
printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
printf("fMinimizeToTray = %d\n", fMinimizeToTray);
printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
printf("fUseProxy = %d\n", fUseProxy);
printf("addrProxy = %s\n", addrProxy.ToString().c_str());
if (fHaveUPnP)
printf("fUseUPnP = %d\n", fUseUPnP);
// Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
return DB_NEED_REWRITE;
if (nFileVersion < CLIENT_VERSION) // Update
{
// Get rid of old debug.log file in current directory
if (nFileVersion <= 105 && !pszSetDataDir[0])
unlink("debug.log");
WriteVersion(CLIENT_VERSION);
}
return DB_LOAD_OK;
}
void ThreadFlushWalletDB(void* parg)
{
const string& strFile = ((const string*)parg)[0];
static bool fOneThread;
if (fOneThread)
return;
fOneThread = true;
if (mapArgs.count("-noflushwallet"))
return;
unsigned int nLastSeen = nWalletDBUpdated;
unsigned int nLastFlushed = nWalletDBUpdated;
- int64 nLastWalletUpdate = GetTime();
+ int64_t nLastWalletUpdate = GetTime();
while (!fShutdown)
{
Sleep(500);
if (nLastSeen != nWalletDBUpdated)
{
nLastSeen = nWalletDBUpdated;
nLastWalletUpdate = GetTime();
}
if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
{
TRY_CRITICAL_BLOCK(cs_db)
{
// Don't do this if any databases are in use
int nRefCount = 0;
map<string, int>::iterator mi = mapFileUseCount.begin();
while (mi != mapFileUseCount.end())
{
nRefCount += (*mi).second;
mi++;
}
if (nRefCount == 0 && !fShutdown)
{
map<string, int>::iterator mi = mapFileUseCount.find(strFile);
if (mi != mapFileUseCount.end())
{
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("Flushing wallet.dat\n");
nLastFlushed = nWalletDBUpdated;
- int64 nStart = GetTimeMillis();
+ int64_t nStart = GetTimeMillis();
// Flush wallet.dat so it's self contained
CloseDb(strFile);
dbenv.txn_checkpoint(0, 0, 0);
dbenv.lsn_reset(strFile.c_str(), 0);
mapFileUseCount.erase(mi++);
printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
}
}
}
}
}
}
bool BackupWallet(const CWallet& wallet, const string& strDest)
{
if (!wallet.fFileBacked)
return false;
while (!fShutdown)
{
CRITICAL_BLOCK(cs_db)
{
if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
{
// Flush log data to the dat file
CloseDb(wallet.strWalletFile);
dbenv.txn_checkpoint(0, 0, 0);
dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
mapFileUseCount.erase(wallet.strWalletFile);
// Copy wallet.dat
filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
filesystem::path pathDest(strDest);
if (filesystem::is_directory(pathDest))
pathDest = pathDest / wallet.strWalletFile;
#if BOOST_VERSION >= 104000
filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
#else
filesystem::copy_file(pathSrc, pathDest);
#endif
printf("copied wallet.dat to %s\n", pathDest.string().c_str());
return true;
}
}
Sleep(100);
}
return false;
}
diff --git a/src/db.h b/src/db.h
index e593ae28ed..674d1475d5 100644
--- a/src/db.h
+++ b/src/db.h
@@ -1,498 +1,500 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_DB_H
#define BITCOIN_DB_H
+#include <stdint.h>
+
#include "key.h"
#include <map>
#include <string>
#include <vector>
#include <db_cxx.h>
class CAccount;
class CAccountingEntry;
class CAddress;
class CBlockLocator;
class CDiskBlockIndex;
class CDiskTxPos;
class CMasterKey;
class COutPoint;
class CTxIndex;
class CWallet;
class CWalletTx;
extern unsigned int nWalletDBUpdated;
extern DbEnv dbenv;
extern void DBFlush(bool fShutdown);
void ThreadFlushWalletDB(void* parg);
bool BackupWallet(const CWallet& wallet, const std::string& strDest);
class CDB
{
protected:
Db* pdb;
std::string strFile;
std::vector<DbTxn*> vTxn;
bool fReadOnly;
explicit CDB(const char* pszFile, const char* pszMode="r+");
~CDB() { Close(); }
public:
void Close();
private:
CDB(const CDB&);
void operator=(const CDB&);
protected:
template<typename K, typename T>
bool Read(const K& key, T& value)
{
if (!pdb)
return false;
// Key
CDataStream ssKey(SER_DISK);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Read
Dbt datValue;
datValue.set_flags(DB_DBT_MALLOC);
int ret = pdb->get(GetTxn(), &datKey, &datValue, 0);
memset(datKey.get_data(), 0, datKey.get_size());
if (datValue.get_data() == NULL)
return false;
// Unserialize value
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
ssValue >> value;
// Clear and free memory
memset(datValue.get_data(), 0, datValue.get_size());
free(datValue.get_data());
return (ret == 0);
}
template<typename K, typename T>
bool Write(const K& key, const T& value, bool fOverwrite=true)
{
if (!pdb)
return false;
if (fReadOnly)
assert(!"Write called on database in read-only mode");
// Key
CDataStream ssKey(SER_DISK);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Value
CDataStream ssValue(SER_DISK);
ssValue.reserve(10000);
ssValue << value;
Dbt datValue(&ssValue[0], ssValue.size());
// Write
int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
// Clear memory in case it was a private key
memset(datKey.get_data(), 0, datKey.get_size());
memset(datValue.get_data(), 0, datValue.get_size());
return (ret == 0);
}
template<typename K>
bool Erase(const K& key)
{
if (!pdb)
return false;
if (fReadOnly)
assert(!"Erase called on database in read-only mode");
// Key
CDataStream ssKey(SER_DISK);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Erase
int ret = pdb->del(GetTxn(), &datKey, 0);
// Clear memory
memset(datKey.get_data(), 0, datKey.get_size());
return (ret == 0 || ret == DB_NOTFOUND);
}
template<typename K>
bool Exists(const K& key)
{
if (!pdb)
return false;
// Key
CDataStream ssKey(SER_DISK);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Exists
int ret = pdb->exists(GetTxn(), &datKey, 0);
// Clear memory
memset(datKey.get_data(), 0, datKey.get_size());
return (ret == 0);
}
Dbc* GetCursor()
{
if (!pdb)
return NULL;
Dbc* pcursor = NULL;
int ret = pdb->cursor(NULL, &pcursor, 0);
if (ret != 0)
return NULL;
return pcursor;
}
int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
{
// Read at cursor
Dbt datKey;
if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
{
datKey.set_data(&ssKey[0]);
datKey.set_size(ssKey.size());
}
Dbt datValue;
if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
{
datValue.set_data(&ssValue[0]);
datValue.set_size(ssValue.size());
}
datKey.set_flags(DB_DBT_MALLOC);
datValue.set_flags(DB_DBT_MALLOC);
int ret = pcursor->get(&datKey, &datValue, fFlags);
if (ret != 0)
return ret;
else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
return 99999;
// Convert to streams
ssKey.SetType(SER_DISK);
ssKey.clear();
ssKey.write((char*)datKey.get_data(), datKey.get_size());
ssValue.SetType(SER_DISK);
ssValue.clear();
ssValue.write((char*)datValue.get_data(), datValue.get_size());
// Clear and free memory
memset(datKey.get_data(), 0, datKey.get_size());
memset(datValue.get_data(), 0, datValue.get_size());
free(datKey.get_data());
free(datValue.get_data());
return 0;
}
DbTxn* GetTxn()
{
if (!vTxn.empty())
return vTxn.back();
else
return NULL;
}
public:
bool TxnBegin()
{
if (!pdb)
return false;
DbTxn* ptxn = NULL;
int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC);
if (!ptxn || ret != 0)
return false;
vTxn.push_back(ptxn);
return true;
}
bool TxnCommit()
{
if (!pdb)
return false;
if (vTxn.empty())
return false;
int ret = vTxn.back()->commit(0);
vTxn.pop_back();
return (ret == 0);
}
bool TxnAbort()
{
if (!pdb)
return false;
if (vTxn.empty())
return false;
int ret = vTxn.back()->abort();
vTxn.pop_back();
return (ret == 0);
}
bool ReadVersion(int& nVersion)
{
nVersion = 0;
return Read(std::string("version"), nVersion);
}
bool WriteVersion(int nVersion)
{
return Write(std::string("version"), nVersion);
}
bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
};
class CTxDB : public CDB
{
public:
CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { }
private:
CTxDB(const CTxDB&);
void operator=(const CTxDB&);
public:
bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
bool EraseTxIndex(const CTransaction& tx);
bool ContainsTx(uint256 hash);
bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx);
bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
bool ReadDiskTx(uint256 hash, CTransaction& tx);
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
bool EraseBlockIndex(uint256 hash);
bool ReadHashBestChain(uint256& hashBestChain);
bool WriteHashBestChain(uint256 hashBestChain);
bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
bool LoadBlockIndex();
};
class CAddrDB : public CDB
{
public:
CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
private:
CAddrDB(const CAddrDB&);
void operator=(const CAddrDB&);
public:
bool WriteAddress(const CAddress& addr);
bool EraseAddress(const CAddress& addr);
bool LoadAddresses();
};
bool LoadAddresses();
class CKeyPool
{
public:
- int64 nTime;
+ int64_t nTime;
std::vector<unsigned char> vchPubKey;
CKeyPool()
{
nTime = GetTime();
}
CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
{
nTime = GetTime();
vchPubKey = vchPubKeyIn;
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(nTime);
READWRITE(vchPubKey);
)
};
enum DBErrors
{
DB_LOAD_OK,
DB_CORRUPT,
DB_TOO_NEW,
DB_LOAD_FAIL,
DB_NEED_REWRITE
};
class CWalletDB : public CDB
{
public:
CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
{
}
private:
CWalletDB(const CWalletDB&);
void operator=(const CWalletDB&);
public:
bool ReadName(const std::string& strAddress, std::string& strName)
{
strName = "";
return Read(std::make_pair(std::string("name"), strAddress), strName);
}
bool WriteName(const std::string& strAddress, const std::string& strName);
bool EraseName(const std::string& strAddress);
bool ReadTx(uint256 hash, CWalletTx& wtx)
{
return Read(std::make_pair(std::string("tx"), hash), wtx);
}
bool WriteTx(uint256 hash, const CWalletTx& wtx)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("tx"), hash), wtx);
}
bool EraseTx(uint256 hash)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("tx"), hash));
}
bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
{
vchPrivKey.clear();
return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey);
}
bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
}
bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
{
nWalletDBUpdated++;
if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
return false;
if (fEraseUnencryptedKey)
{
Erase(std::make_pair(std::string("key"), vchPubKey));
Erase(std::make_pair(std::string("wkey"), vchPubKey));
}
return true;
}
bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
}
// Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
bool ReadCScript(const uint160 &hash, CScript& redeemScript)
{
redeemScript.clear();
return Read(std::make_pair(std::string("cscript"), hash), redeemScript);
}
bool WriteCScript(const uint160& hash, const CScript& redeemScript)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
}
bool WriteBestBlock(const CBlockLocator& locator)
{
nWalletDBUpdated++;
return Write(std::string("bestblock"), locator);
}
bool ReadBestBlock(CBlockLocator& locator)
{
return Read(std::string("bestblock"), locator);
}
bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey)
{
vchPubKey.clear();
return Read(std::string("defaultkey"), vchPubKey);
}
bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
{
nWalletDBUpdated++;
return Write(std::string("defaultkey"), vchPubKey);
}
- bool ReadPool(int64 nPool, CKeyPool& keypool)
+ bool ReadPool(int64_t nPool, CKeyPool& keypool)
{
return Read(std::make_pair(std::string("pool"), nPool), keypool);
}
- bool WritePool(int64 nPool, const CKeyPool& keypool)
+ bool WritePool(int64_t nPool, const CKeyPool& keypool)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("pool"), nPool), keypool);
}
- bool ErasePool(int64 nPool)
+ bool ErasePool(int64_t nPool)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("pool"), nPool));
}
template<typename T>
bool ReadSetting(const std::string& strKey, T& value)
{
return Read(std::make_pair(std::string("setting"), strKey), value);
}
template<typename T>
bool WriteSetting(const std::string& strKey, const T& value)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("setting"), strKey), value);
}
bool ReadAccount(const std::string& strAccount, CAccount& account);
bool WriteAccount(const std::string& strAccount, const CAccount& account);
bool WriteAccountingEntry(const CAccountingEntry& acentry);
- int64 GetAccountCreditDebit(const std::string& strAccount);
+ int64_t GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
int LoadWallet(CWallet* pwallet);
};
#endif
diff --git a/src/init.cpp b/src/init.cpp
index 1e389b226b..6fa25ac281 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,690 +1,693 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "db.h"
#include "bitcoinrpc.h"
#include "net.h"
#include "init.h"
#include "strlcpy.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
#define _BITCOIN_QT_PLUGINS_INCLUDED
#define __INSURE__
#include <QtPlugin>
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
#endif
using namespace std;
using namespace boost;
CWallet* pwalletMain;
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
//
void ExitTimeout(void* parg)
{
#ifdef WIN32
Sleep(5000);
ExitProcess(0);
#endif
}
void Shutdown(void* parg)
{
static CCriticalSection cs_Shutdown;
static bool fTaken;
bool fFirstThread = false;
TRY_CRITICAL_BLOCK(cs_Shutdown)
{
fFirstThread = !fTaken;
fTaken = true;
}
static bool fExit;
if (fFirstThread)
{
fShutdown = true;
nTransactionsUpdated++;
DBFlush(false);
StopNode();
DBFlush(true);
boost::filesystem::remove(GetPidFile());
UnregisterWallet(pwalletMain);
delete pwalletMain;
CreateThread(ExitTimeout, NULL);
Sleep(50);
printf("Bitcoin exiting\n\n");
fExit = true;
exit(0);
}
else
{
while (!fExit)
Sleep(500);
Sleep(100);
ExitThread(0);
}
}
void HandleSIGTERM(int)
{
fRequestShutdown = true;
}
//////////////////////////////////////////////////////////////////////////////
//
// Start
//
#if !defined(QT_GUI)
int main(int argc, char* argv[])
{
bool fRet = false;
fRet = AppInit(argc, argv);
if (fRet && fDaemon)
return 0;
return 1;
}
#endif
bool AppInit(int argc, char* argv[])
{
bool fRet = false;
try
{
fRet = AppInit2(argc, argv);
}
catch (std::exception& e) {
PrintException(&e, "AppInit()");
} catch (...) {
PrintException(NULL, "AppInit()");
}
if (!fRet)
Shutdown(NULL);
return fRet;
}
bool AppInit2(int argc, char* argv[])
{
#ifdef _MSC_VER
// Turn off microsoft heap dump noise
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
#endif
#if _MSC_VER >= 1400
// Disable confusing "helpful" text message on abort, ctrl-c
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
#ifndef WIN32
umask(077);
#endif
#ifndef WIN32
// Clean shutdown on SIGTERM
struct sigaction sa;
sa.sa_handler = HandleSIGTERM;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
#endif
//
// Parameters
//
// If Qt is used, parameters are parsed in qt/bitcoin.cpp's main()
#if !defined(QT_GUI)
ParseParameters(argc, argv);
#endif
if (mapArgs.count("-datadir"))
{
if (filesystem::is_directory(filesystem::system_complete(mapArgs["-datadir"])))
{
filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
}
else
{
fprintf(stderr, "Error: Specified directory does not exist\n");
Shutdown(NULL);
}
}
ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
string strUsage = string() +
_("Bitcoin version") + " " + FormatFullVersion() + "\n\n" +
_("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
" bitcoind [options] \t " + "\n" +
" bitcoind [options] <command> [params]\t " + _("Send command to -server or bitcoind") + "\n" +
" bitcoind [options] help \t\t " + _("List commands") + "\n" +
" bitcoind [options] help <command> \t\t " + _("Get help for a command") + "\n" +
_("Options:") + "\n" +
" -conf=<file> \t\t " + _("Specify configuration file (default: bitcoin.conf)") + "\n" +
" -pid=<file> \t\t " + _("Specify pid file (default: bitcoind.pid)") + "\n" +
" -gen \t\t " + _("Generate coins") + "\n" +
" -gen=0 \t\t " + _("Don't generate coins") + "\n" +
" -min \t\t " + _("Start minimized") + "\n" +
" -datadir=<dir> \t\t " + _("Specify data directory") + "\n" +
" -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> \t " + _("Connect through socks4 proxy") + "\n" +
" -dns \t " + _("Allow DNS lookups for addnode and connect") + "\n" +
" -port=<port> \t\t " + _("Listen for connections on <port> (default: 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" +
#else
" -upnp \t " + _("Attempt to use UPnP to map the listening port") + "\n" +
#endif
#endif
" -paytxfee=<amt> \t " + _("Fee per KB to add to transactions you send") + "\n" +
#ifdef GUI
" -server \t\t " + _("Accept command line and JSON-RPC commands") + "\n" +
#endif
#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" +
" -rpcallowip=<ip> \t\t " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
" -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
" -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan \t " + _("Rescan the block chain for missing wallet transactions") + "\n";
#ifdef USE_SSL
strUsage += string() +
_("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" +
" -rpcssl \t " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" +
" -rpcsslcertificatechainfile=<file.cert>\t " + _("Server certificate file (default: server.cert)") + "\n" +
" -rpcsslprivatekeyfile=<file.pem> \t " + _("Server private key (default: server.pem)") + "\n" +
" -rpcsslciphers=<ciphers> \t " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n";
#endif
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());
return false;
}
fDebug = GetBoolArg("-debug");
fAllowDNS = GetBoolArg("-dns");
#ifndef WIN32
fDaemon = GetBoolArg("-daemon");
#else
fDaemon = false;
#endif
if (fDaemon)
fServer = true;
else
fServer = GetBoolArg("-server");
/* force fServer when running without GUI */
#if !defined(QT_GUI)
fServer = true;
#endif
fPrintToConsole = GetBoolArg("-printtoconsole");
fPrintToDebugger = GetBoolArg("-printtodebugger");
fTestNet = GetBoolArg("-testnet");
bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
fNoListen = GetBoolArg("-nolisten") || fTOR;
fLogTimestamps = GetBoolArg("-logtimestamps");
#ifndef QT_GUI
for (int i = 1; i < argc; i++)
if (!IsSwitchChar(argv[i][0]))
fCommandLine = true;
if (fCommandLine)
{
int ret = CommandLineRPC(argc, argv);
exit(ret);
}
#endif
#ifndef WIN32
if (fDaemon)
{
// Daemonize
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
return false;
}
if (pid > 0)
{
CreatePidFile(GetPidFile(), pid);
return true;
}
pid_t sid = setsid();
if (sid < 0)
fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
}
#endif
if (!fDebug && !pszSetDataDir[0])
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());
printf("Default data directory %s\n", GetDefaultDataDir().c_str());
if (GetBoolArg("-loadblockindextest"))
{
CTxDB txdb("r");
txdb.LoadBlockIndex();
PrintBlockTree();
return false;
}
// 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.
if (file) fclose(file);
static boost::interprocess::file_lock lock(strLockFile.c_str());
if (!lock.try_lock())
{
wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin");
return false;
}
// Bind to the port early so we can tell if another instance is already running.
if (!fNoListen)
{
std::string strError;
if (!BindListenPort(strError))
{
wxMessageBox(strError, "Bitcoin");
return false;
}
}
std::ostringstream strErrors;
//
// Load data files
//
if (fDaemon)
fprintf(stdout, "bitcoin server starting\n");
- int64 nStart;
+ int64_t 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;
pwalletMain = new CWallet("wallet.dat");
int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT)
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.str(), "Bitcoin", wxOK | wxICON_ERROR);
return false;
}
else
strErrors << _("Error loading wallet.dat") << "\n";
}
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
RegisterWallet(pwalletMain);
CBlockIndex *pindexRescan = pindexBest;
if (GetBoolArg("-rescan"))
pindexRescan = pindexGenesisBlock;
else
{
CWalletDB walletdb("wallet.dat");
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = locator.GetBlockIndex();
}
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
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight);
printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size());
if (!strErrors.str().empty())
{
wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
return false;
}
// Add wallet transactions that aren't already in a block to mapTransactions
pwalletMain->ReacceptWalletTransactions();
//
// Parameters
//
if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree"))
{
PrintBlockTree();
return false;
}
if (mapArgs.count("-timeout"))
{
int nNewTimeout = GetArg("-timeout", 5000);
if (nNewTimeout > 0 && nNewTimeout < 600000)
nConnectTimeout = nNewTimeout;
}
if (mapArgs.count("-printblock"))
{
string strMatch = mapArgs["-printblock"];
int nFound = 0;
for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
{
uint256 hash = (*mi).first;
if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
{
CBlockIndex* pindex = (*mi).second;
CBlock block;
block.ReadFromDisk(pindex);
block.BuildMerkleTree();
block.print();
printf("\n");
nFound++;
}
}
if (nFound == 0)
printf("No blocks matching %s were found\n", strMatch.c_str());
return false;
}
fGenerateBitcoins = GetBoolArg("-gen");
if (mapArgs.count("-proxy"))
{
fUseProxy = true;
addrProxy = CAddress(mapArgs["-proxy"]);
if (!addrProxy.IsValid())
{
wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
return false;
}
}
if (mapArgs.count("-addnode"))
{
BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
{
CAddress addr(strAddr, fAllowDNS);
addr.nTime = 0; // so it won't relay unless successfully connected
if (addr.IsValid())
AddAddress(addr);
}
}
if (mapArgs.count("-paytxfee"))
{
if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
{
wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
return false;
}
if (nTransactionFee > 0.25 * COIN)
wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
}
if (fHaveUPnP)
{
#if USE_UPNP
if (GetBoolArg("-noupnp"))
fUseUPnP = false;
#else
if (GetBoolArg("-upnp"))
fUseUPnP = true;
#endif
}
//
// Start the node
//
if (!CheckDiskSpace())
return false;
RandAddSeedPerfmon();
if (!CreateThread(StartNode, NULL))
wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
if (fServer)
CreateThread(ThreadRPCServer, NULL);
#ifdef QT_GUI
if(GetStartOnSystemStartup())
SetStartOnSystemStartup(true); // Remove startup links to bitcoin-wx
#endif
#if !defined(QT_GUI)
while (1)
Sleep(5000);
#endif
return true;
}
#ifdef WIN32
string StartupShortcutPath()
{
return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
}
bool GetStartOnSystemStartup()
{
return filesystem::exists(StartupShortcutPath().c_str());
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
// If the shortcut exists already, remove it for updating
remove(StartupShortcutPath().c_str());
if (fAutoStart)
{
CoInitialize(NULL);
// Get a pointer to the IShellLink interface.
IShellLink* psl = NULL;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER, IID_IShellLink,
reinterpret_cast<void**>(&psl));
if (SUCCEEDED(hres))
{
// Get the current executable path
TCHAR pszExePath[MAX_PATH];
GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
TCHAR pszArgs[5] = TEXT("-min");
// Set the path to the shortcut target
psl->SetPath(pszExePath);
PathRemoveFileSpec(pszExePath);
psl->SetWorkingDirectory(pszExePath);
psl->SetShowCmd(SW_SHOWMINNOACTIVE);
psl->SetArguments(pszArgs);
// Query IShellLink for the IPersistFile interface for
// saving the shortcut in persistent storage.
IPersistFile* ppf = NULL;
hres = psl->QueryInterface(IID_IPersistFile,
reinterpret_cast<void**>(&ppf));
if (SUCCEEDED(hres))
{
WCHAR pwsz[MAX_PATH];
// Ensure that the string is ANSI.
MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(pwsz, TRUE);
ppf->Release();
psl->Release();
CoUninitialize();
return true;
}
psl->Release();
}
CoUninitialize();
return false;
}
return true;
}
#elif defined(LINUX)
// Follow the Desktop Application Autostart Spec:
// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
boost::filesystem::path GetAutostartDir()
{
namespace fs = boost::filesystem;
char* pszConfigHome = getenv("XDG_CONFIG_HOME");
if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
char* pszHome = getenv("HOME");
if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
return fs::path();
}
boost::filesystem::path GetAutostartFilePath()
{
return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
}
bool GetStartOnSystemStartup()
{
boost::filesystem::ifstream optionFile(GetAutostartFilePath());
if (!optionFile.good())
return false;
// Scan through file for "Hidden=true":
string line;
while (!optionFile.eof())
{
getline(optionFile, line);
if (line.find("Hidden") != string::npos &&
line.find("true") != string::npos)
return false;
}
optionFile.close();
return true;
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
if (!fAutoStart)
{
#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
unlink(GetAutostartFilePath().string().c_str());
#else
unlink(GetAutostartFilePath().native_file_string().c_str());
#endif
}
else
{
char pszExePath[MAX_PATH+1];
memset(pszExePath, 0, sizeof(pszExePath));
if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
return false;
boost::filesystem::create_directories(GetAutostartDir());
boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
if (!optionFile.good())
return false;
// Write a bitcoin.desktop file to the autostart directory:
optionFile << "[Desktop Entry]\n";
optionFile << "Type=Application\n";
optionFile << "Name=Bitcoin\n";
optionFile << "Exec=" << pszExePath << " -min\n";
optionFile << "Terminal=false\n";
optionFile << "Hidden=false\n";
optionFile.close();
}
return true;
}
#else
// TODO: OSX startup stuff; see:
// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
bool GetStartOnSystemStartup() { return false; }
bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
#endif
diff --git a/src/irc.cpp b/src/irc.cpp
index 5278488dcd..0f6f46e5f7 100644
--- a/src/irc.cpp
+++ b/src/irc.cpp
@@ -1,449 +1,451 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "irc.h"
#include "net.h"
#include "strlcpy.h"
using namespace std;
using namespace boost;
int nGotIRCAddresses = 0;
bool fGotExternalIP = false;
void ThreadIRCSeed2(void* parg);
#pragma pack(push, 1)
struct ircaddr
{
int ip;
short port;
};
#pragma pack(pop)
string EncodeAddress(const CAddress& addr)
{
struct ircaddr tmp;
tmp.ip = addr.ip;
tmp.port = addr.port;
vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
return string("u") + EncodeBase58Check(vch);
}
bool DecodeAddress(string str, CAddress& addr)
{
vector<unsigned char> vch;
if (!DecodeBase58Check(str.substr(1), vch))
return false;
struct ircaddr tmp;
if (vch.size() != sizeof(tmp))
return false;
memcpy(&tmp, &vch[0], sizeof(tmp));
addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
return true;
}
static bool Send(SOCKET hSocket, const char* pszSend)
{
if (strstr(pszSend, "PONG") != pszSend)
printf("IRC SENDING: %s\n", pszSend);
const char* psz = pszSend;
const char* pszEnd = psz + strlen(psz);
while (psz < pszEnd)
{
int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
if (ret < 0)
return false;
psz += ret;
}
return true;
}
bool RecvLine(SOCKET hSocket, string& strLine)
{
strLine = "";
loop
{
char c;
int nBytes = recv(hSocket, &c, 1, 0);
if (nBytes > 0)
{
if (c == '\n')
continue;
if (c == '\r')
return true;
strLine += c;
if (strLine.size() >= 9000)
return true;
}
else if (nBytes <= 0)
{
if (fShutdown)
return false;
if (nBytes < 0)
{
int nErr = WSAGetLastError();
if (nErr == WSAEMSGSIZE)
continue;
if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
{
Sleep(10);
continue;
}
}
if (!strLine.empty())
return true;
if (nBytes == 0)
{
// socket closed
printf("IRC socket closed\n");
return false;
}
else
{
// socket error
int nErr = WSAGetLastError();
printf("IRC recv failed: %d\n", nErr);
return false;
}
}
}
}
bool RecvLineIRC(SOCKET hSocket, string& strLine)
{
loop
{
bool fRet = RecvLine(hSocket, strLine);
if (fRet)
{
if (fShutdown)
return false;
vector<string> vWords;
ParseString(strLine, ' ', vWords);
if (vWords.size() >= 1 && vWords[0] == "PING")
{
strLine[1] = 'O';
strLine += '\r';
Send(hSocket, strLine.c_str());
continue;
}
}
return fRet;
}
}
int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
{
loop
{
string strLine;
strLine.reserve(10000);
if (!RecvLineIRC(hSocket, strLine))
return 0;
printf("IRC %s\n", strLine.c_str());
if (psz1 && strLine.find(psz1) != -1)
return 1;
if (psz2 && strLine.find(psz2) != -1)
return 2;
if (psz3 && strLine.find(psz3) != -1)
return 3;
if (psz4 && strLine.find(psz4) != -1)
return 4;
}
}
bool Wait(int nSeconds)
{
if (fShutdown)
return false;
printf("IRC waiting %d seconds to reconnect\n", nSeconds);
for (int i = 0; i < nSeconds; i++)
{
if (fShutdown)
return false;
Sleep(1000);
}
return true;
}
bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
{
strRet.clear();
loop
{
string strLine;
if (!RecvLineIRC(hSocket, strLine))
return false;
vector<string> vWords;
ParseString(strLine, ' ', vWords);
if (vWords.size() < 2)
continue;
if (vWords[1] == psz1)
{
printf("IRC %s\n", strLine.c_str());
strRet = strLine;
return true;
}
}
}
bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
{
Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
string strLine;
if (!RecvCodeLine(hSocket, "302", strLine))
return false;
vector<string> vWords;
ParseString(strLine, ' ', vWords);
if (vWords.size() < 4)
return false;
string str = vWords[3];
if (str.rfind("@") == string::npos)
return false;
string strHost = str.substr(str.rfind("@")+1);
// Hybrid IRC used by lfnet always returns IP when you userhost yourself,
// but in case another IRC is ever used this should work.
printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
if (fUseProxy)
return false;
CAddress addr(strHost, 0, true);
if (!addr.IsValid())
return false;
ipRet = addr.ip;
return true;
}
void ThreadIRCSeed(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
try
{
ThreadIRCSeed2(parg);
}
catch (std::exception& e) {
PrintExceptionContinue(&e, "ThreadIRCSeed()");
} catch (...) {
PrintExceptionContinue(NULL, "ThreadIRCSeed()");
}
printf("ThreadIRCSeed exiting\n");
}
void ThreadIRCSeed2(void* parg)
{
/* Dont advertise on IRC if we don't allow incoming connections */
if (mapArgs.count("-connect") || fNoListen)
return;
if (GetBoolArg("-noirc"))
return;
printf("ThreadIRCSeed started\n");
int nErrorWait = 10;
int nRetryWait = 10;
bool fNameInUse = false;
bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
while (!fShutdown)
{
//CAddress addrConnect("216.155.130.130:6667"); // chat.freenode.net
CAddress addrConnect("92.243.23.21", 6667); // irc.lfnet.org
if (!fTOR)
{
//struct hostent* phostent = gethostbyname("chat.freenode.net");
CAddress addrIRC("irc.lfnet.org", 6667, true);
if (addrIRC.IsValid())
addrConnect = addrIRC;
}
SOCKET hSocket;
if (!ConnectSocket(addrConnect, hSocket))
{
printf("IRC connect failed\n");
nErrorWait = nErrorWait * 11 / 10;
if (Wait(nErrorWait += 60))
continue;
else
return;
}
if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
nErrorWait = nErrorWait * 11 / 10;
if (Wait(nErrorWait += 60))
continue;
else
return;
}
string strMyName;
if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
strMyName = EncodeAddress(addrLocalHost);
else
strMyName = strprintf("x%u", GetRand(1000000000));
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
if (nRet != 1)
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
if (nRet == 2)
{
printf("IRC name already in use\n");
fNameInUse = true;
Wait(10);
continue;
}
nErrorWait = nErrorWait * 11 / 10;
if (Wait(nErrorWait += 60))
continue;
else
return;
}
Sleep(500);
// Get our external IP from the IRC server and re-nick before joining the channel
CAddress addrFromIRC;
if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
{
printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
if (!fUseProxy && addrFromIRC.IsRoutable())
{
// IRC lets you to re-nick
fGotExternalIP = true;
addrLocalHost.ip = addrFromIRC.ip;
strMyName = EncodeAddress(addrLocalHost);
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
}
}
if (fTestNet) {
Send(hSocket, "JOIN #bitcoinTEST\r");
Send(hSocket, "WHO #bitcoinTEST\r");
} else {
// randomly join #bitcoin00-#bitcoin99
int channel_number = GetRandInt(100);
Send(hSocket, strprintf("JOIN #bitcoin%02d\r", channel_number).c_str());
Send(hSocket, strprintf("WHO #bitcoin%02d\r", channel_number).c_str());
}
- int64 nStart = GetTime();
+ int64_t nStart = GetTime();
string strLine;
strLine.reserve(10000);
while (!fShutdown && RecvLineIRC(hSocket, strLine))
{
if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
continue;
vector<string> vWords;
ParseString(strLine, ' ', vWords);
if (vWords.size() < 2)
continue;
char pszName[10000];
pszName[0] = '\0';
if (vWords[1] == "352" && vWords.size() >= 8)
{
// index 7 is limited to 16 characters
// could get full length name at index 10, but would be different from join messages
strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
printf("IRC got who\n");
}
if (vWords[1] == "JOIN" && vWords[0].size() > 1)
{
// :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
if (strchr(pszName, '!'))
*strchr(pszName, '!') = '\0';
printf("IRC got join\n");
}
if (pszName[0] == 'u')
{
CAddress addr;
if (DecodeAddress(pszName, addr))
{
addr.nTime = GetAdjustedTime();
if (AddAddress(addr, 51 * 60))
printf("IRC got new address: %s\n", addr.ToString().c_str());
nGotIRCAddresses++;
}
else
{
printf("IRC decode failed\n");
}
}
}
closesocket(hSocket);
hSocket = INVALID_SOCKET;
// IRC usually blocks TOR, so only try once
if (fTOR)
return;
if (GetTime() - nStart > 20 * 60)
{
nErrorWait /= 3;
nRetryWait /= 3;
}
nRetryWait = nRetryWait * 11 / 10;
if (!Wait(nRetryWait += 60))
return;
}
}
#ifdef TEST
int main(int argc, char *argv[])
{
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
{
printf("Error at WSAStartup()\n");
return false;
}
ThreadIRCSeed(NULL);
WSACleanup();
return 0;
}
#endif
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 21fb0f91b2..c1f54a5fa8 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -1,208 +1,210 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "crypter.h"
#include "db.h"
#include "script.h"
std::vector<unsigned char> CKeyStore::GenerateNewKey()
{
RandAddSeedPerfmon();
CKey key;
key.MakeNewKey();
if (!AddKey(key))
throw std::runtime_error("CKeyStore::GenerateNewKey() : AddKey failed");
return key.GetPubKey();
}
bool CKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char> &vchPubKeyOut) const
{
CKey key;
if (!GetKey(address, key))
return false;
vchPubKeyOut = key.GetPubKey();
return true;
}
bool CBasicKeyStore::AddKey(const CKey& key)
{
CRITICAL_BLOCK(cs_KeyStore)
mapKeys[CBitcoinAddress(key.GetPubKey())] = key.GetSecret();
return true;
}
bool CBasicKeyStore::AddCScript(const uint160 &hash, const CScript& redeemScript)
{
CRITICAL_BLOCK(cs_KeyStore)
mapScripts[hash] = redeemScript;
return true;
}
bool CBasicKeyStore::HaveCScript(const uint160& hash) const
{
bool result;
CRITICAL_BLOCK(cs_KeyStore)
result = (mapScripts.count(hash) > 0);
return result;
}
bool CBasicKeyStore::GetCScript(const uint160 &hash, CScript& redeemScriptOut) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
ScriptMap::const_iterator mi = mapScripts.find(hash);
if (mi != mapScripts.end())
{
redeemScriptOut = (*mi).second;
return true;
}
}
return false;
}
bool CCryptoKeyStore::SetCrypted()
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (fUseCrypto)
return true;
if (!mapKeys.empty())
return false;
fUseCrypto = true;
}
return true;
}
std::vector<unsigned char> CCryptoKeyStore::GenerateNewKey()
{
RandAddSeedPerfmon();
CKey key;
key.MakeNewKey();
if (!AddKey(key))
throw std::runtime_error("CCryptoKeyStore::GenerateNewKey() : AddKey failed");
return key.GetPubKey();
}
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!SetCrypted())
return false;
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
{
const std::vector<unsigned char> &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CSecret vchSecret;
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecret))
return false;
CKey key;
key.SetSecret(vchSecret);
if (key.GetPubKey() == vchPubKey)
break;
return false;
}
vMasterKey = vMasterKeyIn;
}
return true;
}
bool CCryptoKeyStore::AddKey(const CKey& key)
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!IsCrypted())
return CBasicKeyStore::AddKey(key);
if (IsLocked())
return false;
std::vector<unsigned char> vchCryptedSecret;
std::vector<unsigned char> vchPubKey = key.GetPubKey();
if (!EncryptSecret(vMasterKey, key.GetSecret(), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
return false;
if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
return false;
}
return true;
}
bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!SetCrypted())
return false;
mapCryptedKeys[CBitcoinAddress(vchPubKey)] = make_pair(vchPubKey, vchCryptedSecret);
}
return true;
}
bool CCryptoKeyStore::GetSecret(const CBitcoinAddress &address, CSecret& vchSecretOut) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!IsCrypted())
return CBasicKeyStore::GetSecret(address, vchSecretOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
const std::vector<unsigned char> &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
return DecryptSecret(vMasterKey, vchCryptedSecret, Hash(vchPubKey.begin(), vchPubKey.end()), vchSecretOut);
}
}
return false;
}
bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!IsCrypted())
return CKeyStore::GetPubKey(address, vchPubKeyOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
vchPubKeyOut = (*mi).second.first;
return true;
}
}
return false;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!mapCryptedKeys.empty() || IsCrypted())
return false;
fUseCrypto = true;
CKey key;
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
{
if (!key.SetSecret(mKey.second))
return false;
const std::vector<unsigned char> vchPubKey = key.GetPubKey();
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, key.GetSecret(), Hash(vchPubKey.begin(), vchPubKey.end()), vchCryptedSecret))
return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
}
mapKeys.clear();
}
return true;
}
diff --git a/src/keystore.h b/src/keystore.h
index 669bf90174..975c2b9ba9 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -1,188 +1,190 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
+#include <stdint.h>
+
#include "crypter.h"
#include "script.h"
// A virtual base class for key stores
class CKeyStore
{
protected:
mutable CCriticalSection cs_KeyStore;
public:
// Add a key to the store.
virtual bool AddKey(const CKey& key) =0;
// Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CBitcoinAddress &address) const =0;
virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const
{
CSecret vchSecret;
if (!GetSecret(address, vchSecret))
return false;
if (!keyOut.SetSecret(vchSecret))
return false;
return true;
}
virtual void GetKeys(std::set<CBitcoinAddress> &setAddress) const =0;
virtual bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
// Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
virtual bool AddCScript(const uint160 &hash, const CScript& redeemScript) =0;
virtual bool HaveCScript(const uint160 &hash) const =0;
virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const =0;
// Generate a new key, and add it to the store
virtual std::vector<unsigned char> GenerateNewKey();
virtual bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const
{
CKey key;
if (!GetKey(address, key))
return false;
vchSecret = key.GetSecret();
return true;
}
};
typedef std::map<CBitcoinAddress, CSecret> KeyMap;
typedef std::map<uint160, CScript > ScriptMap;
// Basic key store, that keeps keys in an address->secret map
class CBasicKeyStore : public CKeyStore
{
protected:
KeyMap mapKeys;
ScriptMap mapScripts;
public:
bool AddKey(const CKey& key);
bool HaveKey(const CBitcoinAddress &address) const
{
bool result;
CRITICAL_BLOCK(cs_KeyStore)
result = (mapKeys.count(address) > 0);
return result;
}
void GetKeys(std::set<CBitcoinAddress> &setAddress) const
{
setAddress.clear();
CRITICAL_BLOCK(cs_KeyStore)
{
KeyMap::const_iterator mi = mapKeys.begin();
while (mi != mapKeys.end())
{
setAddress.insert((*mi).first);
mi++;
}
}
}
bool GetSecret(const CBitcoinAddress &address, CSecret &vchSecret) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
KeyMap::const_iterator mi = mapKeys.find(address);
if (mi != mapKeys.end())
{
vchSecret = (*mi).second;
return true;
}
}
return false;
}
virtual bool AddCScript(const uint160 &hash, const CScript& redeemScript);
virtual bool HaveCScript(const uint160 &hash) const;
virtual bool GetCScript(const uint160 &hash, CScript& redeemScriptOut) const;
};
typedef std::map<CBitcoinAddress, std::pair<std::vector<unsigned char>, std::vector<unsigned char> > > CryptedKeyMap;
// Keystore which keeps the private keys encrypted
// It derives from the basic key store, which is used if no encryption is active.
class CCryptoKeyStore : public CBasicKeyStore
{
private:
CryptedKeyMap mapCryptedKeys;
CKeyingMaterial vMasterKey;
// if fUseCrypto is true, mapKeys must be empty
// if fUseCrypto is false, vMasterKey must be empty
bool fUseCrypto;
protected:
bool SetCrypted();
// will encrypt previously unencrypted keys
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
public:
CCryptoKeyStore() : fUseCrypto(false)
{
}
bool IsCrypted() const
{
return fUseCrypto;
}
bool IsLocked() const
{
if (!IsCrypted())
return false;
bool result;
CRITICAL_BLOCK(cs_KeyStore)
result = vMasterKey.empty();
return result;
}
bool Lock()
{
if (!SetCrypted())
return false;
CRITICAL_BLOCK(cs_KeyStore)
vMasterKey.clear();
return true;
}
virtual bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
std::vector<unsigned char> GenerateNewKey();
bool AddKey(const CKey& key);
bool HaveKey(const CBitcoinAddress &address) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!IsCrypted())
return CBasicKeyStore::HaveKey(address);
return mapCryptedKeys.count(address) > 0;
}
return false;
}
bool GetSecret(const CBitcoinAddress &address, CSecret& vchSecret) const;
bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
void GetKeys(std::set<CBitcoinAddress> &setAddress) const
{
if (!IsCrypted())
{
CBasicKeyStore::GetKeys(setAddress);
return;
}
setAddress.clear();
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
while (mi != mapCryptedKeys.end())
{
setAddress.insert((*mi).first);
mi++;
}
}
};
#endif
diff --git a/src/main.cpp b/src/main.cpp
index bef76f7374..0b004466a0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,3308 +1,3311 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "checkpoints.h"
#include "db.h"
#include "net.h"
#include "init.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace std;
using namespace boost;
//
// Global state
//
// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("bitcoin-qt");
CCriticalSection cs_setpwalletRegistered;
set<CWallet*> setpwalletRegistered;
CCriticalSection cs_main;
static map<uint256, CTransaction> mapTransactions;
CCriticalSection cs_mapTransactions;
unsigned int nTransactionsUpdated = 0;
map<COutPoint, CInPoint> mapNextTx;
map<uint256, CBlockIndex*> mapBlockIndex;
uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
CBigNum bnBestChainWork = 0;
CBigNum bnBestInvalidWork = 0;
uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL;
-int64 nTimeBestReceived = 0;
+int64_t nTimeBestReceived = 0;
CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
map<uint256, CDataStream*> mapOrphanTransactions;
multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
double dHashesPerSec;
-int64 nHPSTimerStart;
+int64_t nHPSTimerStart;
// Settings
int fGenerateBitcoins = false;
-int64 nTransactionFee = 0;
+int64_t nTransactionFee = 0;
int fLimitProcessors = false;
int nLimitProcessors = 1;
int fMinimizeToTray = true;
int fMinimizeOnClose = true;
#if USE_UPNP
int fUseUPnP = true;
#else
int fUseUPnP = false;
#endif
//////////////////////////////////////////////////////////////////////////////
//
// dispatching functions
//
// These functions dispatch to one or all registered wallets
void RegisterWallet(CWallet* pwalletIn)
{
CRITICAL_BLOCK(cs_setpwalletRegistered)
{
setpwalletRegistered.insert(pwalletIn);
}
}
void UnregisterWallet(CWallet* pwalletIn)
{
CRITICAL_BLOCK(cs_setpwalletRegistered)
{
setpwalletRegistered.erase(pwalletIn);
}
}
// check whether the passed transaction is from us
bool static IsFromMe(CTransaction& tx)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
if (pwallet->IsFromMe(tx))
return true;
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)
if (pwallet->GetTransaction(hashTx,wtx))
return true;
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)
pwallet->ResendWalletTransactions();
}
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
//
void static AddOrphanTx(const CDataStream& vMsg)
{
CTransaction tx;
CDataStream(vMsg) >> tx;
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
return;
CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
}
void static EraseOrphanTx(uint256 hash)
{
if (!mapOrphanTransactions.count(hash))
return;
const CDataStream* pvMsg = mapOrphanTransactions[hash];
CTransaction tx;
CDataStream(*pvMsg) >> tx;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash);
mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);)
{
if ((*mi).second == pvMsg)
mapOrphanTransactionsByPrev.erase(mi++);
else
mi++;
}
}
delete pvMsg;
mapOrphanTransactions.erase(hash);
}
//////////////////////////////////////////////////////////////////////////////
//
// CTransaction and CTxIndex
//
bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet)
{
SetNull();
if (!txdb.ReadTxIndex(prevout.hash, txindexRet))
return false;
if (!ReadFromDisk(txindexRet.pos))
return false;
if (prevout.n >= vout.size())
{
SetNull();
return false;
}
return true;
}
bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout)
{
CTxIndex txindex;
return ReadFromDisk(txdb, prevout, txindex);
}
bool CTransaction::ReadFromDisk(COutPoint prevout)
{
CTxDB txdb("r");
CTxIndex txindex;
return ReadFromDisk(txdb, prevout, txindex);
}
bool CTransaction::IsStandard() const
{
BOOST_FOREACH(const CTxIn& txin, vin)
{
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
// in an OP_EVAL, which is 3 ~80-byte signatures, 3
// ~65-byte public keys, plus a few script ops.
if (txin.scriptSig.size() > 500)
return error("nonstandard txin, size %d is too large\n", txin.scriptSig.size());
if (!txin.scriptSig.IsPushOnly())
return error("nonstandard txin (opcodes other than PUSH): %s", txin.scriptSig.ToString().c_str());
}
BOOST_FOREACH(const CTxOut& txout, vout)
if (!::IsStandard(txout.scriptPubKey))
return error("nonstandard txout: %s", txout.scriptPubKey.ToString().c_str());
return true;
}
//
// Check transaction inputs, and make sure any
// OP_EVAL transactions are evaluating IsStandard scripts
//
// Why bother? To avoid denial-of-service attacks; an attacker
// can submit a standard DUP HASH... OP_EVAL transaction,
// which will get accepted into blocks. The script being
// EVAL'ed can be anything; an attacker could use a very
// expensive-to-check-upon-redemption script like:
// DUP CHECKSIG DROP ... repeated 100 times... OP_1
//
bool CTransaction::AreInputsStandard(std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs) const
{
if (fTestNet)
return true; // Allow non-standard on testnet
for (int i = 0; i < vin.size(); i++)
{
COutPoint prevout = vin[i].prevout;
assert(mapInputs.count(prevout.hash) > 0);
CTransaction& txPrev = mapInputs[prevout.hash].second;
vector<vector<unsigned char> > vSolutions;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
CScript& prevScript = txPrev.vout[prevout.n].scriptPubKey;
if (!Solver(prevScript, whichType, vSolutions))
return error("nonstandard txin (spending nonstandard txout %s)", prevScript.ToString().c_str());
if (whichType == TX_SCRIPTHASH)
{
vector<vector<unsigned char> > stack;
int nUnused;
if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0, true, nUnused))
return false;
CScript subscript(stack.back().begin(), stack.back().end());
if (!::IsStandard(subscript))
return error("nonstandard txin (nonstandard OP_EVAL subscript %s)", subscript.ToString().c_str());
}
}
return true;
}
int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
{
if (fClient)
{
if (hashBlock == 0)
return 0;
}
else
{
CBlock blockTmp;
if (pblock == NULL)
{
// Load the block this tx is in
CTxIndex txindex;
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
return 0;
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
return 0;
pblock = &blockTmp;
}
// Update the tx's hashBlock
hashBlock = pblock->GetHash();
// Locate the transaction
for (nIndex = 0; nIndex < pblock->vtx.size(); nIndex++)
if (pblock->vtx[nIndex] == *(CTransaction*)this)
break;
if (nIndex == pblock->vtx.size())
{
vMerkleBranch.clear();
nIndex = -1;
printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
return 0;
}
// Fill in merkle branch
vMerkleBranch = pblock->GetMerkleBranch(nIndex);
}
// Is the tx in a block that's in the main chain
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !pindex->IsInMainChain())
return 0;
return pindexBest->nHeight - pindex->nHeight + 1;
}
bool CTransaction::CheckTransaction() const
{
// Basic checks that don't depend on any context
if (vin.empty())
return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
if (vout.empty())
return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
// Size limits
if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values
- int64 nValueOut = 0;
+ int64_t nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout)
{
if (txout.nValue < 0)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
if (txout.nValue > MAX_MONEY)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
}
// Check for duplicate inputs
set<COutPoint> vInOutPoints;
BOOST_FOREACH(const CTxIn& txin, vin)
{
if (vInOutPoints.count(txin.prevout))
return false;
vInOutPoints.insert(txin.prevout);
}
if (IsCoinBase())
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
}
else
{
BOOST_FOREACH(const CTxIn& txin, vin)
if (txin.prevout.IsNull())
return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
}
return true;
}
bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
{
if (pfMissingInputs)
*pfMissingInputs = false;
if (!CheckTransaction())
return error("AcceptToMemoryPool() : CheckTransaction failed");
// Coinbase is only valid in a block, not as a loose transaction
if (IsCoinBase())
return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
// To help v0.1.5 clients who would see it as a negative number
- if ((int64)nLockTime > std::numeric_limits<int>::max())
+ if ((int64_t)nLockTime > std::numeric_limits<int>::max())
return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
// Rather not work on nonstandard transactions (unless -testnet)
if (!fTestNet && !IsStandard())
return error("AcceptToMemoryPool() : nonstandard transaction type");
// Do we already have it?
uint256 hash = GetHash();
CRITICAL_BLOCK(cs_mapTransactions)
if (mapTransactions.count(hash))
return false;
if (fCheckInputs)
if (txdb.ContainsTx(hash))
return false;
// Check for conflicts with in-memory transactions
CTransaction* ptxOld = NULL;
for (int i = 0; i < vin.size(); i++)
{
COutPoint outpoint = vin[i].prevout;
if (mapNextTx.count(outpoint))
{
// Disable replacement feature for now
return false;
// Allow replacing with a newer version of the same transaction
if (i != 0)
return false;
ptxOld = mapNextTx[outpoint].ptx;
if (ptxOld->IsFinal())
return false;
if (!IsNewerThan(*ptxOld))
return false;
for (int i = 0; i < vin.size(); i++)
{
COutPoint outpoint = vin[i].prevout;
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
return false;
}
break;
}
}
if (fCheckInputs)
{
map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
map<uint256, CTxIndex> mapUnused;
if (!FetchInputs(txdb, mapUnused, false, false, mapInputs))
{
if (pfMissingInputs)
*pfMissingInputs = true;
return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
}
// Check for non-standard OP_EVALs in inputs
if (!AreInputsStandard(mapInputs))
return error("AcceptToMemoryPool() : nonstandard transaction input");
// Check against previous transactions
- int64 nFees = 0;
+ int64_t nFees = 0;
int nSigOps = 0;
if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false, nSigOps))
{
if (pfMissingInputs)
*pfMissingInputs = true;
return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
// Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
// attacks disallow transactions with more than one SigOp per 65 bytes.
// 65 bytes because that is the minimum size of an ECDSA signature
unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
if (nSigOps > nSize / 65 || nSize < 100)
return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
// Don't accept it if it can't get into a block
if (nFees < GetMinFee(1000, true, GMF_RELAY))
return error("AcceptToMemoryPool() : not enough fees");
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make other's transactions take longer to confirm.
if (nFees < MIN_RELAY_TX_FEE)
{
static CCriticalSection cs;
static double dFreeCount;
- static int64 nLastTime;
- int64 nNow = GetTime();
+ static int64_t nLastTime;
+ int64_t nNow = GetTime();
CRITICAL_BLOCK(cs)
{
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(*this))
return error("AcceptToMemoryPool() : free transaction rejected by rate limiter");
if (fDebug)
printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}
}
}
// Store transaction in memory
CRITICAL_BLOCK(cs_mapTransactions)
{
if (ptxOld)
{
printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
ptxOld->RemoveFromMemoryPool();
}
AddToMemoryPoolUnchecked();
}
///// are we sure this is ok when loading transactions or restoring block txes
// If updated, erase old tx from wallet
if (ptxOld)
EraseFromWallets(ptxOld->GetHash());
printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
return true;
}
bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
{
CTxDB txdb("r");
return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
}
bool CTransaction::AddToMemoryPoolUnchecked()
{
// Add to memory pool without checking anything. Don't call this directly,
// call AcceptToMemoryPool to properly check the transaction first.
CRITICAL_BLOCK(cs_mapTransactions)
{
uint256 hash = GetHash();
mapTransactions[hash] = *this;
for (int i = 0; i < vin.size(); i++)
mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
nTransactionsUpdated++;
}
return true;
}
bool CTransaction::RemoveFromMemoryPool()
{
// Remove transaction from memory pool
CRITICAL_BLOCK(cs_mapTransactions)
{
BOOST_FOREACH(const CTxIn& txin, vin)
mapNextTx.erase(txin.prevout);
mapTransactions.erase(GetHash());
nTransactionsUpdated++;
}
return true;
}
int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
{
if (hashBlock == 0 || nIndex == -1)
return 0;
// Find the block it claims to be in
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !pindex->IsInMainChain())
return 0;
// Make sure the merkle branch connects to this block
if (!fMerkleVerified)
{
if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
return 0;
fMerkleVerified = true;
}
pindexRet = pindex;
return pindexBest->nHeight - pindex->nHeight + 1;
}
int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
return 0;
return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());
}
bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
{
if (fClient)
{
if (!IsInMainChain() && !ClientConnectInputs())
return false;
return CTransaction::AcceptToMemoryPool(txdb, false);
}
else
{
return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs);
}
}
bool CMerkleTx::AcceptToMemoryPool()
{
CTxDB txdb("r");
return AcceptToMemoryPool(txdb);
}
bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
{
CRITICAL_BLOCK(cs_mapTransactions)
{
// Add previous supporting transactions first
BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
{
if (!tx.IsCoinBase())
{
uint256 hash = tx.GetHash();
if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash))
tx.AcceptToMemoryPool(txdb, fCheckInputs);
}
}
return AcceptToMemoryPool(txdb, fCheckInputs);
}
return false;
}
bool CWalletTx::AcceptWalletTransaction()
{
CTxDB txdb("r");
return AcceptWalletTransaction(txdb);
}
int CTxIndex::GetDepthInMainChain() const
{
// Read block header
CBlock block;
if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false))
return 0;
// Find the block in the index
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.GetHash());
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !pindex->IsInMainChain())
return 0;
return 1 + nBestHeight - pindex->nHeight;
}
//////////////////////////////////////////////////////////////////////////////
//
// CBlock and CBlockIndex
//
bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
{
if (!fReadTransactions)
{
*this = pindex->GetBlockHeader();
return true;
}
if (!ReadFromDisk(pindex->nFile, pindex->nBlockPos, fReadTransactions))
return false;
if (GetHash() != pindex->GetBlockHash())
return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
return true;
}
uint256 static GetOrphanRoot(const CBlock* pblock)
{
// Work back to the first block in the orphan chain
while (mapOrphanBlocks.count(pblock->hashPrevBlock))
pblock = mapOrphanBlocks[pblock->hashPrevBlock];
return pblock->GetHash();
}
-int64 static GetBlockValue(int nHeight, int64 nFees)
+int64_t static GetBlockValue(int nHeight, int64_t nFees)
{
- int64 nSubsidy = 50 * COIN;
+ int64_t nSubsidy = 50 * COIN;
// Subsidy is cut in half every 4 years
nSubsidy >>= (nHeight / 210000);
return nSubsidy + nFees;
}
-static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
-static const int64 nTargetSpacing = 10 * 60;
-static const int64 nInterval = nTargetTimespan / nTargetSpacing;
+static const int64_t nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+static const int64_t nTargetSpacing = 10 * 60;
+static const int64_t 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)
+unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime)
{
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)
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();
+ int64_t 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
CBigNum bnNew;
bnNew.SetCompact(pindexLast->nBits);
bnNew *= nActualTimespan;
bnNew /= nTargetTimespan;
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();
}
bool CheckProofOfWork(uint256 hash, unsigned int nBits)
{
CBigNum bnTarget;
bnTarget.SetCompact(nBits);
// Check range
if (bnTarget <= 0 || bnTarget > bnProofOfWorkLimit)
return error("CheckProofOfWork() : nBits below minimum work");
// Check proof of work matches claimed amount
if (hash > bnTarget.getuint256())
return error("CheckProofOfWork() : hash doesn't match nBits");
return true;
}
// Return maximum amount of blocks that other nodes claim to have
int GetNumBlocksOfPeers()
{
return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate());
}
bool IsInitialBlockDownload()
{
if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
return true;
- static int64 nLastUpdate;
+ static int64_t nLastUpdate;
static CBlockIndex* pindexLastBest;
if (pindexBest != pindexLastBest)
{
pindexLastBest = pindexBest;
nLastUpdate = GetTime();
}
return (GetTime() - nLastUpdate < 10 &&
pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
}
void static InvalidChainFound(CBlockIndex* pindexNew)
{
if (pindexNew->bnChainWork > bnBestInvalidWork)
{
bnBestInvalidWork = pindexNew->bnChainWork;
CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
MainFrameRepaint();
}
printf("InvalidChainFound: invalid block=%s height=%d work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str());
printf("InvalidChainFound: current best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
printf("InvalidChainFound: WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
}
bool CTransaction::DisconnectInputs(CTxDB& txdb)
{
// Relinquish previous transactions' spent pointers
if (!IsCoinBase())
{
BOOST_FOREACH(const CTxIn& txin, vin)
{
COutPoint prevout = txin.prevout;
// Get prev txindex from disk
CTxIndex txindex;
if (!txdb.ReadTxIndex(prevout.hash, txindex))
return error("DisconnectInputs() : ReadTxIndex failed");
if (prevout.n >= txindex.vSpent.size())
return error("DisconnectInputs() : prevout.n out of range");
// Mark outpoint as not spent
txindex.vSpent[prevout.n].SetNull();
// Write back
if (!txdb.UpdateTxIndex(prevout.hash, txindex))
return error("DisconnectInputs() : UpdateTxIndex failed");
}
}
// Remove transaction from index
if (!txdb.EraseTxIndex(*this))
return error("DisconnectInputs() : EraseTxPos failed");
return true;
}
bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool,
bool fBlock, bool fMiner, map<uint256, pair<CTxIndex, CTransaction> >& inputsRet)
{
if (IsCoinBase())
return true; // Coinbase transactions have no inputs to fetch.
for (int i = 0; i < vin.size(); i++)
{
COutPoint prevout = vin[i].prevout;
if (inputsRet.count(prevout.hash))
continue; // Got it already
// Read txindex
CTxIndex& txindex = inputsRet[prevout.hash].first;
bool fFound = true;
if ((fBlock || fMiner) && mapTestPool.count(prevout.hash))
{
// Get txindex from current proposed changes
txindex = mapTestPool.find(prevout.hash)->second;
}
else
{
// Read txindex from txdb
fFound = txdb.ReadTxIndex(prevout.hash, txindex);
}
if (!fFound && (fBlock || fMiner))
return fMiner ? false : error("FetchInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
// Read txPrev
CTransaction& txPrev = inputsRet[prevout.hash].second;
if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
{
// Get prev tx from single transactions in memory
CRITICAL_BLOCK(cs_mapTransactions)
{
if (!mapTransactions.count(prevout.hash))
return error("FetchInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
txPrev = mapTransactions[prevout.hash];
}
if (!fFound)
txindex.vSpent.resize(txPrev.vout.size());
}
else
{
// Get prev tx from disk
if (!txPrev.ReadFromDisk(txindex.pos))
return error("FetchInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
}
}
return true;
}
bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inputs,
map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
- CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64 nMinFee)
+ CBlockIndex* pindexBlock, int64_t& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64_t 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;
+ int64_t nValueIn = 0;
for (int i = 0; i < vin.size(); i++)
{
COutPoint prevout = vin[i].prevout;
assert(inputs.count(prevout.hash) > 0);
CTxIndex& txindex = inputs[prevout.hash].first;
CTransaction& txPrev = inputs[prevout.hash].second;
if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
// If prev is coinbase, check that it's matured
if (txPrev.IsCoinBase())
for (CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < COINBASE_MATURITY; pindex = pindex->pprev)
if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
// 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()))
{
bool fStrictOpEval = true;
// This code should be removed when OP_EVAL has
// a majority of hashing power on the network.
if (fBlock)
{
// To avoid being on the short end of a block-chain split,
// interpret OP_EVAL as a NO_OP until blocks with timestamps
// after opevaltime:
- int64 nEvalSwitchTime = GetArg("opevaltime", 1328054400); // Feb 1, 2012
+ int64_t nEvalSwitchTime = GetArg("opevaltime", 1328054400); // Feb 1, 2012
fStrictOpEval = (pindexBlock->nTime >= nEvalSwitchTime);
}
// if !fBlock, then always be strict-- don't accept
// invalid-under-new-rules OP_EVAL transactions into
// our memory pool (don't relay them, don't include them
// in blocks we mine).
// Verify signature
if (!VerifySignature(txPrev, *this, i, nSigOpsRet, fStrictOpEval))
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 DoS(100, error("ConnectInputs() : txin values out of range"));
// Mark outpoints as spent
txindex.vSpent[prevout.n] = posThisTx;
// Write back
if (fBlock || fMiner)
{
mapTestPool[prevout.hash] = txindex;
}
}
if (nValueIn < GetValueOut())
return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
// Tally transaction fees
- int64 nTxFee = nValueIn - GetValueOut();
+ int64_t nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0)
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 DoS(100, error("ConnectInputs() : nFees out of range"));
}
if (fBlock)
{
// Add transaction to changes
mapTestPool[GetHash()] = CTxIndex(posThisTx, vout.size());
}
else if (fMiner)
{
// Add transaction to test pool
mapTestPool[GetHash()] = CTxIndex(CDiskTxPos(1,1,1), vout.size());
}
return true;
}
bool CTransaction::ClientConnectInputs()
{
if (IsCoinBase())
return false;
// Take over previous transactions' spent pointers
CRITICAL_BLOCK(cs_mapTransactions)
{
- int64 nValueIn = 0;
+ int64_t nValueIn = 0;
for (int i = 0; i < vin.size(); i++)
{
// Get prev tx from single transactions in memory
COutPoint prevout = vin[i].prevout;
if (!mapTransactions.count(prevout.hash))
return false;
CTransaction& txPrev = mapTransactions[prevout.hash];
if (prevout.n >= txPrev.vout.size())
return false;
// Verify signature
int nUnused = 0;
if (!VerifySignature(txPrev, *this, i, nUnused, false))
return error("ConnectInputs() : VerifySignature failed");
///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of
///// this has to go away now that posNext is gone
// // Check for conflicts
// if (!txPrev.vout[prevout.n].posNext.IsNull())
// return error("ConnectInputs() : prev tx already used");
//
// // Flag outpoints as used
// txPrev.vout[prevout.n].posNext = posThisTx;
nValueIn += txPrev.vout[prevout.n].nValue;
if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
return error("ClientConnectInputs() : txin values out of range");
}
if (GetValueOut() > nValueIn)
return false;
}
return true;
}
bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex)
{
// Disconnect in reverse order
for (int i = vtx.size()-1; i >= 0; i--)
if (!vtx[i].DisconnectInputs(txdb))
return false;
// Update block index on disk without changing it in memory.
// The memory index structure will be changed after the db commits.
if (pindex->pprev)
{
CDiskBlockIndex blockindexPrev(pindex->pprev);
blockindexPrev.hashNext = 0;
if (!txdb.WriteBlockIndex(blockindexPrev))
return error("DisconnectBlock() : WriteBlockIndex failed");
}
return true;
}
bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
{
// Check it again in case a previous version let a bad block in
if (!CheckBlock())
return false;
//// issue here: it doesn't know the version
unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
map<uint256, CTxIndex> mapQueuedChanges;
- int64 nFees = 0;
+ int64_t nFees = 0;
int nSigOps = 0;
BOOST_FOREACH(CTransaction& tx, vtx)
{
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
nTxPos += ::GetSerializeSize(tx, SER_DISK);
map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs))
return false;
if (!tx.ConnectInputs(mapInputs, mapQueuedChanges, posThisTx, pindex, nFees, true, false, nSigOps))
return false;
if (nSigOps > MAX_BLOCK_SIGOPS)
return DoS(100, error("ConnectBlock() : too many sigops"));
}
// Write queued txindex changes
for (map<uint256, CTxIndex>::iterator mi = mapQueuedChanges.begin(); mi != mapQueuedChanges.end(); ++mi)
{
if (!txdb.UpdateTxIndex((*mi).first, (*mi).second))
return error("ConnectBlock() : UpdateTxIndex failed");
}
if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
return false;
// Update block index on disk without changing it in memory.
// The memory index structure will be changed after the db commits.
if (pindex->pprev)
{
CDiskBlockIndex blockindexPrev(pindex->pprev);
blockindexPrev.hashNext = pindex->GetBlockHash();
if (!txdb.WriteBlockIndex(blockindexPrev))
return error("ConnectBlock() : WriteBlockIndex failed");
}
// Watch for transactions paying to me
BOOST_FOREACH(CTransaction& tx, vtx)
SyncWithWallets(tx, this, true);
return true;
}
bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{
printf("REORGANIZE\n");
// Find the fork
CBlockIndex* pfork = pindexBest;
CBlockIndex* plonger = pindexNew;
while (pfork != plonger)
{
while (plonger->nHeight > pfork->nHeight)
if (!(plonger = plonger->pprev))
return error("Reorganize() : plonger->pprev is null");
if (pfork == plonger)
break;
if (!(pfork = pfork->pprev))
return error("Reorganize() : pfork->pprev is null");
}
// List of what to disconnect
vector<CBlockIndex*> vDisconnect;
for (CBlockIndex* pindex = pindexBest; pindex != pfork; pindex = pindex->pprev)
vDisconnect.push_back(pindex);
// List of what to connect
vector<CBlockIndex*> vConnect;
for (CBlockIndex* pindex = pindexNew; pindex != pfork; pindex = pindex->pprev)
vConnect.push_back(pindex);
reverse(vConnect.begin(), vConnect.end());
// Disconnect shorter branch
vector<CTransaction> vResurrect;
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
{
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("Reorganize() : ReadFromDisk for disconnect failed");
if (!block.DisconnectBlock(txdb, pindex))
return error("Reorganize() : DisconnectBlock failed");
// Queue memory transactions to resurrect
BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!tx.IsCoinBase())
vResurrect.push_back(tx);
}
// Connect longer branch
vector<CTransaction> vDelete;
for (int i = 0; i < vConnect.size(); i++)
{
CBlockIndex* pindex = vConnect[i];
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("Reorganize() : ReadFromDisk for connect failed");
if (!block.ConnectBlock(txdb, pindex))
{
// Invalid block
txdb.TxnAbort();
return error("Reorganize() : ConnectBlock failed");
}
// Queue memory transactions to delete
BOOST_FOREACH(const CTransaction& tx, block.vtx)
vDelete.push_back(tx);
}
if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash()))
return error("Reorganize() : WriteHashBestChain failed");
// Make sure it's successfully written to disk before changing memory structure
if (!txdb.TxnCommit())
return error("Reorganize() : TxnCommit failed");
// Disconnect shorter branch
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
if (pindex->pprev)
pindex->pprev->pnext = NULL;
// Connect longer branch
BOOST_FOREACH(CBlockIndex* pindex, vConnect)
if (pindex->pprev)
pindex->pprev->pnext = pindex;
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH(CTransaction& tx, vResurrect)
tx.AcceptToMemoryPool(txdb, false);
// Delete redundant memory transactions that are in the connected branch
BOOST_FOREACH(CTransaction& tx, vDelete)
tx.RemoveFromMemoryPool();
return true;
}
bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
{
uint256 hash = GetHash();
txdb.TxnBegin();
if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
{
txdb.WriteHashBestChain(hash);
if (!txdb.TxnCommit())
return error("SetBestChain() : TxnCommit failed");
pindexGenesisBlock = pindexNew;
}
else if (hashPrevBlock == hashBestChain)
{
// Adding to current best branch
if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
{
txdb.TxnAbort();
InvalidChainFound(pindexNew);
return error("SetBestChain() : ConnectBlock failed");
}
if (!txdb.TxnCommit())
return error("SetBestChain() : TxnCommit failed");
// Add to current best branch
pindexNew->pprev->pnext = pindexNew;
// Delete redundant memory transactions
BOOST_FOREACH(CTransaction& tx, vtx)
tx.RemoveFromMemoryPool();
}
else
{
// New best branch
if (!Reorganize(txdb, pindexNew))
{
txdb.TxnAbort();
InvalidChainFound(pindexNew);
return error("SetBestChain() : Reorganize failed");
}
}
// Update best block in wallet (so we can detect restored wallets)
if (!IsInitialBlockDownload())
{
const CBlockLocator locator(pindexNew);
::SetBestChain(locator);
}
// New best block
hashBestChain = hash;
pindexBest = pindexNew;
nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexNew->bnChainWork;
nTimeBestReceived = GetTime();
nTransactionsUpdated++;
printf("SetBestChain: new best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
return true;
}
bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
{
// Check for duplicate
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str());
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);
if (!pindexNew)
return error("AddToBlockIndex() : new CBlockIndex failed");
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
if (miPrev != mapBlockIndex.end())
{
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
}
pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
CTxDB txdb;
txdb.TxnBegin();
txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
if (!txdb.TxnCommit())
return false;
// New best
if (pindexNew->bnChainWork > bnBestChainWork)
if (!SetBestChain(txdb, pindexNew))
return false;
txdb.Close();
if (pindexNew == pindexBest)
{
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = vtx[0].GetHash();
}
MainFrameRepaint();
return true;
}
bool CBlock::CheckBlock() const
{
// These are checks that are independent of context
// that can be verified before saving an orphan block.
// Size limits
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
return DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount
if (!CheckProofOfWork(GetHash(), nBits))
return DoS(50, error("CheckBlock() : proof of work failed"));
// Check timestamp
if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return error("CheckBlock() : block timestamp too far in the future");
// First transaction must be coinbase, the rest must not be
if (vtx.empty() || !vtx[0].IsCoinBase())
return DoS(100, error("CheckBlock() : first tx is not coinbase"));
for (int i = 1; i < vtx.size(); i++)
if (vtx[i].IsCoinBase())
return DoS(100, error("CheckBlock() : more than one coinbase"));
// Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.CheckTransaction())
return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
// This code should be removed when a compatibility-breaking block chain split has passed.
// Compatibility check for old clients that counted sigops differently:
int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx)
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
nSigOps += txin.scriptSig.GetSigOpCount();
}
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
nSigOps += txout.scriptPubKey.GetSigOpCount();
}
}
if (nSigOps > MAX_BLOCK_SIGOPS)
return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkleroot
if (hashMerkleRoot != BuildMerkleTree())
return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
return true;
}
bool CBlock::AcceptBlock()
{
// Check for duplicate
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
return error("AcceptBlock() : block already in mapBlockIndex");
// Get prev block index
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
if (mi == mapBlockIndex.end())
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 DoS(100, error("AcceptBlock() : incorrect proof of work"));
// Check timestamp against prev
if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
return error("AcceptBlock() : block's timestamp is too early");
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.IsFinal(nHeight, GetBlockTime()))
return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
// Check that the block chain matches the known block chain up to a checkpoint
if (!Checkpoints::CheckBlock(nHeight, hash))
return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
// Write block to history file
if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
return error("AcceptBlock() : out of disk space");
unsigned int nFile = -1;
unsigned int nBlockPos = 0;
if (!WriteToDisk(nFile, nBlockPos))
return error("AcceptBlock() : WriteToDisk failed");
if (!AddToBlockIndex(nFile, nBlockPos))
return error("AcceptBlock() : AddToBlockIndex failed");
// Relay inventory, but don't relay old inventory during initial block download
if (hashBestChain == hash)
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 140700))
pnode->PushInventory(CInv(MSG_BLOCK, hash));
return true;
}
bool ProcessBlock(CNode* pfrom, CBlock* pblock)
{
// Check for duplicate
uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash))
return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,20).c_str());
if (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str());
// Preliminary checks
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;
+ int64_t 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))
{
printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str());
CBlock* pblock2 = new CBlock(*pblock);
mapOrphanBlocks.insert(make_pair(hash, pblock2));
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
// Ask this guy to fill in what we're missing
if (pfrom)
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
return true;
}
// Store to disk
if (!pblock->AcceptBlock())
return error("ProcessBlock() : AcceptBlock FAILED");
// Recursively process any orphan blocks that depended on this one
vector<uint256> vWorkQueue;
vWorkQueue.push_back(hash);
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);
++mi)
{
CBlock* pblockOrphan = (*mi).second;
if (pblockOrphan->AcceptBlock())
vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash());
delete pblockOrphan;
}
mapOrphanBlocksByPrev.erase(hashPrev);
}
printf("ProcessBlock: ACCEPTED\n");
return true;
}
-bool CheckDiskSpace(uint64 nAdditionalBytes)
+bool CheckDiskSpace(uint64_t nAdditionalBytes)
{
- uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
+ uint64_t nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
// Check for 15MB because database could create another 10MB log file at any time
- if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes)
+ if (nFreeBytesAvailable < (uint64_t)15000000 + nAdditionalBytes)
{
fShutdown = true;
string strMessage = _("Warning: Disk space is low ");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
CreateThread(Shutdown, NULL);
return false;
}
return true;
}
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode)
{
if (nFile == -1)
return NULL;
FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
if (!file)
return NULL;
if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
{
if (fseek(file, nBlockPos, SEEK_SET) != 0)
{
fclose(file);
return NULL;
}
}
return file;
}
static unsigned int nCurrentBlockFile = 1;
FILE* AppendBlockFile(unsigned int& nFileRet)
{
nFileRet = 0;
loop
{
FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab");
if (!file)
return NULL;
if (fseek(file, 0, SEEK_END) != 0)
return NULL;
// FAT32 filesize max 4GB, fseek and ftell max 2GB, so we must stay under 2GB
if (ftell(file) < 0x7F000000 - MAX_SIZE)
{
nFileRet = nCurrentBlockFile;
return file;
}
fclose(file);
nCurrentBlockFile++;
}
}
bool LoadBlockIndex(bool fAllowNew)
{
if (fTestNet)
{
hashGenesisBlock = uint256("0x00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28);
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda;
}
//
// Load block index
//
CTxDB txdb("cr");
if (!txdb.LoadBlockIndex())
return false;
txdb.Close();
//
// Init with genesis block
//
if (mapBlockIndex.empty())
{
if (!fAllowNew)
return false;
// Genesis Block:
// CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
// CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
// CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
// CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
// vMerkleTree: 4a5e1e
// Genesis block
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
CTransaction txNew;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vout[0].nValue = 50 * COIN;
txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
CBlock block;
block.vtx.push_back(txNew);
block.hashPrevBlock = 0;
block.hashMerkleRoot = block.BuildMerkleTree();
block.nVersion = 1;
block.nTime = 1231006505;
block.nBits = 0x1d00ffff;
block.nNonce = 2083236893;
if (fTestNet)
{
block.nTime = 1296688602;
block.nBits = 0x1d07fff8;
block.nNonce = 384568319;
}
//// debug print
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"));
block.print();
assert(block.GetHash() == hashGenesisBlock);
// Start new block file
unsigned int nFile;
unsigned int nBlockPos;
if (!block.WriteToDisk(nFile, nBlockPos))
return error("LoadBlockIndex() : writing genesis block to disk failed");
if (!block.AddToBlockIndex(nFile, nBlockPos))
return error("LoadBlockIndex() : genesis block not accepted");
}
return true;
}
void PrintBlockTree()
{
// precompute tree structure
map<CBlockIndex*, vector<CBlockIndex*> > mapNext;
for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
{
CBlockIndex* pindex = (*mi).second;
mapNext[pindex->pprev].push_back(pindex);
// test
//while (rand() % 3 == 0)
// mapNext[pindex->pprev].push_back(pindex);
}
vector<pair<int, CBlockIndex*> > vStack;
vStack.push_back(make_pair(0, pindexGenesisBlock));
int nPrevCol = 0;
while (!vStack.empty())
{
int nCol = vStack.back().first;
CBlockIndex* pindex = vStack.back().second;
vStack.pop_back();
// print split or gap
if (nCol > nPrevCol)
{
for (int i = 0; i < nCol-1; i++)
printf("| ");
printf("|\\\n");
}
else if (nCol < nPrevCol)
{
for (int i = 0; i < nCol; i++)
printf("| ");
printf("|\n");
}
nPrevCol = nCol;
// print columns
for (int i = 0; i < nCol; i++)
printf("| ");
// print item
CBlock block;
block.ReadFromDisk(pindex);
printf("%d (%u,%u) %s %s tx %d",
pindex->nHeight,
pindex->nFile,
pindex->nBlockPos,
block.GetHash().ToString().substr(0,20).c_str(),
DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
block.vtx.size());
PrintWallets(block);
// put the main timechain first
vector<CBlockIndex*>& vNext = mapNext[pindex];
for (int i = 0; i < vNext.size(); i++)
{
if (vNext[i]->pnext)
{
swap(vNext[0], vNext[i]);
break;
}
}
// iterate children
for (int i = 0; i < vNext.size(); i++)
vStack.push_back(make_pair(nCol+i, vNext[i]));
}
}
//////////////////////////////////////////////////////////////////////////////
//
// CAlert
//
map<uint256, CAlert> mapAlerts;
CCriticalSection cs_mapAlerts;
string GetWarnings(string strFor)
{
int nPriority = 0;
string strStatusBar;
string strRPC;
if (GetBoolArg("-testsafemode"))
strRPC = "test";
// Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "")
{
nPriority = 1000;
strStatusBar = strMiscWarning;
}
// Longer invalid proof-of-work chain
if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
{
nPriority = 2000;
strStatusBar = strRPC = "WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.";
}
// Alerts
CRITICAL_BLOCK(cs_mapAlerts)
{
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
{
const CAlert& alert = item.second;
if (alert.AppliesToMe() && alert.nPriority > nPriority)
{
nPriority = alert.nPriority;
strStatusBar = alert.strStatusBar;
}
}
}
if (strFor == "statusbar")
return strStatusBar;
else if (strFor == "rpc")
return strRPC;
assert(!"GetWarnings() : invalid parameter");
return "error";
}
bool CAlert::ProcessAlert()
{
if (!CheckSignature())
return false;
if (!IsInEffect())
return false;
CRITICAL_BLOCK(cs_mapAlerts)
{
// Cancel previous alerts
for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
{
const CAlert& alert = (*mi).second;
if (Cancels(alert))
{
printf("cancelling alert %d\n", alert.nID);
mapAlerts.erase(mi++);
}
else if (!alert.IsInEffect())
{
printf("expiring alert %d\n", alert.nID);
mapAlerts.erase(mi++);
}
else
mi++;
}
// Check if this alert has been cancelled
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
{
const CAlert& alert = item.second;
if (alert.Cancels(*this))
{
printf("alert already cancelled by %d\n", alert.nID);
return false;
}
}
// Add to mapAlerts
mapAlerts.insert(make_pair(GetHash(), *this));
}
printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
MainFrameRepaint();
return true;
}
//////////////////////////////////////////////////////////////////////////////
//
// Messages
//
bool static AlreadyHave(CTxDB& txdb, const CInv& inv)
{
switch (inv.type)
{
case MSG_TX: return mapTransactions.count(inv.hash) || mapOrphanTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
}
// Don't know what it is, just say we already got one
return true;
}
// The message start string is designed to be unlikely to occur in normal data.
// The characters are rarely used upper ascii, not valid as UTF-8, and produce
// a large 4-byte int at any alignment.
unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
static map<unsigned int, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon();
if (fDebug) {
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
}
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
printf("dropmessagestest DROPPING RECV MESSAGE\n");
return true;
}
if (strCommand == "version")
{
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
pfrom->Misbehaving(1);
return false;
}
- int64 nTime;
+ int64_t nTime;
CAddress addrMe;
CAddress addrFrom;
- uint64 nNonce = 1;
+ uint64_t nNonce = 1;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
if (pfrom->nVersion == 10300)
pfrom->nVersion = 300;
if (pfrom->nVersion >= 106 && !vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (pfrom->nVersion >= 106 && !vRecv.empty())
vRecv >> pfrom->strSubVer;
if (pfrom->nVersion >= 209 && !vRecv.empty())
vRecv >> pfrom->nStartingHeight;
if (pfrom->nVersion == 0)
return false;
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
{
printf("connected to self at %s, disconnecting\n", pfrom->addr.ToString().c_str());
pfrom->fDisconnect = true;
return true;
}
// Be shy and don't send version until we hear
if (pfrom->fInbound)
pfrom->PushVersion();
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
AddTimeData(pfrom->addr.ip, nTime);
// Change version
if (pfrom->nVersion >= 209)
pfrom->PushMessage("verack");
pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
if (pfrom->nVersion < 209)
pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
if (!pfrom->fInbound)
{
// Advertise our address
if (addrLocalHost.IsRoutable() && !fUseProxy)
{
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
pfrom->PushAddress(addr);
}
// Get recent addresses
if (pfrom->nVersion >= 31402 || mapAddresses.size() < 1000)
{
pfrom->PushMessage("getaddr");
pfrom->fGetAddr = true;
}
}
// Ask the first connected node for block updates
static int nAskedForBlocks = 0;
if (!pfrom->fClient &&
(pfrom->nVersion < 32000 || pfrom->nVersion >= 32400) &&
(nAskedForBlocks < 1 || vNodes.size() <= 1))
{
nAskedForBlocks++;
pfrom->PushGetBlocks(pindexBest, uint256(0));
}
// Relay alerts
CRITICAL_BLOCK(cs_mapAlerts)
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
item.second.RelayTo(pfrom);
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;
}
else if (strCommand == "verack")
{
pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
}
else if (strCommand == "addr")
{
vector<CAddress> vAddr;
vRecv >> vAddr;
// Don't want addr from older versions unless seeding
if (pfrom->nVersion < 209)
return true;
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;
addrDB.TxnBegin();
- int64 nNow = GetAdjustedTime();
- int64 nSince = nNow - 10 * 60;
+ int64_t nNow = GetAdjustedTime();
+ int64_t nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr)
{
if (fShutdown)
return true;
// ignore IPv6 for now, since it isn't implemented anyway
if (!addr.IsIPv4())
continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
AddAddress(addr, 2 * 60 * 60, &addrDB);
pfrom->AddAddressKnown(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
// Relay to a limited number of other nodes
CRITICAL_BLOCK(cs_vNodes)
{
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the setAddrKnowns of the chosen nodes prevent repeats
static uint256 hashSalt;
if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
- uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
+ uint256 hashRand = hashSalt ^ (((int64_t)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->nVersion < 31402)
continue;
unsigned int nPointer;
memcpy(&nPointer, &pnode, sizeof(nPointer));
uint256 hashKey = hashRand ^ nPointer;
hashKey = Hash(BEGIN(hashKey), END(hashKey));
mapMix.insert(make_pair(hashKey, pnode));
}
int nRelayNodes = 2;
for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
((*mi).second)->PushAddress(addr);
}
}
}
addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
}
else if (strCommand == "inv")
{
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)
{
if (fShutdown)
return true;
pfrom->AddInventoryKnown(inv);
bool fAlreadyHave = AlreadyHave(txdb, inv);
if (fDebug)
printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
if (!fAlreadyHave)
pfrom->AskFor(inv);
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
// Track requests for our stuff
Inventory(inv.hash);
}
}
else if (strCommand == "getdata")
{
vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > 50000)
{
pfrom->Misbehaving(20);
return error("message getdata size() = %d", vInv.size());
}
BOOST_FOREACH(const CInv& inv, vInv)
{
if (fShutdown)
return true;
printf("received getdata for: %s\n", inv.ToString().c_str());
if (inv.type == MSG_BLOCK)
{
// Send block from disk
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);
if (mi != mapBlockIndex.end())
{
CBlock block;
block.ReadFromDisk((*mi).second);
pfrom->PushMessage("block", block);
// Trigger them to send a getblocks request for the next batch of inventory
if (inv.hash == pfrom->hashContinue)
{
// Bypass PushInventory, this must send even if redundant,
// and we want it right after the last block so they don't
// wait for other stuff first.
vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
pfrom->PushMessage("inv", vInv);
pfrom->hashContinue = 0;
}
}
}
else if (inv.IsKnownType())
{
// Send stream from relay memory
CRITICAL_BLOCK(cs_mapRelay)
{
map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
if (mi != mapRelay.end())
pfrom->PushMessage(inv.GetCommand(), (*mi).second);
}
}
// Track requests for our stuff
Inventory(inv.hash);
}
}
else if (strCommand == "getblocks")
{
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
// Find the last block the caller has in the main chain
CBlockIndex* pindex = locator.GetBlockIndex();
// Send the rest of the chain
if (pindex)
pindex = pindex->pnext;
int nLimit = 500 + locator.GetDistanceBack();
unsigned int nBytes = 0;
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
if (pindex->GetBlockHash() == hashStop)
{
printf(" getblocks stopping at %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
CBlock block;
block.ReadFromDisk(pindex, true);
nBytes += block.GetSerializeSize(SER_NETWORK);
if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
{
// When this block is requested, we'll send an inv that'll make them
// getblocks the next batch of inventory.
printf(" getblocks stopping at limit %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
pfrom->hashContinue = pindex->GetBlockHash();
break;
}
}
}
else if (strCommand == "getheaders")
{
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
CBlockIndex* pindex = NULL;
if (locator.IsNull())
{
// If locator is null, return the hashStop block
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashStop);
if (mi == mapBlockIndex.end())
return true;
pindex = (*mi).second;
}
else
{
// Find the last block the caller has in the main chain
pindex = locator.GetBlockIndex();
if (pindex)
pindex = pindex->pnext;
}
vector<CBlock> vHeaders;
int nLimit = 2000 + locator.GetDistanceBack();
printf("getheaders %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
break;
}
pfrom->PushMessage("headers", vHeaders);
}
else if (strCommand == "tx")
{
vector<uint256> vWorkQueue;
CDataStream vMsg(vRecv);
CTransaction tx;
vRecv >> tx;
CInv inv(MSG_TX, tx.GetHash());
pfrom->AddInventoryKnown(inv);
bool fMissingInputs = false;
if (tx.AcceptToMemoryPool(true, &fMissingInputs))
{
SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
// Recursively process any orphan transactions that depended on this one
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);
mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev);
++mi)
{
const CDataStream& vMsg = *((*mi).second);
CTransaction tx;
CDataStream(vMsg) >> tx;
CInv inv(MSG_TX, tx.GetHash());
if (tx.AcceptToMemoryPool(true))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
}
}
}
BOOST_FOREACH(uint256 hash, vWorkQueue)
EraseOrphanTx(hash);
}
else if (fMissingInputs)
{
printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
AddOrphanTx(vMsg);
}
if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
}
else if (strCommand == "block")
{
CBlock block;
vRecv >> block;
printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str());
// block.print();
CInv inv(MSG_BLOCK, block.GetHash());
pfrom->AddInventoryKnown(inv);
if (ProcessBlock(pfrom, &block))
mapAlreadyAskedFor.erase(inv);
if (block.nDoS) pfrom->Misbehaving(block.nDoS);
}
else if (strCommand == "getaddr")
{
// Nodes rebroadcast an addr every 24 hours
pfrom->vAddrToSend.clear();
- int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
+ int64_t nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
CRITICAL_BLOCK(cs_mapAddresses)
{
unsigned int nCount = 0;
BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
const CAddress& addr = item.second;
if (addr.nTime > nSince)
nCount++;
}
BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
const CAddress& addr = item.second;
if (addr.nTime > nSince && GetRand(nCount) < 2500)
pfrom->PushAddress(addr);
}
}
}
else if (strCommand == "checkorder")
{
uint256 hashReply;
vRecv >> hashReply;
if (!GetBoolArg("-allowreceivebyip"))
{
pfrom->PushMessage("reply", hashReply, (int)2, string(""));
return true;
}
CWalletTx order;
vRecv >> order;
/// we have a chance to check the order here
// Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip))
pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true);
// Send back approval of order and pubkey to use
CScript scriptPubKey;
scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
}
else if (strCommand == "reply")
{
uint256 hashReply;
vRecv >> hashReply;
CRequestTracker tracker;
CRITICAL_BLOCK(pfrom->cs_mapRequests)
{
map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
if (mi != pfrom->mapRequests.end())
{
tracker = (*mi).second;
pfrom->mapRequests.erase(mi);
}
}
if (!tracker.IsNull())
tracker.fn(tracker.param1, vRecv);
}
else if (strCommand == "ping")
{
}
else if (strCommand == "alert")
{
CAlert alert;
vRecv >> alert;
if (alert.ProcessAlert())
{
// Relay
pfrom->setKnown.insert(alert.GetHash());
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
alert.RelayTo(pnode);
}
}
else
{
// Ignore unknown commands for extensibility
}
// Update the last seen time for this node's address
if (pfrom->fNetworkNode)
if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")
AddressCurrentlyConnected(pfrom->addr);
return true;
}
bool ProcessMessages(CNode* pfrom)
{
CDataStream& vRecv = pfrom->vRecv;
if (vRecv.empty())
return true;
//if (fDebug)
// printf("ProcessMessages(%u bytes)\n", vRecv.size());
//
// Message format
// (4) message start
// (12) command
// (4) size
// (4) checksum
// (x) data
//
loop
{
// Scan for message start
CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
if (vRecv.end() - pstart < nHeaderSize)
{
if (vRecv.size() > nHeaderSize)
{
printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
}
break;
}
if (pstart - vRecv.begin() > 0)
printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin());
vRecv.erase(vRecv.begin(), pstart);
// Read header
vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
CMessageHeader hdr;
vRecv >> hdr;
if (!hdr.IsValid())
{
printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
continue;
}
string strCommand = hdr.GetCommand();
// Message size
unsigned int nMessageSize = hdr.nMessageSize;
if (nMessageSize > MAX_SIZE)
{
printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
continue;
}
if (nMessageSize > vRecv.size())
{
// Rewind and wait for rest of message
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
break;
}
// Checksum
if (vRecv.GetVersion() >= 209)
{
uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum)
{
printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
continue;
}
}
// Copy message to its own buffer
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
vRecv.ignore(nMessageSize);
// Process message
bool fRet = false;
try
{
CRITICAL_BLOCK(cs_main)
fRet = ProcessMessage(pfrom, strCommand, vMsg);
if (fShutdown)
return true;
}
catch (std::ios_base::failure& e)
{
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from underlength message on vRecv
printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
}
else if (strstr(e.what(), "size too large"))
{
// Allow exceptions from overlong size
printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
}
else
{
PrintExceptionContinue(&e, "ProcessMessage()");
}
}
catch (std::exception& e) {
PrintExceptionContinue(&e, "ProcessMessage()");
} catch (...) {
PrintExceptionContinue(NULL, "ProcessMessage()");
}
if (!fRet)
printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
}
vRecv.Compact();
return true;
}
bool SendMessages(CNode* pto, bool fSendTrickle)
{
CRITICAL_BLOCK(cs_main)
{
// Don't send anything until we get their version message
if (pto->nVersion == 0)
return true;
// Keep-alive ping
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
pto->PushMessage("ping");
// Resend wallet transactions that haven't gotten in a block yet
ResendWalletTransactions();
// Address refresh broadcast
- static int64 nLastRebroadcast;
+ static int64_t nLastRebroadcast;
if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
{
nLastRebroadcast = GetTime();
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
{
// Periodically clear setAddrKnown to allow refresh broadcasts
pnode->setAddrKnown.clear();
// Rebroadcast our address
if (addrLocalHost.IsRoutable() && !fUseProxy)
{
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
pnode->PushAddress(addr);
}
}
}
}
// Clear out old addresses periodically so it's not too much work at once
- static int64 nLastClear;
+ static int64_t nLastClear;
if (nLastClear == 0)
nLastClear = GetTime();
if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3)
{
nLastClear = GetTime();
CRITICAL_BLOCK(cs_mapAddresses)
{
CAddrDB addrdb;
- int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
+ int64_t nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.begin();
mi != mapAddresses.end();)
{
const CAddress& addr = (*mi).second;
if (addr.nTime < nSince)
{
if (mapAddresses.size() < 1000 || GetTime() > nLastClear + 20)
break;
addrdb.EraseAddress(addr);
mapAddresses.erase(mi++);
}
else
mi++;
}
}
}
//
// Message: addr
//
if (fSendTrickle)
{
vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());
BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
{
// returns true if wasn't already contained in the set
if (pto->setAddrKnown.insert(addr).second)
{
vAddr.push_back(addr);
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
pto->PushMessage("addr", vAddr);
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
pto->PushMessage("addr", vAddr);
}
//
// Message: inventory
//
vector<CInv> vInv;
vector<CInv> vInvWait;
CRITICAL_BLOCK(pto->cs_inventory)
{
vInv.reserve(pto->vInventoryToSend.size());
vInvWait.reserve(pto->vInventoryToSend.size());
BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
{
if (pto->setInventoryKnown.count(inv))
continue;
// trickle out tx inv to protect privacy
if (inv.type == MSG_TX && !fSendTrickle)
{
// 1/4 of tx invs blast to all immediately
static uint256 hashSalt;
if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
uint256 hashRand = inv.hash ^ hashSalt;
hashRand = Hash(BEGIN(hashRand), END(hashRand));
bool fTrickleWait = ((hashRand & 3) != 0);
// always trickle our own transactions
if (!fTrickleWait)
{
CWalletTx wtx;
if (GetTransaction(inv.hash, wtx))
if (wtx.fFromMe)
fTrickleWait = true;
}
if (fTrickleWait)
{
vInvWait.push_back(inv);
continue;
}
}
// returns true if wasn't already contained in the set
if (pto->setInventoryKnown.insert(inv).second)
{
vInv.push_back(inv);
if (vInv.size() >= 1000)
{
pto->PushMessage("inv", vInv);
vInv.clear();
}
}
}
pto->vInventoryToSend = vInvWait;
}
if (!vInv.empty())
pto->PushMessage("inv", vInv);
//
// Message: getdata
//
vector<CInv> vGetData;
- int64 nNow = GetTime() * 1000000;
+ int64_t nNow = GetTime() * 1000000;
CTxDB txdb("r");
while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
{
const CInv& inv = (*pto->mapAskFor.begin()).second;
if (!AlreadyHave(txdb, inv))
{
printf("sending getdata: %s\n", inv.ToString().c_str());
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
pto->PushMessage("getdata", vGetData);
vGetData.clear();
}
}
mapAlreadyAskedFor[inv] = nNow;
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
pto->PushMessage("getdata", vGetData);
}
return true;
}
//////////////////////////////////////////////////////////////////////////////
//
// BitcoinMiner
//
int static FormatHashBlocks(void* pbuffer, unsigned int len)
{
unsigned char* pdata = (unsigned char*)pbuffer;
unsigned int blocks = 1 + ((len + 8) / 64);
unsigned char* pend = pdata + 64 * blocks;
memset(pdata + len, 0, 64 * blocks - len);
pdata[len] = 0x80;
unsigned int bits = len * 8;
pend[-1] = (bits >> 0) & 0xff;
pend[-2] = (bits >> 8) & 0xff;
pend[-3] = (bits >> 16) & 0xff;
pend[-4] = (bits >> 24) & 0xff;
return blocks;
}
static const unsigned int pSHA256InitState[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
void SHA256Transform(void* pstate, void* pinput, const void* pinit)
{
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];
}
//
// ScanHash scans nonces looking for a hash with at least some zero bits.
// It operates on big endian data. Caller does the byte reversing.
// All input buffers are 16-byte aligned. nNonce is usually preserved
// between calls, but periodically or if nNonce is 0xffff0000 or above,
// the block is rebuilt and nNonce starts over at zero.
//
unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
{
unsigned int& nNonce = *(unsigned int*)(pdata + 12);
for (;;)
{
// Crypto++ SHA-256
// Hash pdata using pmidstate as the starting state into
// preformatted buffer phash1, then hash phash1 into phash
nNonce++;
SHA256Transform(phash1, pdata, pmidstate);
SHA256Transform(phash, phash1, pSHA256InitState);
// Return the nonce if the hash has at least some zero bits,
// caller will check if it has enough to reach the target
if (((unsigned short*)phash)[14] == 0)
return nNonce;
// If nothing found after trying for a while, return -1
if ((nNonce & 0xffff) == 0)
{
nHashesDone = 0xffff+1;
return -1;
}
}
}
// Some explaining would be appreciated
class COrphan
{
public:
CTransaction* ptx;
set<uint256> setDependsOn;
double dPriority;
COrphan(CTransaction* ptxIn)
{
ptx = ptxIn;
dPriority = 0;
}
void print() const
{
printf("COrphan(hash=%s, dPriority=%.1f)\n", ptx->GetHash().ToString().substr(0,10).c_str(), dPriority);
BOOST_FOREACH(uint256 hash, setDependsOn)
printf(" setDependsOn %s\n", hash.ToString().substr(0,10).c_str());
}
};
CBlock* CreateNewBlock(CReserveKey& reservekey)
{
CBlockIndex* pindexPrev = pindexBest;
// Create new block
auto_ptr<CBlock> pblock(new CBlock());
if (!pblock.get())
return NULL;
// Create coinbase tx
CTransaction txNew;
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1);
txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
// Add our coinbase tx as first transaction
pblock->vtx.push_back(txNew);
// Collect memory pool transactions into the block
- int64 nFees = 0;
+ int64_t nFees = 0;
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapTransactions)
{
CTxDB txdb("r");
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
map<uint256, vector<COrphan*> > mapDependers;
multimap<double, CTransaction*> mapPriority;
for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi)
{
CTransaction& tx = (*mi).second;
if (tx.IsCoinBase() || !tx.IsFinal())
continue;
COrphan* porphan = NULL;
double dPriority = 0;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
// Read prev transaction
CTransaction txPrev;
CTxIndex txindex;
if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
{
// Has to wait for dependencies
if (!porphan)
{
// Use list for automatic deletion
vOrphan.push_back(COrphan(&tx));
porphan = &vOrphan.back();
}
mapDependers[txin.prevout.hash].push_back(porphan);
porphan->setDependsOn.insert(txin.prevout.hash);
continue;
}
- int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
+ int64_t nValueIn = txPrev.vout[txin.prevout.n].nValue;
// Read block header
int nConf = txindex.GetDepthInMainChain();
dPriority += (double)nValueIn * nConf;
if (fDebug && GetBoolArg("-printpriority"))
printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
}
// Priority is sum(valuein * age) / txsize
dPriority /= ::GetSerializeSize(tx, SER_NETWORK);
if (porphan)
porphan->dPriority = dPriority;
else
mapPriority.insert(make_pair(-dPriority, &(*mi).second));
if (fDebug && GetBoolArg("-printpriority"))
{
printf("priority %-20.1f %s\n%s", dPriority, tx.GetHash().ToString().substr(0,10).c_str(), tx.ToString().c_str());
if (porphan)
porphan->print();
printf("\n");
}
}
// Collect transactions into block
map<uint256, CTxIndex> mapTestPool;
- uint64 nBlockSize = 1000;
+ uint64_t nBlockSize = 1000;
int nBlockSigOps = 100;
while (!mapPriority.empty())
{
// Take highest priority transaction off priority queue
double dPriority = -(*mapPriority.begin()).first;
CTransaction& tx = *(*mapPriority.begin()).second;
mapPriority.erase(mapPriority.begin());
// Size limits
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
continue;
// Transaction fee required depends on block size
bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority));
- int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK);
+ int64_t nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK);
// Connecting shouldn't fail due to dependency on other memory pool transactions
// because we're already processing them in order of dependency
map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs))
continue;
int nTxSigOps = 0;
if (!tx.ConnectInputs(mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nTxSigOps, nMinFee))
continue;
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
swap(mapTestPool, mapTestPoolTmp);
// Added
pblock->vtx.push_back(tx);
nBlockSize += nTxSize;
nBlockSigOps += nTxSigOps;
// Add transactions that depend on this one to the priority queue
uint256 hash = tx.GetHash();
if (mapDependers.count(hash))
{
BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
{
if (!porphan->setDependsOn.empty())
{
porphan->setDependsOn.erase(hash);
if (porphan->setDependsOn.empty())
mapPriority.insert(make_pair(-porphan->dPriority, porphan->ptx));
}
}
}
}
}
pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
pblock->nBits = GetNextWorkRequired(pindexPrev);
pblock->nNonce = 0;
return pblock.release();
}
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
// Update nExtraNonce
static uint256 hashPrevBlock;
if (hashPrevBlock != pblock->hashPrevBlock)
{
nExtraNonce = 0;
hashPrevBlock = pblock->hashPrevBlock;
}
++nExtraNonce;
pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nTime << CBigNum(nExtraNonce);
// Put "OP_EVAL" in the coinbase so everybody can tell when
// a majority of miners support it
const char* pOpEvalName = GetOpName(OP_EVAL);
pblock->vtx[0].vin[0].scriptSig += CScript() << std::vector<unsigned char>(pOpEvalName, pOpEvalName+strlen(pOpEvalName));
assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1)
{
//
// Prebuild hash buffers
//
struct
{
struct unnamed2
{
int nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
}
block;
unsigned char pchPadding0[64];
uint256 hash1;
unsigned char pchPadding1[64];
}
tmp;
memset(&tmp, 0, sizeof(tmp));
tmp.block.nVersion = pblock->nVersion;
tmp.block.hashPrevBlock = pblock->hashPrevBlock;
tmp.block.hashMerkleRoot = pblock->hashMerkleRoot;
tmp.block.nTime = pblock->nTime;
tmp.block.nBits = pblock->nBits;
tmp.block.nNonce = pblock->nNonce;
FormatHashBlocks(&tmp.block, sizeof(tmp.block));
FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
// Byte swap all the input buffer
for (int i = 0; i < sizeof(tmp)/4; i++)
((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
// Precalc the first half of the first hash, which stays constant
SHA256Transform(pmidstate, &tmp.block, pSHA256InitState);
memcpy(pdata, &tmp.block, 128);
memcpy(phash1, &tmp.hash1, 64);
}
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
{
uint256 hash = pblock->GetHash();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
if (hash > hashTarget)
return false;
//// debug print
printf("BitcoinMiner:\n");
printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
pblock->print();
printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
// Found a solution
CRITICAL_BLOCK(cs_main)
{
if (pblock->hashPrevBlock != hashBestChain)
return error("BitcoinMiner : generated block is stale");
// Remove key from key pool
reservekey.KeepKey();
// Track how many getdata requests this block gets
CRITICAL_BLOCK(wallet.cs_wallet)
wallet.mapRequestCount[pblock->GetHash()] = 0;
// Process this block the same as if we had received it from another node
if (!ProcessBlock(NULL, pblock))
return error("BitcoinMiner : ProcessBlock, block not accepted");
}
return true;
}
void static ThreadBitcoinMiner(void* parg);
void static BitcoinMiner(CWallet *pwallet)
{
printf("BitcoinMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
// Each thread has its own key and counter
CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
while (fGenerateBitcoins)
{
if (AffinityBugWorkaround(ThreadBitcoinMiner))
return;
if (fShutdown)
return;
while (vNodes.empty() || IsInitialBlockDownload())
{
Sleep(1000);
if (fShutdown)
return;
if (!fGenerateBitcoins)
return;
}
//
// Create new block
//
unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
CBlockIndex* pindexPrev = pindexBest;
auto_ptr<CBlock> pblock(CreateNewBlock(reservekey));
if (!pblock.get())
return;
IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce);
printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());
//
// Prebuild hash buffers
//
char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf);
char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf);
char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf);
FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1);
unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
//
// Search
//
- int64 nStart = GetTime();
+ int64_t nStart = GetTime();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
uint256 hashbuf[2];
uint256& hash = *alignup<16>(hashbuf);
loop
{
unsigned int nHashesDone = 0;
unsigned int nNonceFound;
// Crypto++ SHA-256
nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1,
(char*)&hash, nHashesDone);
// Check if something found
if (nNonceFound != -1)
{
for (int i = 0; i < sizeof(hash)/4; i++)
((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
if (hash <= hashTarget)
{
// Found a solution
pblock->nNonce = ByteReverse(nNonceFound);
assert(hash == pblock->GetHash());
SetThreadPriority(THREAD_PRIORITY_NORMAL);
CheckWork(pblock.get(), *pwalletMain, reservekey);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
break;
}
}
// Meter hashes/sec
- static int64 nHashCounter;
+ static int64_t nHashCounter;
if (nHPSTimerStart == 0)
{
nHPSTimerStart = GetTimeMillis();
nHashCounter = 0;
}
else
nHashCounter += nHashesDone;
if (GetTimeMillis() - nHPSTimerStart > 4000)
{
static CCriticalSection cs;
CRITICAL_BLOCK(cs)
{
if (GetTimeMillis() - nHPSTimerStart > 4000)
{
dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
nHPSTimerStart = GetTimeMillis();
nHashCounter = 0;
string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0);
UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
- static int64 nLogTime;
+ static int64_t nLogTime;
if (GetTime() - nLogTime > 30 * 60)
{
nLogTime = GetTime();
printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
}
}
}
}
// Check for stop or if block needs to be rebuilt
if (fShutdown)
return;
if (!fGenerateBitcoins)
return;
if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
return;
if (vNodes.empty())
break;
if (nBlockNonce >= 0xffff0000)
break;
if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
if (pindexPrev != pindexBest)
break;
// Update nTime every few seconds
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
nBlockTime = ByteReverse(pblock->nTime);
}
}
}
void static ThreadBitcoinMiner(void* parg)
{
CWallet* pwallet = (CWallet*)parg;
try
{
vnThreadsRunning[3]++;
BitcoinMiner(pwallet);
vnThreadsRunning[3]--;
}
catch (std::exception& e) {
vnThreadsRunning[3]--;
PrintException(&e, "ThreadBitcoinMiner()");
} catch (...) {
vnThreadsRunning[3]--;
PrintException(NULL, "ThreadBitcoinMiner()");
}
UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
nHPSTimerStart = 0;
if (vnThreadsRunning[3] == 0)
dHashesPerSec = 0;
printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
}
void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
{
if (fGenerateBitcoins != fGenerate)
{
fGenerateBitcoins = fGenerate;
WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
MainFrameRepaint();
}
if (fGenerateBitcoins)
{
int nProcessors = boost::thread::hardware_concurrency();
printf("%d processors\n", nProcessors);
if (nProcessors < 1)
nProcessors = 1;
if (fLimitProcessors && nProcessors > nLimitProcessors)
nProcessors = nLimitProcessors;
int nAddThreads = nProcessors - vnThreadsRunning[3];
printf("Starting %d BitcoinMiner threads\n", nAddThreads);
for (int i = 0; i < nAddThreads; i++)
{
if (!CreateThread(ThreadBitcoinMiner, pwallet))
printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
Sleep(10);
}
}
}
diff --git a/src/main.h b/src/main.h
index d613d284b6..7b18d22b69 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1,1567 +1,1569 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_MAIN_H
#define BITCOIN_MAIN_H
+#include <stdint.h>
+
#include "bignum.h"
#include "net.h"
#include "key.h"
#include "script.h"
#include "db.h"
#include <list>
class CBlock;
class CBlockIndex;
class CWalletTx;
class CWallet;
class CKeyItem;
class CReserveKey;
class CWalletDB;
class CAddress;
class CInv;
class CRequestTracker;
class CNode;
class CBlockIndex;
static const int CLIENT_VERSION = 59900;
static const bool VERSION_IS_BETA = true;
extern const std::string CLIENT_NAME;
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 MIN_RELAY_TX_FEE = 10000;
-static const int64 MAX_MONEY = 21000000 * COIN;
-inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
+static const int64_t COIN = 100000000;
+static const int64_t CENT = 1000000;
+static const int64_t MIN_TX_FEE = 50000;
+static const int64_t MIN_RELAY_TX_FEE = 10000;
+static const int64_t MAX_MONEY = 21000000 * COIN;
+inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
static const int COINBASE_MATURITY = 100;
// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
static const int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
#ifdef USE_UPNP
static const int fHaveUPnP = true;
#else
static const int fHaveUPnP = false;
#endif
extern CCriticalSection cs_main;
extern std::map<uint256, CBlockIndex*> mapBlockIndex;
extern uint256 hashGenesisBlock;
extern CBlockIndex* pindexGenesisBlock;
extern int nBestHeight;
extern CBigNum bnBestChainWork;
extern CBigNum bnBestInvalidWork;
extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated;
extern double dHashesPerSec;
-extern int64 nHPSTimerStart;
-extern int64 nTimeBestReceived;
+extern int64_t nHPSTimerStart;
+extern int64_t nTimeBestReceived;
extern CCriticalSection cs_setpwalletRegistered;
extern std::set<CWallet*> setpwalletRegistered;
// Settings
extern int fGenerateBitcoins;
-extern int64 nTransactionFee;
+extern int64_t nTransactionFee;
extern int fLimitProcessors;
extern int nLimitProcessors;
extern int fMinimizeToTray;
extern int fMinimizeOnClose;
extern int fUseUPnP;
class CReserveKey;
class CTxDB;
class CTxIndex;
void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn);
bool ProcessBlock(CNode* pfrom, CBlock* pblock);
-bool CheckDiskSpace(uint64 nAdditionalBytes=0);
+bool CheckDiskSpace(uint64_t nAdditionalBytes=0);
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
FILE* AppendBlockFile(unsigned int& nFileRet);
bool LoadBlockIndex(bool fAllowNew=true);
void PrintBlockTree();
bool ProcessMessages(CNode* pfrom);
bool SendMessages(CNode* pto, bool fSendTrickle);
void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
CBlock* CreateNewBlock(CReserveKey& reservekey);
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
-unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
+unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime);
int GetNumBlocksOfPeers();
bool IsInitialBlockDownload();
std::string GetWarnings(std::string strFor);
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
template<typename T>
bool WriteSetting(const std::string& strKey, const T& value)
{
bool fOk = false;
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
{
std::string strWalletFile;
if (!GetWalletFile(pwallet, strWalletFile))
continue;
fOk |= CWalletDB(strWalletFile).WriteSetting(strKey, value);
}
return fOk;
}
class CDiskTxPos
{
public:
unsigned int nFile;
unsigned int nBlockPos;
unsigned int nTxPos;
CDiskTxPos()
{
SetNull();
}
CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn)
{
nFile = nFileIn;
nBlockPos = nBlockPosIn;
nTxPos = nTxPosIn;
}
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; }
bool IsNull() const { return (nFile == -1); }
friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b)
{
return (a.nFile == b.nFile &&
a.nBlockPos == b.nBlockPos &&
a.nTxPos == b.nTxPos);
}
friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b)
{
return !(a == b);
}
std::string ToString() const
{
if (IsNull())
return strprintf("null");
else
return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);
}
void print() const
{
printf("%s", ToString().c_str());
}
};
class CInPoint
{
public:
CTransaction* ptx;
unsigned int n;
CInPoint() { SetNull(); }
CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
void SetNull() { ptx = NULL; n = -1; }
bool IsNull() const { return (ptx == NULL && n == -1); }
};
class COutPoint
{
public:
uint256 hash;
unsigned int n;
COutPoint() { SetNull(); }
COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
void SetNull() { hash = 0; n = -1; }
bool IsNull() const { return (hash == 0 && n == -1); }
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
{
return (a.hash == b.hash && a.n == b.n);
}
friend bool operator!=(const COutPoint& a, const COutPoint& b)
{
return !(a == b);
}
std::string ToString() const
{
return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n);
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
//
// An input of a transaction. It contains the location of the previous
// transaction's output that it claims and a signature that matches the
// output's public key.
//
class CTxIn
{
public:
COutPoint prevout;
CScript scriptSig;
unsigned int nSequence;
CTxIn()
{
nSequence = std::numeric_limits<unsigned int>::max();
}
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
{
prevout = prevoutIn;
scriptSig = scriptSigIn;
nSequence = nSequenceIn;
}
CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
{
prevout = COutPoint(hashPrevTx, nOut);
scriptSig = scriptSigIn;
nSequence = nSequenceIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(prevout);
READWRITE(scriptSig);
READWRITE(nSequence);
)
bool IsFinal() const
{
return (nSequence == std::numeric_limits<unsigned int>::max());
}
friend bool operator==(const CTxIn& a, const CTxIn& b)
{
return (a.prevout == b.prevout &&
a.scriptSig == b.scriptSig &&
a.nSequence == b.nSequence);
}
friend bool operator!=(const CTxIn& a, const CTxIn& b)
{
return !(a == b);
}
std::string ToString() const
{
std::string str;
str += strprintf("CTxIn(");
str += prevout.ToString();
if (prevout.IsNull())
str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
else
str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
if (nSequence != std::numeric_limits<unsigned int>::max())
str += strprintf(", nSequence=%u", nSequence);
str += ")";
return str;
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
//
// An output of a transaction. It contains the public key that the next input
// must be able to sign with to claim it.
//
class CTxOut
{
public:
- int64 nValue;
+ int64_t nValue;
CScript scriptPubKey;
CTxOut()
{
SetNull();
}
- CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
+ CTxOut(int64_t nValueIn, CScript scriptPubKeyIn)
{
nValue = nValueIn;
scriptPubKey = scriptPubKeyIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(nValue);
READWRITE(scriptPubKey);
)
void SetNull()
{
nValue = -1;
scriptPubKey.clear();
}
bool IsNull()
{
return (nValue == -1);
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
friend bool operator==(const CTxOut& a, const CTxOut& b)
{
return (a.nValue == b.nValue &&
a.scriptPubKey == b.scriptPubKey);
}
friend bool operator!=(const CTxOut& a, const CTxOut& b)
{
return !(a == b);
}
std::string ToString() const
{
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());
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
enum GetMinFee_mode
{
GMF_BLOCK,
GMF_RELAY,
GMF_SEND,
};
//
// The basic transaction that is broadcasted on the network and contained in
// blocks. A transaction can contain multiple inputs and outputs.
//
class CTransaction
{
public:
int nVersion;
std::vector<CTxIn> vin;
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()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(vin);
READWRITE(vout);
READWRITE(nLockTime);
)
void SetNull()
{
nVersion = 1;
vin.clear();
vout.clear();
nLockTime = 0;
nDoS = 0; // Denial-of-service prevention
}
bool IsNull() const
{
return (vin.empty() && vout.empty());
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
- bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
+ bool IsFinal(int nBlockHeight=0, int64_t nBlockTime=0) const
{
// Time based nLockTime implemented in 0.1.6
if (nLockTime == 0)
return true;
if (nBlockHeight == 0)
nBlockHeight = nBestHeight;
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
- if ((int64)nLockTime < (nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
+ if ((int64_t)nLockTime < (nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
return true;
BOOST_FOREACH(const CTxIn& txin, vin)
if (!txin.IsFinal())
return false;
return true;
}
bool IsNewerThan(const CTransaction& old) const
{
if (vin.size() != old.vin.size())
return false;
for (int i = 0; i < vin.size(); i++)
if (vin[i].prevout != old.vin[i].prevout)
return false;
bool fNewer = false;
unsigned int nLowest = std::numeric_limits<unsigned int>::max();
for (int i = 0; i < vin.size(); i++)
{
if (vin[i].nSequence != old.vin[i].nSequence)
{
if (vin[i].nSequence <= nLowest)
{
fNewer = false;
nLowest = vin[i].nSequence;
}
if (old.vin[i].nSequence < nLowest)
{
fNewer = true;
nLowest = old.vin[i].nSequence;
}
}
}
return fNewer;
}
bool IsCoinBase() const
{
return (vin.size() == 1 && vin[0].prevout.IsNull());
}
bool IsStandard() const;
bool AreInputsStandard(std::map<uint256, std::pair<CTxIndex, CTransaction> > mapInputs) const;
- int64 GetValueOut() const
+ int64_t GetValueOut() const
{
- int64 nValueOut = 0;
+ int64_t nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout)
{
nValueOut += txout.nValue;
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
}
return nValueOut;
}
static bool AllowFree(double dPriority)
{
// Large (in bytes) low-priority (new, small-coin) transactions
// need a fee.
return dPriority > COIN * 144 / 250;
}
- int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const
+ int64_t GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const
{
// Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
- int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
+ int64_t nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
unsigned int nNewBlockSize = nBlockSize + nBytes;
- int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
+ int64_t nMinFee = (1 + (int64_t)nBytes / 1000) * nBaseFee;
if (fAllowFree)
{
if (nBlockSize == 1)
{
// Transactions under 10K are free
// (about 4500bc if made of 50bc inputs)
if (nBytes < 10000)
nMinFee = 0;
}
else
{
// Free transaction area
if (nNewBlockSize < 27000)
nMinFee = 0;
}
}
// To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01
if (nMinFee < nBaseFee)
BOOST_FOREACH(const CTxOut& txout, vout)
if (txout.nValue < CENT)
nMinFee = nBaseFee;
// Raise the price as the block approaches full
if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2)
{
if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN)
return MAX_MONEY;
nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize);
}
if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
return nMinFee;
}
bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)
{
CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb");
if (!filein)
return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");
// Read transaction
if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
return error("CTransaction::ReadFromDisk() : fseek failed");
filein >> *this;
// Return file pointer
if (pfileRet)
{
if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
return error("CTransaction::ReadFromDisk() : second fseek failed");
*pfileRet = filein.release();
}
return true;
}
friend bool operator==(const CTransaction& a, const CTransaction& b)
{
return (a.nVersion == b.nVersion &&
a.vin == b.vin &&
a.vout == b.vout &&
a.nLockTime == b.nLockTime);
}
friend bool operator!=(const CTransaction& a, const CTransaction& b)
{
return !(a == b);
}
std::string ToString() const
{
std::string str;
str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
GetHash().ToString().substr(0,10).c_str(),
nVersion,
vin.size(),
vout.size(),
nLockTime);
for (int i = 0; i < vin.size(); i++)
str += " " + vin[i].ToString() + "\n";
for (int i = 0; i < vout.size(); i++)
str += " " + vout[i].ToString() + "\n";
return str;
}
void print() const
{
printf("%s", ToString().c_str());
}
bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet);
bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
bool ReadFromDisk(COutPoint prevout);
bool DisconnectInputs(CTxDB& txdb);
// Fetch from memory and/or disk. inputsRet keys are transaction hashes.
bool FetchInputs(CTxDB& txdb, const std::map<uint256, CTxIndex>& mapTestPool,
bool fBlock, bool fMiner, std::map<uint256, std::pair<CTxIndex, CTransaction> >& inputsRet);
bool ConnectInputs(std::map<uint256, std::pair<CTxIndex, CTransaction> > inputs,
std::map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
- CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64 nMinFee=0);
+ CBlockIndex* pindexBlock, int64_t& nFees, bool fBlock, bool fMiner, int& nSigOpsRet, int64_t nMinFee=0);
bool ClientConnectInputs();
bool CheckTransaction() const;
bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
protected:
bool AddToMemoryPoolUnchecked();
public:
bool RemoveFromMemoryPool();
};
//
// A transaction with a merkle branch linking it to the block chain
//
class CMerkleTx : public CTransaction
{
public:
uint256 hashBlock;
std::vector<uint256> vMerkleBranch;
int nIndex;
// memory only
mutable char fMerkleVerified;
CMerkleTx()
{
Init();
}
CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
{
Init();
}
void Init()
{
hashBlock = 0;
nIndex = -1;
fMerkleVerified = false;
}
IMPLEMENT_SERIALIZE
(
nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
nVersion = this->nVersion;
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
)
int SetMerkleBranch(const CBlock* pblock=NULL);
int GetDepthInMainChain(CBlockIndex* &pindexRet) const;
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
int GetBlocksToMaturity() const;
bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true);
bool AcceptToMemoryPool();
};
//
// A txdb record that contains the disk location of a transaction and the
// locations of transactions that spend its outputs. vSpent is really only
// used as a flag, but having the location is very helpful for debugging.
//
class CTxIndex
{
public:
CDiskTxPos pos;
std::vector<CDiskTxPos> vSpent;
CTxIndex()
{
SetNull();
}
CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs)
{
pos = posIn;
vSpent.resize(nOutputs);
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(pos);
READWRITE(vSpent);
)
void SetNull()
{
pos.SetNull();
vSpent.clear();
}
bool IsNull()
{
return pos.IsNull();
}
friend bool operator==(const CTxIndex& a, const CTxIndex& b)
{
return (a.pos == b.pos &&
a.vSpent == b.vSpent);
}
friend bool operator!=(const CTxIndex& a, const CTxIndex& b)
{
return !(a == b);
}
int GetDepthInMainChain() const;
};
//
// Nodes collect new transactions into a block, hash them into a hash tree,
// and scan through nonce values to make the block's hash satisfy proof-of-work
// requirements. When they solve the proof-of-work, they broadcast the block
// to everyone and the block is added to the block chain. The first transaction
// in the block is a special one that creates a new coin owned by the creator
// of the block.
//
// Blocks are appended to blk0001.dat files on disk. Their location on disk
// is indexed by CBlockIndex objects in memory.
//
class CBlock
{
public:
// header
int nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
// network and disk
std::vector<CTransaction> vtx;
// 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()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
// ConnectBlock depends on vtx being last so it can calculate offset
if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))
READWRITE(vtx);
else if (fRead)
const_cast<CBlock*>(this)->vtx.clear();
)
void SetNull()
{
nVersion = 1;
hashPrevBlock = 0;
hashMerkleRoot = 0;
nTime = 0;
nBits = 0;
nNonce = 0;
vtx.clear();
vMerkleTree.clear();
nDoS = 0;
}
bool IsNull() const
{
return (nBits == 0);
}
uint256 GetHash() const
{
return Hash(BEGIN(nVersion), END(nNonce));
}
- int64 GetBlockTime() const
+ int64_t GetBlockTime() const
{
- return (int64)nTime;
+ return (int64_t)nTime;
}
uint256 BuildMerkleTree() const
{
vMerkleTree.clear();
BOOST_FOREACH(const CTransaction& tx, vtx)
vMerkleTree.push_back(tx.GetHash());
int j = 0;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
for (int i = 0; i < nSize; i += 2)
{
int i2 = std::min(i+1, nSize-1);
vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
}
j += nSize;
}
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}
std::vector<uint256> GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())
BuildMerkleTree();
std::vector<uint256> vMerkleBranch;
int j = 0;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
int i = std::min(nIndex^1, nSize-1);
vMerkleBranch.push_back(vMerkleTree[j+i]);
nIndex >>= 1;
j += nSize;
}
return vMerkleBranch;
}
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
{
if (nIndex == -1)
return 0;
BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
{
if (nIndex & 1)
hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
else
hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
nIndex >>= 1;
}
return hash;
}
bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet)
{
// Open history file to append
CAutoFile fileout = AppendBlockFile(nFileRet);
if (!fileout)
return error("CBlock::WriteToDisk() : AppendBlockFile failed");
// Write index header
unsigned int nSize = fileout.GetSerializeSize(*this);
fileout << FLATDATA(pchMessageStart) << nSize;
// Write block
nBlockPosRet = ftell(fileout);
if (nBlockPosRet == -1)
return error("CBlock::WriteToDisk() : ftell failed");
fileout << *this;
// Flush stdio buffers and commit to disk before returning
fflush(fileout);
if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
{
#ifdef WIN32
_commit(_fileno(fileout));
#else
fsync(fileno(fileout));
#endif
}
return true;
}
bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true)
{
SetNull();
// Open history file to read
CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb");
if (!filein)
return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
if (!fReadTransactions)
filein.nType |= SER_BLOCKHEADERONLY;
// Read block
filein >> *this;
// Check the header
if (!CheckProofOfWork(GetHash(), nBits))
return error("CBlock::ReadFromDisk() : errors in block header");
return true;
}
void print() const
{
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n",
GetHash().ToString().substr(0,20).c_str(),
nVersion,
hashPrevBlock.ToString().substr(0,20).c_str(),
hashMerkleRoot.ToString().substr(0,10).c_str(),
nTime, nBits, nNonce,
vtx.size());
for (int i = 0; i < vtx.size(); i++)
{
printf(" ");
vtx[i].print();
}
printf(" vMerkleTree: ");
for (int i = 0; i < vMerkleTree.size(); i++)
printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str());
printf("\n");
}
bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew);
bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
bool CheckBlock() const;
bool AcceptBlock();
};
//
// The block chain is a tree shaped structure starting with the
// genesis block at the root, with each block potentially having multiple
// candidates to be the next block. pprev and pnext link a path through the
// main/longest chain. A blockindex may have multiple pprev pointing back
// to it, but pnext will only point forward to the longest branch, or will
// be null if the block is not part of the longest chain.
//
class CBlockIndex
{
public:
const uint256* phashBlock;
CBlockIndex* pprev;
CBlockIndex* pnext;
unsigned int nFile;
unsigned int nBlockPos;
int nHeight;
CBigNum bnChainWork;
// block header
int nVersion;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
CBlockIndex()
{
phashBlock = NULL;
pprev = NULL;
pnext = NULL;
nFile = 0;
nBlockPos = 0;
nHeight = 0;
bnChainWork = 0;
nVersion = 0;
hashMerkleRoot = 0;
nTime = 0;
nBits = 0;
nNonce = 0;
}
CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block)
{
phashBlock = NULL;
pprev = NULL;
pnext = NULL;
nFile = nFileIn;
nBlockPos = nBlockPosIn;
nHeight = 0;
bnChainWork = 0;
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
nTime = block.nTime;
nBits = block.nBits;
nNonce = block.nNonce;
}
CBlock GetBlockHeader() const
{
CBlock block;
block.nVersion = nVersion;
if (pprev)
block.hashPrevBlock = pprev->GetBlockHash();
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
return block;
}
uint256 GetBlockHash() const
{
return *phashBlock;
}
- int64 GetBlockTime() const
+ int64_t GetBlockTime() const
{
- return (int64)nTime;
+ return (int64_t)nTime;
}
CBigNum GetBlockWork() const
{
CBigNum bnTarget;
bnTarget.SetCompact(nBits);
if (bnTarget <= 0)
return 0;
return (CBigNum(1)<<256) / (bnTarget+1);
}
bool IsInMainChain() const
{
return (pnext || this == pindexBest);
}
bool CheckIndex() const
{
return CheckProofOfWork(GetBlockHash(), nBits);
}
bool EraseBlockFromDisk()
{
// Open history file
CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+");
if (!fileout)
return false;
// Overwrite with empty null block
CBlock block;
block.SetNull();
fileout << block;
return true;
}
enum { nMedianTimeSpan=11 };
- int64 GetMedianTimePast() const
+ int64_t GetMedianTimePast() const
{
- int64 pmedian[nMedianTimeSpan];
- int64* pbegin = &pmedian[nMedianTimeSpan];
- int64* pend = &pmedian[nMedianTimeSpan];
+ int64_t pmedian[nMedianTimeSpan];
+ int64_t* pbegin = &pmedian[nMedianTimeSpan];
+ int64_t* pend = &pmedian[nMedianTimeSpan];
const CBlockIndex* pindex = this;
for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
*(--pbegin) = pindex->GetBlockTime();
std::sort(pbegin, pend);
return pbegin[(pend - pbegin)/2];
}
- int64 GetMedianTime() const
+ int64_t GetMedianTime() const
{
const CBlockIndex* pindex = this;
for (int i = 0; i < nMedianTimeSpan/2; i++)
{
if (!pindex->pnext)
return GetBlockTime();
pindex = pindex->pnext;
}
return pindex->GetMedianTimePast();
}
std::string ToString() const
{
return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",
pprev, pnext, nFile, nBlockPos, nHeight,
hashMerkleRoot.ToString().substr(0,10).c_str(),
GetBlockHash().ToString().substr(0,20).c_str());
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
//
// Used to marshal pointers into hashes for db storage.
//
class CDiskBlockIndex : public CBlockIndex
{
public:
uint256 hashPrev;
uint256 hashNext;
CDiskBlockIndex()
{
hashPrev = 0;
hashNext = 0;
}
explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex)
{
hashPrev = (pprev ? pprev->GetBlockHash() : 0);
hashNext = (pnext ? pnext->GetBlockHash() : 0);
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(hashNext);
READWRITE(nFile);
READWRITE(nBlockPos);
READWRITE(nHeight);
// block header
READWRITE(this->nVersion);
READWRITE(hashPrev);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
)
uint256 GetBlockHash() const
{
CBlock block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
return block.GetHash();
}
std::string ToString() const
{
std::string str = "CDiskBlockIndex(";
str += CBlockIndex::ToString();
str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)",
GetBlockHash().ToString().c_str(),
hashPrev.ToString().substr(0,20).c_str(),
hashNext.ToString().substr(0,20).c_str());
return str;
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
//
// Describes a place in the block chain to another node such that if the
// other node doesn't have the same branch, it can find a recent common trunk.
// The further back it is, the further before the fork it may be.
//
class CBlockLocator
{
protected:
std::vector<uint256> vHave;
public:
CBlockLocator()
{
}
explicit CBlockLocator(const CBlockIndex* pindex)
{
Set(pindex);
}
explicit CBlockLocator(uint256 hashBlock)
{
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end())
Set((*mi).second);
}
CBlockLocator(const std::vector<uint256>& vHaveIn)
{
vHave = vHaveIn;
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vHave);
)
void SetNull()
{
vHave.clear();
}
bool IsNull()
{
return vHave.empty();
}
void Set(const CBlockIndex* pindex)
{
vHave.clear();
int nStep = 1;
while (pindex)
{
vHave.push_back(pindex->GetBlockHash());
// Exponentially larger steps back
for (int i = 0; pindex && i < nStep; i++)
pindex = pindex->pprev;
if (vHave.size() > 10)
nStep *= 2;
}
vHave.push_back(hashGenesisBlock);
}
int GetDistanceBack()
{
// Retrace how far back it was in the sender's branch
int nDistance = 0;
int nStep = 1;
BOOST_FOREACH(const uint256& hash, vHave)
{
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (pindex->IsInMainChain())
return nDistance;
}
nDistance += nStep;
if (nDistance > 10)
nStep *= 2;
}
return nDistance;
}
CBlockIndex* GetBlockIndex()
{
// Find the first block the caller has in the main chain
BOOST_FOREACH(const uint256& hash, vHave)
{
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (pindex->IsInMainChain())
return pindex;
}
}
return pindexGenesisBlock;
}
uint256 GetBlockHash()
{
// Find the first block the caller has in the main chain
BOOST_FOREACH(const uint256& hash, vHave)
{
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (pindex->IsInMainChain())
return hash;
}
}
return hashGenesisBlock;
}
int GetHeight()
{
CBlockIndex* pindex = GetBlockIndex();
if (!pindex)
return 0;
return pindex->nHeight;
}
};
//
// Alerts are for notifying old versions if they become too obsolete and
// need to upgrade. The message is displayed in the status bar.
// Alert messages are broadcast as a vector of signed data. Unserializing may
// not read the entire buffer if the alert is for a newer version, but older
// versions can still relay the original data.
//
class CUnsignedAlert
{
public:
int nVersion;
- int64 nRelayUntil; // when newer nodes stop relaying to newer nodes
- int64 nExpiration;
+ int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes
+ int64_t nExpiration;
int nID;
int nCancel;
std::set<int> setCancel;
int nMinVer; // lowest version inclusive
int nMaxVer; // highest version inclusive
std::set<std::string> setSubVer; // empty matches all
int nPriority;
// Actions
std::string strComment;
std::string strStatusBar;
std::string strReserved;
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(nRelayUntil);
READWRITE(nExpiration);
READWRITE(nID);
READWRITE(nCancel);
READWRITE(setCancel);
READWRITE(nMinVer);
READWRITE(nMaxVer);
READWRITE(setSubVer);
READWRITE(nPriority);
READWRITE(strComment);
READWRITE(strStatusBar);
READWRITE(strReserved);
)
void SetNull()
{
nVersion = 1;
nRelayUntil = 0;
nExpiration = 0;
nID = 0;
nCancel = 0;
setCancel.clear();
nMinVer = 0;
nMaxVer = 0;
setSubVer.clear();
nPriority = 0;
strComment.clear();
strStatusBar.clear();
strReserved.clear();
}
std::string ToString() const
{
std::string strSetCancel;
BOOST_FOREACH(int n, setCancel)
strSetCancel += strprintf("%d ", n);
std::string strSetSubVer;
BOOST_FOREACH(std::string str, setSubVer)
strSetSubVer += "\"" + str + "\" ";
return strprintf(
"CAlert(\n"
" nVersion = %d\n"
" nRelayUntil = %"PRI64d"\n"
" nExpiration = %"PRI64d"\n"
" nID = %d\n"
" nCancel = %d\n"
" setCancel = %s\n"
" nMinVer = %d\n"
" nMaxVer = %d\n"
" setSubVer = %s\n"
" nPriority = %d\n"
" strComment = \"%s\"\n"
" strStatusBar = \"%s\"\n"
")\n",
nVersion,
nRelayUntil,
nExpiration,
nID,
nCancel,
strSetCancel.c_str(),
nMinVer,
nMaxVer,
strSetSubVer.c_str(),
nPriority,
strComment.c_str(),
strStatusBar.c_str());
}
void print() const
{
printf("%s", ToString().c_str());
}
};
class CAlert : public CUnsignedAlert
{
public:
std::vector<unsigned char> vchMsg;
std::vector<unsigned char> vchSig;
CAlert()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(vchMsg);
READWRITE(vchSig);
)
void SetNull()
{
CUnsignedAlert::SetNull();
vchMsg.clear();
vchSig.clear();
}
bool IsNull() const
{
return (nExpiration == 0);
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
bool IsInEffect() const
{
return (GetAdjustedTime() < nExpiration);
}
bool Cancels(const CAlert& alert) const
{
if (!IsInEffect())
return false; // this was a no-op before 31403
return (alert.nID <= nCancel || setCancel.count(alert.nID));
}
bool AppliesTo(int nVersion, std::string strSubVerIn) const
{
// TODO: rework for client-version-embedded-in-strSubVer ?
return (IsInEffect() &&
nMinVer <= nVersion && nVersion <= nMaxVer &&
(setSubVer.empty() || setSubVer.count(strSubVerIn)));
}
bool AppliesToMe() const
{
return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
}
bool RelayTo(CNode* pnode) const
{
if (!IsInEffect())
return false;
// returns true if wasn't already contained in the set
if (pnode->setKnown.insert(GetHash()).second)
{
if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
AppliesToMe() ||
GetAdjustedTime() < nRelayUntil)
{
pnode->PushMessage("alert", *this);
return true;
}
}
return false;
}
bool CheckSignature()
{
CKey key;
if (!key.SetPubKey(ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284")))
return error("CAlert::CheckSignature() : SetPubKey failed");
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
return error("CAlert::CheckSignature() : verify signature failed");
// Now unserialize the data
CDataStream sMsg(vchMsg);
sMsg >> *(CUnsignedAlert*)this;
return true;
}
bool ProcessAlert();
};
#endif
diff --git a/src/net.cpp b/src/net.cpp
index 9b8dbe11e8..b90eebde4f 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1,1902 +1,1904 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "irc.h"
#include "db.h"
#include "net.h"
#include "init.h"
#include "strlcpy.h"
#ifdef WIN32
#include <string.h>
#endif
#ifdef USE_UPNP
#include <miniupnpc/miniwget.h>
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#include <miniupnpc/upnperrors.h>
#endif
using namespace std;
using namespace boost;
static const int MAX_OUTBOUND_CONNECTIONS = 8;
void ThreadMessageHandler2(void* parg);
void ThreadSocketHandler2(void* parg);
void ThreadOpenConnections2(void* parg);
#ifdef USE_UPNP
void ThreadMapPort2(void* parg);
#endif
void ThreadDNSAddressSeed2(void* parg);
bool OpenNetworkConnection(const CAddress& addrConnect);
//
// Global state variables
//
bool fClient = false;
bool fAllowDNS = false;
-uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
+uint64_t nLocalServices = (fClient ? 0 : NODE_NETWORK);
CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices);
static CNode* pnodeLocalHost = NULL;
-uint64 nLocalHostNonce = 0;
+uint64_t nLocalHostNonce = 0;
array<int, 10> vnThreadsRunning;
static SOCKET hListenSocket = INVALID_SOCKET;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
map<vector<unsigned char>, CAddress> mapAddresses;
CCriticalSection cs_mapAddresses;
map<CInv, CDataStream> mapRelay;
-deque<pair<int64, CInv> > vRelayExpiration;
+deque<pair<int64_t, CInv> > vRelayExpiration;
CCriticalSection cs_mapRelay;
-map<CInv, int64> mapAlreadyAskedFor;
+map<CInv, int64_t> mapAlreadyAskedFor;
// Settings
int fUseProxy = false;
int nConnectTimeout = 5000;
CAddress addrProxy("127.0.0.1",9050);
unsigned short GetListenPort()
{
return (unsigned short)(GetArg("-port", GetDefaultPort()));
}
void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
{
// Filter out duplicate requests
if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
return;
pindexLastGetBlocksBegin = pindexBegin;
hashLastGetBlocksEnd = hashEnd;
PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
}
bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout)
{
hSocketRet = INVALID_SOCKET;
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
return false;
#ifdef SO_NOSIGPIPE
int set = 1;
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif
bool fProxy = (fUseProxy && addrConnect.IsRoutable());
struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
#ifdef WIN32
u_long fNonblock = 1;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
#else
int fFlags = fcntl(hSocket, F_GETFL, 0);
if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
#endif
{
closesocket(hSocket);
return false;
}
if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
{
// WSAEINVAL is here because some legacy version of winsock uses it
if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
{
struct timeval timeout;
timeout.tv_sec = nTimeout / 1000;
timeout.tv_usec = (nTimeout % 1000) * 1000;
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
if (nRet == 0)
{
printf("connection timeout\n");
closesocket(hSocket);
return false;
}
if (nRet == SOCKET_ERROR)
{
printf("select() for connection failed: %i\n",WSAGetLastError());
closesocket(hSocket);
return false;
}
socklen_t nRetSize = sizeof(nRet);
#ifdef WIN32
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
#else
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
#endif
{
printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
closesocket(hSocket);
return false;
}
if (nRet != 0)
{
printf("connect() failed after select(): %s\n",strerror(nRet));
closesocket(hSocket);
return false;
}
}
#ifdef WIN32
else if (WSAGetLastError() != WSAEISCONN)
#else
else
#endif
{
printf("connect() failed: %i\n",WSAGetLastError());
closesocket(hSocket);
return false;
}
}
/*
this isn't even strictly necessary
CNode::ConnectNode immediately turns the socket back to non-blocking
but we'll turn it back to blocking just in case
*/
#ifdef WIN32
fNonblock = 0;
if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
#else
fFlags = fcntl(hSocket, F_GETFL, 0);
if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
#endif
{
closesocket(hSocket);
return false;
}
if (fProxy)
{
printf("proxy connecting %s\n", addrConnect.ToString().c_str());
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
char* pszSocks4 = pszSocks4IP;
int nSize = sizeof(pszSocks4IP);
int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
if (ret != nSize)
{
closesocket(hSocket);
return error("Error sending to proxy");
}
char pchRet[8];
if (recv(hSocket, pchRet, 8, 0) != 8)
{
closesocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet[1] != 0x5a)
{
closesocket(hSocket);
if (pchRet[1] != 0x5b)
printf("ERROR: Proxy returned error %d\n", pchRet[1]);
return false;
}
printf("proxy connected %s\n", addrConnect.ToString().c_str());
}
hSocketRet = hSocket;
return true;
}
// portDefault is in host order
bool Lookup(const char *pszName, vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup, int portDefault, bool fAllowPort)
{
vaddr.clear();
if (pszName[0] == 0)
return false;
int port = portDefault;
char psz[256];
char *pszHost = psz;
strlcpy(psz, pszName, sizeof(psz));
if (fAllowPort)
{
char* pszColon = strrchr(psz+1,':');
char *pszPortEnd = NULL;
int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
{
if (psz[0] == '[' && pszColon[-1] == ']')
{
// Future: enable IPv6 colon-notation inside []
pszHost = psz+1;
pszColon[-1] = 0;
}
else
pszColon[0] = 0;
port = portParsed;
if (port < 0 || port > std::numeric_limits<unsigned short>::max())
port = std::numeric_limits<unsigned short>::max();
}
}
unsigned int addrIP = inet_addr(pszHost);
if (addrIP != INADDR_NONE)
{
// valid IP address passed
vaddr.push_back(CAddress(addrIP, port, nServices));
return true;
}
if (!fAllowLookup)
return false;
struct hostent* phostent = gethostbyname(pszHost);
if (!phostent)
return false;
if (phostent->h_addrtype != AF_INET)
return false;
char** ppAddr = phostent->h_addr_list;
while (*ppAddr != NULL && vaddr.size() != nMaxSolutions)
{
CAddress addr(((struct in_addr*)ppAddr[0])->s_addr, port, nServices);
if (addr.IsValid())
vaddr.push_back(addr);
ppAddr++;
}
return (vaddr.size() > 0);
}
// portDefault is in host order
bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup, int portDefault, bool fAllowPort)
{
vector<CAddress> vaddr;
bool fRet = Lookup(pszName, vaddr, nServices, 1, fAllowLookup, portDefault, fAllowPort);
if (fRet)
addr = vaddr[0];
return fRet;
}
bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
{
SOCKET hSocket;
if (!ConnectSocket(addrConnect, hSocket))
return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());
send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);
string strLine;
while (RecvLine(hSocket, strLine))
{
if (strLine.empty()) // HTTP response is separated from headers by blank line
{
loop
{
if (!RecvLine(hSocket, strLine))
{
closesocket(hSocket);
return false;
}
if (pszKeyword == NULL)
break;
if (strLine.find(pszKeyword) != -1)
{
strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
break;
}
}
closesocket(hSocket);
if (strLine.find("<") != -1)
strLine = strLine.substr(0, strLine.find("<"));
strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
strLine.resize(strLine.size()-1);
CAddress addr(strLine,0,true);
printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
return false;
ipRet = addr.ip;
return true;
}
}
closesocket(hSocket);
return error("GetMyExternalIP() : connection closed");
}
// We now get our external IP from the IRC server first and only use this as a backup
bool GetMyExternalIP(unsigned int& ipRet)
{
CAddress addrConnect;
const char* pszGet;
const char* pszKeyword;
if (fUseProxy)
return false;
for (int nLookup = 0; nLookup <= 1; nLookup++)
for (int nHost = 1; nHost <= 2; nHost++)
{
// We should be phasing out our use of sites like these. If we need
// replacements, we should ask for volunteers to put this simple
// php file on their webserver that prints the client IP:
// <?php echo $_SERVER["REMOTE_ADDR"]; ?>
if (nHost == 1)
{
addrConnect = CAddress("91.198.22.70",80); // checkip.dyndns.org
if (nLookup == 1)
{
CAddress addrIP("checkip.dyndns.org", 80, true);
if (addrIP.IsValid())
addrConnect = addrIP;
}
pszGet = "GET / HTTP/1.1\r\n"
"Host: checkip.dyndns.org\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
"Connection: close\r\n"
"\r\n";
pszKeyword = "Address:";
}
else if (nHost == 2)
{
addrConnect = CAddress("74.208.43.192", 80); // www.showmyip.com
if (nLookup == 1)
{
CAddress addrIP("www.showmyip.com", 80, true);
if (addrIP.IsValid())
addrConnect = addrIP;
}
pszGet = "GET /simple/ HTTP/1.1\r\n"
"Host: www.showmyip.com\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
"Connection: close\r\n"
"\r\n";
pszKeyword = NULL; // Returns just IP address
}
if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
return true;
}
return false;
}
void ThreadGetMyExternalIP(void* parg)
{
// Wait for IRC to get it first
if (!GetBoolArg("-noirc"))
{
for (int i = 0; i < 2 * 60; i++)
{
Sleep(1000);
if (fGotExternalIP || fShutdown)
return;
}
}
// Fallback in case IRC fails to get it
if (GetMyExternalIP(addrLocalHost.ip))
{
printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
if (addrLocalHost.IsRoutable())
{
// If we already connected to a few before we had our IP, go back and addr them.
// setAddrKnown automatically filters any duplicate sends.
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushAddress(addr);
}
}
}
-bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
+bool AddAddress(CAddress addr, int64_t nTimePenalty, CAddrDB *pAddrDB)
{
if (!addr.IsRoutable())
return false;
if (addr.ip == addrLocalHost.ip)
return false;
- addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
+ addr.nTime = max((int64_t)0, (int64_t)addr.nTime - nTimePenalty);
bool fUpdated = false;
bool fNew = false;
CAddress addrFound = addr;
CRITICAL_BLOCK(cs_mapAddresses)
{
map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
if (it == mapAddresses.end())
{
// New address
printf("AddAddress(%s)\n", addr.ToString().c_str());
mapAddresses.insert(make_pair(addr.GetKey(), addr));
fUpdated = true;
fNew = true;
}
else
{
addrFound = (*it).second;
if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
{
// Services have been added
addrFound.nServices |= addr.nServices;
fUpdated = true;
}
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
- int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
+ int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
if (addrFound.nTime < addr.nTime - nUpdateInterval)
{
// Periodically update most recently seen time
addrFound.nTime = addr.nTime;
fUpdated = true;
}
}
}
// There is a nasty deadlock bug if this is done inside the cs_mapAddresses
// CRITICAL_BLOCK:
// Thread 1: begin db transaction (locks inside-db-mutex)
// then AddAddress (locks cs_mapAddresses)
// Thread 2: AddAddress (locks cs_mapAddresses)
// ... then db operation hangs waiting for inside-db-mutex
if (fUpdated)
{
if (pAddrDB)
pAddrDB->WriteAddress(addrFound);
else
CAddrDB().WriteAddress(addrFound);
}
return fNew;
}
void AddressCurrentlyConnected(const CAddress& addr)
{
CRITICAL_BLOCK(cs_mapAddresses)
{
// Only if it's been published already
map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
if (it != mapAddresses.end())
{
CAddress& addrFound = (*it).second;
- int64 nUpdateInterval = 20 * 60;
+ int64_t nUpdateInterval = 20 * 60;
if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
{
// Periodically update most recently seen time
addrFound.nTime = GetAdjustedTime();
CAddrDB addrdb;
addrdb.WriteAddress(addrFound);
}
}
}
}
void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
{
// If the dialog might get closed before the reply comes back,
// call this in the destructor so it doesn't get called after it's deleted.
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
{
CRITICAL_BLOCK(pnode->cs_mapRequests)
{
for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
{
CRequestTracker& tracker = (*mi).second;
if (tracker.fn == fn && tracker.param1 == param1)
pnode->mapRequests.erase(mi++);
else
mi++;
}
}
}
}
}
//
// Subscription methods for the broadcast and subscription system.
// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
//
// The subscription system uses a meet-in-the-middle strategy.
// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
//
bool AnySubscribed(unsigned int nChannel)
{
if (pnodeLocalHost->IsSubscribed(nChannel))
return true;
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->IsSubscribed(nChannel))
return true;
return false;
}
bool CNode::IsSubscribed(unsigned int nChannel)
{
if (nChannel >= vfSubscribe.size())
return false;
return vfSubscribe[nChannel];
}
void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
{
if (nChannel >= vfSubscribe.size())
return;
if (!AnySubscribed(nChannel))
{
// Relay subscribe
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode != this)
pnode->PushMessage("subscribe", nChannel, nHops);
}
vfSubscribe[nChannel] = true;
}
void CNode::CancelSubscribe(unsigned int nChannel)
{
if (nChannel >= vfSubscribe.size())
return;
// Prevent from relaying cancel if wasn't subscribed
if (!vfSubscribe[nChannel])
return;
vfSubscribe[nChannel] = false;
if (!AnySubscribed(nChannel))
{
// Relay subscription cancel
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode != this)
pnode->PushMessage("sub-cancel", nChannel);
}
}
CNode* FindNode(unsigned int ip)
{
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->addr.ip == ip)
return (pnode);
}
return NULL;
}
CNode* FindNode(CAddress addr)
{
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->addr == addr)
return (pnode);
}
return NULL;
}
-CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
+CNode* ConnectNode(CAddress addrConnect, int64_t nTimeout)
{
if (addrConnect.ip == addrLocalHost.ip)
return NULL;
// Look for an existing connection
CNode* pnode = FindNode(addrConnect.ip);
if (pnode)
{
if (nTimeout != 0)
pnode->AddRef(nTimeout);
else
pnode->AddRef();
return pnode;
}
/// debug print
printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
addrConnect.ToString().c_str(),
(double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
(double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
CRITICAL_BLOCK(cs_mapAddresses)
mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
// Connect
SOCKET hSocket;
if (ConnectSocket(addrConnect, hSocket))
{
/// debug print
printf("connected %s\n", addrConnect.ToString().c_str());
// Set to nonblocking
#ifdef WIN32
u_long nOne = 1;
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
#else
if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno);
#endif
// Add node
CNode* pnode = new CNode(hSocket, addrConnect, false);
if (nTimeout != 0)
pnode->AddRef(nTimeout);
else
pnode->AddRef();
CRITICAL_BLOCK(cs_vNodes)
vNodes.push_back(pnode);
pnode->nTimeConnected = GetTime();
return pnode;
}
else
{
return NULL;
}
}
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
if (hSocket != INVALID_SOCKET)
{
if (fDebug)
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("disconnecting node %s\n", addr.ToString().c_str());
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
}
void CNode::Cleanup()
{
// All of a nodes broadcasts and subscriptions are automatically torn down
// when it goes down, so a node has to stay up to keep its broadcast going.
// Cancel subscriptions
for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
if (vfSubscribe[nChannel])
CancelSubscribe(nChannel);
}
void CNode::PushVersion()
{
/// when NTP implemented, change to just nTime = GetAdjustedTime()
- int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
+ int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
}
-std::map<unsigned int, int64> CNode::setBanned;
+std::map<unsigned int, int64_t> 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);
+ std::map<unsigned int, int64_t>::iterator i = setBanned.find(ip);
if (i != setBanned.end())
{
- int64 t = (*i).second;
+ int64_t 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
+ int64_t 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;
}
void ThreadSocketHandler(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
try
{
vnThreadsRunning[0]++;
ThreadSocketHandler2(parg);
vnThreadsRunning[0]--;
}
catch (std::exception& e) {
vnThreadsRunning[0]--;
PrintException(&e, "ThreadSocketHandler()");
} catch (...) {
vnThreadsRunning[0]--;
throw; // support pthread_cancel()
}
printf("ThreadSocketHandler exiting\n");
}
void ThreadSocketHandler2(void* parg)
{
printf("ThreadSocketHandler started\n");
list<CNode*> vNodesDisconnected;
int nPrevNodeCount = 0;
loop
{
//
// Disconnect nodes
//
CRITICAL_BLOCK(cs_vNodes)
{
// Disconnect unused nodes
vector<CNode*> vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
if (pnode->fDisconnect ||
(pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
{
// remove from vNodes
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
// close socket and cleanup
pnode->CloseSocketDisconnect();
pnode->Cleanup();
// hold in disconnected pool until all refs are released
pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
if (pnode->fNetworkNode || pnode->fInbound)
pnode->Release();
vNodesDisconnected.push_back(pnode);
}
}
// Delete disconnected nodes
list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
{
// wait until threads are done using it
if (pnode->GetRefCount() <= 0)
{
bool fDelete = false;
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
TRY_CRITICAL_BLOCK(pnode->cs_inventory)
fDelete = true;
if (fDelete)
{
vNodesDisconnected.remove(pnode);
delete pnode;
}
}
}
}
if (vNodes.size() != nPrevNodeCount)
{
nPrevNodeCount = vNodes.size();
MainFrameRepaint();
}
//
// Find which sockets have data to receive
//
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50000; // frequency to poll pnode->vSend
fd_set fdsetRecv;
fd_set fdsetSend;
fd_set fdsetError;
FD_ZERO(&fdsetRecv);
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
SOCKET hSocketMax = 0;
if(hListenSocket != INVALID_SOCKET)
FD_SET(hListenSocket, &fdsetRecv);
hSocketMax = max(hSocketMax, hListenSocket);
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
{
if (pnode->hSocket == INVALID_SOCKET)
continue;
FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError);
hSocketMax = max(hSocketMax, pnode->hSocket);
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
if (!pnode->vSend.empty())
FD_SET(pnode->hSocket, &fdsetSend);
}
}
vnThreadsRunning[0]--;
int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
vnThreadsRunning[0]++;
if (fShutdown)
return;
if (nSelect == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
if (hSocketMax > -1)
{
printf("socket select error %d\n", nErr);
for (int i = 0; i <= hSocketMax; i++)
FD_SET(i, &fdsetRecv);
}
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
Sleep(timeout.tv_usec/1000);
}
//
// Accept new connections
//
if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
{
struct sockaddr_in sockaddr;
socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
CAddress addr(sockaddr);
int nInbound = 0;
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->fInbound)
nInbound++;
if (hSocket == INVALID_SOCKET)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
printf("socket error accept failed: %d\n", WSAGetLastError());
}
else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
{
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());
CNode* pnode = new CNode(hSocket, addr, true);
pnode->AddRef();
CRITICAL_BLOCK(cs_vNodes)
vNodes.push_back(pnode);
}
}
//
// Service each socket
//
vector<CNode*> vNodesCopy;
CRITICAL_BLOCK(cs_vNodes)
{
vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->AddRef();
}
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
if (fShutdown)
return;
//
// Receive
//
if (pnode->hSocket == INVALID_SOCKET)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
{
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
{
CDataStream& vRecv = pnode->vRecv;
unsigned int nPos = vRecv.size();
if (nPos > ReceiveBufferSize()) {
if (!pnode->fDisconnect)
printf("socket recv flood control disconnect (%d bytes)\n", vRecv.size());
pnode->CloseSocketDisconnect();
}
else {
// typical socket buffer is 8K-64K
char pchBuf[0x10000];
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
if (nBytes > 0)
{
vRecv.resize(nPos + nBytes);
memcpy(&vRecv[nPos], pchBuf, nBytes);
pnode->nLastRecv = GetTime();
}
else if (nBytes == 0)
{
// socket closed gracefully
if (!pnode->fDisconnect)
printf("socket closed\n");
pnode->CloseSocketDisconnect();
}
else if (nBytes < 0)
{
// error
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
if (!pnode->fDisconnect)
printf("socket recv error %d\n", nErr);
pnode->CloseSocketDisconnect();
}
}
}
}
}
//
// Send
//
if (pnode->hSocket == INVALID_SOCKET)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetSend))
{
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
{
CDataStream& vSend = pnode->vSend;
if (!vSend.empty())
{
int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
if (nBytes > 0)
{
vSend.erase(vSend.begin(), vSend.begin() + nBytes);
pnode->nLastSend = GetTime();
}
else if (nBytes < 0)
{
// error
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
printf("socket send error %d\n", nErr);
pnode->CloseSocketDisconnect();
}
}
if (vSend.size() > SendBufferSize()) {
if (!pnode->fDisconnect)
printf("socket send flood control disconnect (%d bytes)\n", vSend.size());
pnode->CloseSocketDisconnect();
}
}
}
}
//
// Inactivity checking
//
if (pnode->vSend.empty())
pnode->nLastSendEmpty = GetTime();
if (GetTime() - pnode->nTimeConnected > 60)
{
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
{
printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
pnode->fDisconnect = true;
}
else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
{
printf("socket not sending\n");
pnode->fDisconnect = true;
}
else if (GetTime() - pnode->nLastRecv > 90*60)
{
printf("socket inactivity timeout\n");
pnode->fDisconnect = true;
}
}
}
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->Release();
}
Sleep(10);
}
}
#ifdef USE_UPNP
void ThreadMapPort(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg));
try
{
vnThreadsRunning[5]++;
ThreadMapPort2(parg);
vnThreadsRunning[5]--;
}
catch (std::exception& e) {
vnThreadsRunning[5]--;
PrintException(&e, "ThreadMapPort()");
} catch (...) {
vnThreadsRunning[5]--;
PrintException(NULL, "ThreadMapPort()");
}
printf("ThreadMapPort exiting\n");
}
void ThreadMapPort2(void* parg)
{
printf("ThreadMapPort started\n");
char port[6];
sprintf(port, "%d", GetListenPort());
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;
int r;
r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
if (r == 1)
{
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",
port, port, lanaddr, r, strupnperror(r));
else
printf("UPnP Port Mapping successful.\n");
loop {
if (fShutdown || !fUseUPnP)
{
r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port, "TCP", 0);
printf("UPNP_DeletePortMapping() returned : %d\n", r);
freeUPNPDevlist(devlist); devlist = 0;
FreeUPNPUrls(&urls);
return;
}
Sleep(2000);
}
} else {
printf("No valid UPnP IGDs found\n");
freeUPNPDevlist(devlist); devlist = 0;
if (r != 0)
FreeUPNPUrls(&urls);
loop {
if (fShutdown || !fUseUPnP)
return;
Sleep(2000);
}
}
}
void MapPort(bool fMapPort)
{
if (fUseUPnP != fMapPort)
{
fUseUPnP = fMapPort;
WriteSetting("fUseUPnP", fUseUPnP);
}
if (fUseUPnP && vnThreadsRunning[5] < 1)
{
if (!CreateThread(ThreadMapPort, NULL))
printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
}
}
#else
void MapPort(bool /* unused fMapPort */)
{
// Intentionally left blank.
}
#endif
static const char *strDNSSeed[] = {
"bitseed.xf2.org",
"dnsseed.bluematt.me",
"seed.bitcoin.sipa.be",
"dnsseed.bitcoin.dashjr.org",
};
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)
{
printf("Loading addresses from DNS seeds (could take a while)\n");
CAddrDB addrDB;
addrDB.TxnBegin();
for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
vector<CAddress> vaddr;
if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true))
{
BOOST_FOREACH (CAddress& addr, vaddr)
{
if (addr.GetByte(3) != 127)
{
addr.nTime = 0;
AddAddress(addr, 0, &addrDB);
found++;
}
}
}
}
addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
}
printf("%d addresses found from DNS seeds\n", found);
}
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,
};
void ThreadOpenConnections(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
try
{
vnThreadsRunning[1]++;
ThreadOpenConnections2(parg);
vnThreadsRunning[1]--;
}
catch (std::exception& e) {
vnThreadsRunning[1]--;
PrintException(&e, "ThreadOpenConnections()");
} catch (...) {
vnThreadsRunning[1]--;
PrintException(NULL, "ThreadOpenConnections()");
}
printf("ThreadOpenConnections exiting\n");
}
void ThreadOpenConnections2(void* parg)
{
printf("ThreadOpenConnections started\n");
// Connect to specific addresses
if (mapArgs.count("-connect"))
{
- for (int64 nLoop = 0;; nLoop++)
+ for (int64_t nLoop = 0;; nLoop++)
{
BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
{
CAddress addr(strAddr, fAllowDNS);
if (addr.IsValid())
OpenNetworkConnection(addr);
for (int i = 0; i < 10 && i < nLoop; i++)
{
Sleep(500);
if (fShutdown)
return;
}
}
}
}
// Connect to manually added nodes first
if (mapArgs.count("-addnode"))
{
BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
{
CAddress addr(strAddr, fAllowDNS);
if (addr.IsValid())
{
OpenNetworkConnection(addr);
Sleep(500);
if (fShutdown)
return;
}
}
}
// Initiate network connections
- int64 nStart = GetTime();
+ int64_t nStart = GetTime();
loop
{
// Limit outbound connections
vnThreadsRunning[1]--;
Sleep(500);
loop
{
int nOutbound = 0;
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (!pnode->fInbound)
nOutbound++;
int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125));
if (nOutbound < nMaxOutboundConnections)
break;
Sleep(2000);
if (fShutdown)
return;
}
vnThreadsRunning[1]++;
if (fShutdown)
return;
CRITICAL_BLOCK(cs_mapAddresses)
{
// Add seed nodes if IRC isn't working
bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
{
for (int i = 0; i < ARRAYLEN(pnSeed); i++)
{
// It'll only connect to one or two seed nodes because once it connects,
// it'll get a pile of addresses with newer timestamps.
// Seed nodes are given a random 'last seen time' of between one and two
// weeks ago.
- const int64 nOneWeek = 7*24*60*60;
+ const int64_t nOneWeek = 7*24*60*60;
CAddress addr;
addr.ip = pnSeed[i];
addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
AddAddress(addr);
}
}
}
//
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect;
- int64 nBest = std::numeric_limits<int64>::min();
+ int64_t nBest = std::numeric_limits<int64_t>::min();
// Only connect to one address per a.b.?.? range.
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
set<unsigned int> setConnected;
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
setConnected.insert(pnode->addr.ip & 0x0000ffff);
- int64 nANow = GetAdjustedTime();
+ int64_t 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 = nANow - addr.nTime;
- int64 nSinceLastTry = nANow - addr.nLastTry;
+ int64_t nSinceLastSeen = nANow - addr.nTime;
+ int64_t 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);
+ int64_t nRandomizer = (uint64_t)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
if (addr.port != htons(GetDefaultPort()))
nRandomizer += 2 * 60 * 60;
// Last seen Base retry frequency
// <1 hour 10 min
// 1 hour 1 hour
// 4 hours 2 hours
// 24 hours 5 hours
// 48 hours 7 hours
// 7 days 13 hours
// 30 days 27 hours
// 90 days 46 hours
// 365 days 93 hours
- int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
+ int64_t nDelay = (int64_t)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
// Fast reconnect for one hour after last seen
if (nSinceLastSeen < 60 * 60)
nDelay = 10 * 60;
// Limit retry frequency
if (nSinceLastTry < nDelay)
continue;
// If we have IRC, we'll be notified when they first come online,
// and again every 24 hours by the refresh broadcast.
if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
continue;
// Only try the old stuff if we don't have enough connections
if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
continue;
// If multiple addresses are ready, prioritize by time since
// last seen and time since last tried.
- int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
+ int64_t nScore = min(nSinceLastTry, (int64_t)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
if (nScore > nBest)
{
nBest = nScore;
addrConnect = addr;
}
}
}
if (addrConnect.IsValid())
OpenNetworkConnection(addrConnect);
}
}
bool OpenNetworkConnection(const CAddress& addrConnect)
{
//
// Initiate outbound network connection
//
if (fShutdown)
return false;
if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
return false;
vnThreadsRunning[1]--;
CNode* pnode = ConnectNode(addrConnect);
vnThreadsRunning[1]++;
if (fShutdown)
return false;
if (!pnode)
return false;
pnode->fNetworkNode = true;
return true;
}
void ThreadMessageHandler(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
try
{
vnThreadsRunning[2]++;
ThreadMessageHandler2(parg);
vnThreadsRunning[2]--;
}
catch (std::exception& e) {
vnThreadsRunning[2]--;
PrintException(&e, "ThreadMessageHandler()");
} catch (...) {
vnThreadsRunning[2]--;
PrintException(NULL, "ThreadMessageHandler()");
}
printf("ThreadMessageHandler exiting\n");
}
void ThreadMessageHandler2(void* parg)
{
printf("ThreadMessageHandler started\n");
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
while (!fShutdown)
{
vector<CNode*> vNodesCopy;
CRITICAL_BLOCK(cs_vNodes)
{
vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->AddRef();
}
// Poll the connected nodes for messages
CNode* pnodeTrickle = NULL;
if (!vNodesCopy.empty())
pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
BOOST_FOREACH(CNode* pnode, vNodesCopy)
{
// Receive messages
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
ProcessMessages(pnode);
if (fShutdown)
return;
// Send messages
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
SendMessages(pnode, pnode == pnodeTrickle);
if (fShutdown)
return;
}
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodesCopy)
pnode->Release();
}
// Wait and allow messages to bunch up.
// Reduce vnThreadsRunning so StopNode has permission to exit while
// we're sleeping, but we must always check fShutdown after doing this.
vnThreadsRunning[2]--;
Sleep(100);
if (fRequestShutdown)
Shutdown(NULL);
vnThreadsRunning[2]++;
if (fShutdown)
return;
}
}
bool BindListenPort(string& strError)
{
strError = "";
int nOne = 1;
addrLocalHost.port = htons(GetListenPort());
#ifdef WIN32
// Initialize Windows Sockets
WSADATA wsadata;
int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
if (ret != NO_ERROR)
{
strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
printf("%s\n", strError.c_str());
return false;
}
#endif
// Create socket for listening for incoming connections
hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hListenSocket == INVALID_SOCKET)
{
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
printf("%s\n", strError.c_str());
return false;
}
#ifdef SO_NOSIGPIPE
// Different way of disabling SIGPIPE on BSD
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
#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 WIN32
// Set to nonblocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
#else
if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
#endif
{
strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
printf("%s\n", strError.c_str());
return false;
}
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
sockaddr.sin_port = htons(GetListenPort());
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), ntohs(sockaddr.sin_port));
else
strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
printf("%s\n", strError.c_str());
return false;
}
printf("Bound to port %d\n", ntohs(sockaddr.sin_port));
// Listen for incoming connections
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
{
strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
printf("%s\n", strError.c_str());
return false;
}
return true;
}
void StartNode(void* parg)
{
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
#ifdef WIN32
// Get local host ip
char pszHostName[1000] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
{
vector<CAddress> vaddr;
if (Lookup(pszHostName, vaddr, nLocalServices, -1, true))
BOOST_FOREACH (const CAddress &addr, vaddr)
if (addr.GetByte(3) != 127)
{
addrLocalHost = addr;
break;
}
}
#else
// Get local host ip
struct ifaddrs* myaddrs;
if (getifaddrs(&myaddrs) == 0)
{
for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL) continue;
if ((ifa->ifa_flags & IFF_UP) == 0) continue;
if (strcmp(ifa->ifa_name, "lo") == 0) continue;
if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
char pszIP[100];
if (ifa->ifa_addr->sa_family == AF_INET)
{
struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
// Take the first IP that isn't loopback 127.x.x.x
CAddress addr(*(unsigned int*)&s4->sin_addr, GetListenPort(), nLocalServices);
if (addr.IsValid() && addr.GetByte(3) != 127)
{
addrLocalHost = addr;
break;
}
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
}
}
freeifaddrs(myaddrs);
}
#endif
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
if (fUseProxy || mapArgs.count("-connect") || fNoListen)
{
// Proxies can't take incoming connections
addrLocalHost.ip = CAddress("0.0.0.0").ip;
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
}
else
{
CreateThread(ThreadGetMyExternalIP, NULL);
}
//
// 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);
// Get addresses from IRC and advertise ours
if (!CreateThread(ThreadIRCSeed, NULL))
printf("Error: CreateThread(ThreadIRCSeed) failed\n");
// Send and receive from sockets, accept connections
if (!CreateThread(ThreadSocketHandler, NULL))
printf("Error: CreateThread(ThreadSocketHandler) failed\n");
// Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL))
printf("Error: CreateThread(ThreadOpenConnections) failed\n");
// Process messages
if (!CreateThread(ThreadMessageHandler, NULL))
printf("Error: CreateThread(ThreadMessageHandler) failed\n");
// Generate coins in the background
GenerateBitcoins(fGenerateBitcoins, pwalletMain);
}
bool StopNode()
{
printf("StopNode()\n");
fShutdown = true;
nTransactionsUpdated++;
- int64 nStart = GetTime();
+ int64_t nStart = GetTime();
while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0
#ifdef USE_UPNP
|| vnThreadsRunning[5] > 0
#endif
)
{
if (GetTime() - nStart > 20)
break;
Sleep(20);
}
if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n");
if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n");
while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
Sleep(20);
Sleep(50);
return true;
}
class CNetCleanup
{
public:
CNetCleanup()
{
}
~CNetCleanup()
{
// Close sockets
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode->hSocket != INVALID_SOCKET)
closesocket(pnode->hSocket);
if (hListenSocket != INVALID_SOCKET)
if (closesocket(hListenSocket) == SOCKET_ERROR)
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
#ifdef WIN32
// Shutdown Windows Sockets
WSACleanup();
#endif
}
}
instance_of_cnetcleanup;
diff --git a/src/net.h b/src/net.h
index c2637dc6ac..9f99f474f6 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1,689 +1,691 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
+#include <stdint.h>
+
#include <deque>
#include <boost/array.hpp>
#include <boost/foreach.hpp>
#include <openssl/rand.h>
#ifndef WIN32
#include <arpa/inet.h>
#endif
#include "protocol.h"
class CAddrDB;
class CRequestTracker;
class CNode;
class CBlockIndex;
extern int nBestHeight;
extern int nConnectTimeout;
inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
static const unsigned int PUBLISH_HOPS = 5;
bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout=nConnectTimeout);
bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
bool GetMyExternalIP(unsigned int& ipRet);
-bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
+bool AddAddress(CAddress addr, int64_t nTimePenalty=0, CAddrDB *pAddrDB=NULL);
void AddressCurrentlyConnected(const CAddress& addr);
CNode* FindNode(unsigned int ip);
-CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
+CNode* ConnectNode(CAddress addrConnect, int64_t nTimeout=0);
void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
bool AnySubscribed(unsigned int nChannel);
void MapPort(bool fMapPort);
bool BindListenPort(std::string& strError=REF(std::string()));
void StartNode(void* parg);
bool StopNode();
enum
{
MSG_TX = 1,
MSG_BLOCK,
};
class CRequestTracker
{
public:
void (*fn)(void*, CDataStream&);
void* param1;
explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
{
fn = fnIn;
param1 = param1In;
}
bool IsNull()
{
return fn == NULL;
}
};
extern bool fClient;
extern bool fAllowDNS;
-extern uint64 nLocalServices;
+extern uint64_t nLocalServices;
extern CAddress addrLocalHost;
-extern uint64 nLocalHostNonce;
+extern uint64_t nLocalHostNonce;
extern boost::array<int, 10> vnThreadsRunning;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
extern CCriticalSection cs_mapAddresses;
extern std::map<CInv, CDataStream> mapRelay;
-extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
+extern std::deque<std::pair<int64_t, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
-extern std::map<CInv, int64> mapAlreadyAskedFor;
+extern std::map<CInv, int64_t> mapAlreadyAskedFor;
// Settings
extern int fUseProxy;
extern CAddress addrProxy;
class CNode
{
public:
// socket
- uint64 nServices;
+ uint64_t nServices;
SOCKET hSocket;
CDataStream vSend;
CDataStream vRecv;
CCriticalSection cs_vSend;
CCriticalSection cs_vRecv;
- int64 nLastSend;
- int64 nLastRecv;
- int64 nLastSendEmpty;
- int64 nTimeConnected;
+ int64_t nLastSend;
+ int64_t nLastRecv;
+ int64_t nLastSendEmpty;
+ int64_t nTimeConnected;
unsigned int nHeaderStart;
unsigned int nMessageStart;
CAddress addr;
int nVersion;
std::string strSubVer;
bool fClient;
bool fInbound;
bool fNetworkNode;
bool fSuccessfullyConnected;
bool fDisconnect;
protected:
int nRefCount;
// Denial-of-service detection/prevention
// Key is ip address, value is banned-until-time
- static std::map<unsigned int, int64> setBanned;
+ static std::map<unsigned int, int64_t> setBanned;
static CCriticalSection cs_setBanned;
int nMisbehavior;
public:
- int64 nReleaseTime;
+ int64_t nReleaseTime;
std::map<uint256, CRequestTracker> mapRequests;
CCriticalSection cs_mapRequests;
uint256 hashContinue;
CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd;
int nStartingHeight;
// flood relay
std::vector<CAddress> vAddrToSend;
std::set<CAddress> setAddrKnown;
bool fGetAddr;
std::set<uint256> setKnown;
// inventory based relay
std::set<CInv> setInventoryKnown;
std::vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory;
- std::multimap<int64, CInv> mapAskFor;
+ std::multimap<int64_t, CInv> mapAskFor;
// publish and subscription
std::vector<char> vfSubscribe;
CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
{
nServices = 0;
hSocket = hSocketIn;
vSend.SetType(SER_NETWORK);
vSend.SetVersion(0);
vRecv.SetType(SER_NETWORK);
vRecv.SetVersion(0);
// Version 0.2 obsoletes 20 Feb 2012
if (GetTime() > 1329696000)
{
vSend.SetVersion(209);
vRecv.SetVersion(209);
}
nLastSend = 0;
nLastRecv = 0;
nLastSendEmpty = GetTime();
nTimeConnected = GetTime();
nHeaderStart = -1;
nMessageStart = -1;
addr = addrIn;
nVersion = 0;
strSubVer = "";
fClient = false; // set by version message
fInbound = fInboundIn;
fNetworkNode = false;
fSuccessfullyConnected = false;
fDisconnect = false;
nRefCount = 0;
nReleaseTime = 0;
hashContinue = 0;
pindexLastGetBlocksBegin = 0;
hashLastGetBlocksEnd = 0;
nStartingHeight = -1;
fGetAddr = false;
vfSubscribe.assign(256, false);
nMisbehavior = 0;
// Be shy and don't send version until we hear
if (!fInbound)
PushVersion();
}
~CNode()
{
if (hSocket != INVALID_SOCKET)
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
}
private:
CNode(const CNode&);
void operator=(const CNode&);
public:
int GetRefCount()
{
return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
}
- CNode* AddRef(int64 nTimeout=0)
+ CNode* AddRef(int64_t nTimeout=0)
{
if (nTimeout != 0)
nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
else
nRefCount++;
return this;
}
void Release()
{
nRefCount--;
}
void AddAddressKnown(const CAddress& addr)
{
setAddrKnown.insert(addr);
}
void PushAddress(const CAddress& addr)
{
// Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added
// after addresses were pushed.
if (addr.IsValid() && !setAddrKnown.count(addr))
vAddrToSend.push_back(addr);
}
void AddInventoryKnown(const CInv& inv)
{
CRITICAL_BLOCK(cs_inventory)
setInventoryKnown.insert(inv);
}
void PushInventory(const CInv& inv)
{
CRITICAL_BLOCK(cs_inventory)
if (!setInventoryKnown.count(inv))
vInventoryToSend.push_back(inv);
}
void AskFor(const CInv& inv)
{
// We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent
- int64& nRequestTime = mapAlreadyAskedFor[inv];
+ int64_t& nRequestTime = mapAlreadyAskedFor[inv];
printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
// Make sure not to reuse time indexes to keep things in the same order
- int64 nNow = (GetTime() - 1) * 1000000;
- static int64 nLastTime;
+ int64_t nNow = (GetTime() - 1) * 1000000;
+ static int64_t nLastTime;
nLastTime = nNow = std::max(nNow, ++nLastTime);
// Each retry is 2 minutes after the last
nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
mapAskFor.insert(std::make_pair(nRequestTime, inv));
}
void BeginMessage(const char* pszCommand)
{
cs_vSend.Enter("cs_vSend", __FILE__, __LINE__);
if (nHeaderStart != -1)
AbortMessage();
nHeaderStart = vSend.size();
vSend << CMessageHeader(pszCommand, 0);
nMessageStart = vSend.size();
if (fDebug) {
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("sending: %s ", pszCommand);
}
}
void AbortMessage()
{
if (nHeaderStart == -1)
return;
vSend.resize(nHeaderStart);
nHeaderStart = -1;
nMessageStart = -1;
cs_vSend.Leave();
if (fDebug)
printf("(aborted)\n");
}
void EndMessage()
{
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
printf("dropmessages DROPPING SEND MESSAGE\n");
AbortMessage();
return;
}
if (nHeaderStart == -1)
return;
// Set the size
unsigned int nSize = vSend.size() - nMessageStart;
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
// Set the checksum
if (vSend.GetVersion() >= 209)
{
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
}
if (fDebug) {
printf("(%d bytes)\n", nSize);
}
nHeaderStart = -1;
nMessageStart = -1;
cs_vSend.Leave();
}
void EndMessageAbortIfEmpty()
{
if (nHeaderStart == -1)
return;
int nSize = vSend.size() - nMessageStart;
if (nSize > 0)
EndMessage();
else
AbortMessage();
}
void PushVersion();
void PushMessage(const char* pszCommand)
{
try
{
BeginMessage(pszCommand);
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1>
void PushMessage(const char* pszCommand, const T1& a1)
{
try
{
BeginMessage(pszCommand);
vSend << a1;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
void PushRequest(const char* pszCommand,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
CRITICAL_BLOCK(cs_mapRequests)
mapRequests[hashReply] = CRequestTracker(fn, param1);
PushMessage(pszCommand, hashReply);
}
template<typename T1>
void PushRequest(const char* pszCommand, const T1& a1,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
CRITICAL_BLOCK(cs_mapRequests)
mapRequests[hashReply] = CRequestTracker(fn, param1);
PushMessage(pszCommand, hashReply, a1);
}
template<typename T1, typename T2>
void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
CRITICAL_BLOCK(cs_mapRequests)
mapRequests[hashReply] = CRequestTracker(fn, param1);
PushMessage(pszCommand, hashReply, a1, a2);
}
void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
bool IsSubscribed(unsigned int nChannel);
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel);
void CloseSocketDisconnect();
void Cleanup();
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
// badly and disconnect/ban them, but do it in a
// one-coding-mistake-won't-shatter-the-entire-network
// way.
// IMPORTANT: There should be nothing I can give a
// node that it will forward on that will make that
// node's peers drop it. If there is, an attacker
// can isolate a node and/or try to split the network.
// Dropping a node for sending stuff that is invalid
// now but might be valid in a later version is also
// dangerous, because it can cause a network split
// between nodes running old code and nodes running
// new code.
static void ClearBanned(); // needed for unit testing
static bool IsBanned(unsigned int ip);
bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
};
inline void RelayInventory(const CInv& inv)
{
// Put on lists to offer to the other nodes
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushInventory(inv);
}
template<typename T>
void RelayMessage(const CInv& inv, const T& a)
{
CDataStream ss(SER_NETWORK);
ss.reserve(10000);
ss << a;
RelayMessage(inv, ss);
}
template<>
inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
{
CRITICAL_BLOCK(cs_mapRelay)
{
// Expire old relay messages
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
{
mapRelay.erase(vRelayExpiration.front().second);
vRelayExpiration.pop_front();
}
// Save original serialized message so newer versions are preserved
mapRelay[inv] = ss;
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
}
RelayInventory(inv);
}
//
// Templates for the publish and subscription system.
// The object being published as T& obj needs to have:
// a set<unsigned int> setSources member
// specializations of AdvertInsert and AdvertErase
// Currently implemented for CTable and CProduct.
//
template<typename T>
void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
{
// Add to sources
obj.setSources.insert(pfrom->addr.ip);
if (!AdvertInsert(obj))
return;
// Relay
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
pnode->PushMessage("publish", nChannel, nHops, obj);
}
template<typename T>
void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
{
uint256 hash = obj.GetHash();
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
AdvertErase(obj);
}
template<typename T>
void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
{
// Remove a source
obj.setSources.erase(pfrom->addr.ip);
// If no longer supported by any sources, cancel it
if (obj.setSources.empty())
AdvertStopPublish(pfrom, nChannel, nHops, obj);
}
#endif
diff --git a/src/noui.h b/src/noui.h
index 754c2225fc..5f6cc752b0 100644
--- a/src/noui.h
+++ b/src/noui.h
@@ -1,74 +1,76 @@
// Copyright (c) 2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_NOUI_H
#define BITCOIN_NOUI_H
+#include <stdint.h>
+
#include <string>
#include <boost/function.hpp>
#include "wallet.h"
typedef void wxWindow;
#define wxYES 0x00000002
#define wxOK 0x00000004
#define wxNO 0x00000008
#define wxYES_NO (wxYES|wxNO)
#define wxCANCEL 0x00000010
#define wxAPPLY 0x00000020
#define wxCLOSE 0x00000040
#define wxOK_DEFAULT 0x00000000
#define wxYES_DEFAULT 0x00000000
#define wxNO_DEFAULT 0x00000080
#define wxCANCEL_DEFAULT 0x80000000
#define wxICON_EXCLAMATION 0x00000100
#define wxICON_HAND 0x00000200
#define wxICON_WARNING wxICON_EXCLAMATION
#define wxICON_ERROR wxICON_HAND
#define wxICON_QUESTION 0x00000400
#define wxICON_INFORMATION 0x00000800
#define wxICON_STOP wxICON_HAND
#define wxICON_ASTERISK wxICON_INFORMATION
#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800)
#define wxFORWARD 0x00001000
#define wxBACKWARD 0x00002000
#define wxRESET 0x00004000
#define wxHELP 0x00008000
#define wxMORE 0x00010000
#define wxSETUP 0x00020000
inline int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
{
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
return 4;
}
#define wxMessageBox MyMessageBox
inline int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
{
return MyMessageBox(message, caption, style, parent, x, y);
}
-inline bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
+inline bool ThreadSafeAskFee(int64_t nFeeRequired, const std::string& strCaption, wxWindow* parent)
{
return true;
}
inline void CalledSetStatusBar(const std::string& strText, int nField)
{
}
inline void UIThreadCall(boost::function0<void> fn)
{
}
inline void MainFrameRepaint()
{
}
inline void InitMessage(const std::string &message)
{
}
#endif
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 27efb8f293..8e588652de 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -1,312 +1,314 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "protocol.h"
#include "util.h"
#ifndef WIN32
# include <arpa/inet.h>
#endif
// Prototypes from net.h, but that header (currently) stinks, can't #include it without breaking things
bool Lookup(const char *pszName, std::vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false);
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
static const char* ppszTypeName[] =
{
"ERROR",
"tx",
"block",
};
CMessageHeader::CMessageHeader()
{
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
memset(pchCommand, 0, sizeof(pchCommand));
pchCommand[1] = 1;
nMessageSize = -1;
nChecksum = 0;
}
CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
{
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
strncpy(pchCommand, pszCommand, COMMAND_SIZE);
nMessageSize = nMessageSizeIn;
nChecksum = 0;
}
std::string CMessageHeader::GetCommand() const
{
if (pchCommand[COMMAND_SIZE-1] == 0)
return std::string(pchCommand, pchCommand + strlen(pchCommand));
else
return std::string(pchCommand, pchCommand + COMMAND_SIZE);
}
bool CMessageHeader::IsValid() const
{
// Check start string
if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
return false;
// Check the command string for errors
for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
{
if (*p1 == 0)
{
// Must be all zeros after the first zero
for (; p1 < pchCommand + COMMAND_SIZE; p1++)
if (*p1 != 0)
return false;
}
else if (*p1 < ' ' || *p1 > 0x7E)
return false;
}
// Message size
if (nMessageSize > MAX_SIZE)
{
printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize);
return false;
}
return true;
}
CAddress::CAddress()
{
Init();
}
-CAddress::CAddress(unsigned int ipIn, unsigned short portIn, uint64 nServicesIn)
+CAddress::CAddress(unsigned int ipIn, unsigned short portIn, uint64_t nServicesIn)
{
Init();
ip = ipIn;
port = htons(portIn == 0 ? GetDefaultPort() : portIn);
nServices = nServicesIn;
}
-CAddress::CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn)
+CAddress::CAddress(const struct sockaddr_in& sockaddr, uint64_t nServicesIn)
{
Init();
ip = sockaddr.sin_addr.s_addr;
port = sockaddr.sin_port;
nServices = nServicesIn;
}
-CAddress::CAddress(const char* pszIn, int portIn, bool fNameLookup, uint64 nServicesIn)
+CAddress::CAddress(const char* pszIn, int portIn, bool fNameLookup, uint64_t nServicesIn)
{
Init();
Lookup(pszIn, *this, nServicesIn, fNameLookup, portIn);
}
-CAddress::CAddress(const char* pszIn, bool fNameLookup, uint64 nServicesIn)
+CAddress::CAddress(const char* pszIn, bool fNameLookup, uint64_t nServicesIn)
{
Init();
Lookup(pszIn, *this, nServicesIn, fNameLookup, 0, true);
}
-CAddress::CAddress(std::string strIn, int portIn, bool fNameLookup, uint64 nServicesIn)
+CAddress::CAddress(std::string strIn, int portIn, bool fNameLookup, uint64_t nServicesIn)
{
Init();
Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, portIn);
}
-CAddress::CAddress(std::string strIn, bool fNameLookup, uint64 nServicesIn)
+CAddress::CAddress(std::string strIn, bool fNameLookup, uint64_t nServicesIn)
{
Init();
Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, 0, true);
}
void CAddress::Init()
{
nServices = NODE_NETWORK;
memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
ip = INADDR_NONE;
port = htons(GetDefaultPort());
nTime = 100000000;
nLastTry = 0;
}
bool operator==(const CAddress& a, const CAddress& b)
{
return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
a.ip == b.ip &&
a.port == b.port);
}
bool operator!=(const CAddress& a, const CAddress& b)
{
return (!(a == b));
}
bool operator<(const CAddress& a, const CAddress& b)
{
int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
if (ret < 0)
return true;
else if (ret == 0)
{
if (ntohl(a.ip) < ntohl(b.ip))
return true;
else if (a.ip == b.ip)
return ntohs(a.port) < ntohs(b.port);
}
return false;
}
std::vector<unsigned char> CAddress::GetKey() const
{
CDataStream ss;
ss.reserve(18);
ss << FLATDATA(pchReserved) << ip << port;
#if defined(_MSC_VER) && _MSC_VER < 1300
return std::vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
#else
return std::vector<unsigned char>(ss.begin(), ss.end());
#endif
}
struct sockaddr_in CAddress::GetSockAddr() const
{
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = ip;
sockaddr.sin_port = port;
return sockaddr;
}
bool CAddress::IsIPv4() const
{
return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
}
bool CAddress::IsRFC1918() const
{
return IsIPv4() && (GetByte(3) == 10 ||
(GetByte(3) == 192 && GetByte(2) == 168) ||
(GetByte(3) == 172 &&
(GetByte(2) >= 16 && GetByte(2) <= 31)));
}
bool CAddress::IsRFC3927() const
{
return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
}
bool CAddress::IsLocal() const
{
return IsIPv4() && (GetByte(3) == 127 ||
GetByte(3) == 0);
}
bool CAddress::IsRoutable() const
{
return IsValid() &&
!(IsRFC1918() || IsRFC3927() || IsLocal());
}
bool CAddress::IsValid() const
{
// Clean up 3-byte shifted addresses caused by garbage in size field
// of addr messages from versions before 0.2.9 checksum.
// Two consecutive addr messages look like this:
// header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
// so if the first length field is garbled, it reads the second batch
// of addr misaligned by 3 bytes.
if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
return false;
return (ip != 0 && ip != INADDR_NONE && port != htons(std::numeric_limits<unsigned short>::max()));
}
unsigned char CAddress::GetByte(int n) const
{
return ((unsigned char*)&ip)[3-n];
}
std::string CAddress::ToStringIPPort() const
{
return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
}
std::string CAddress::ToStringIP() const
{
return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
}
std::string CAddress::ToStringPort() const
{
return strprintf("%u", ntohs(port));
}
std::string CAddress::ToString() const
{
return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
}
void CAddress::print() const
{
printf("CAddress(%s)\n", ToString().c_str());
}
CInv::CInv()
{
type = 0;
hash = 0;
}
CInv::CInv(int typeIn, const uint256& hashIn)
{
type = typeIn;
hash = hashIn;
}
CInv::CInv(const std::string& strType, const uint256& hashIn)
{
int i;
for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
{
if (strType == ppszTypeName[i])
{
type = i;
break;
}
}
if (i == ARRAYLEN(ppszTypeName))
throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
hash = hashIn;
}
bool operator<(const CInv& a, const CInv& b)
{
return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
}
bool CInv::IsKnownType() const
{
return (type >= 1 && type < ARRAYLEN(ppszTypeName));
}
const char* CInv::GetCommand() const
{
if (!IsKnownType())
throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
return ppszTypeName[type];
}
std::string CInv::ToString() const
{
return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
}
void CInv::print() const
{
printf("CInv(%s)\n", ToString().c_str());
}
diff --git a/src/protocol.h b/src/protocol.h
index 53d3eef4d5..4d1b329514 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,150 +1,152 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef __cplusplus
# error This header can only be compiled as C++.
#endif
#ifndef __INCLUDED_PROTOCOL_H__
#define __INCLUDED_PROTOCOL_H__
+#include <stdint.h>
+
#include "serialize.h"
#include <string>
#include "uint256.h"
extern bool fTestNet;
static inline unsigned short GetDefaultPort(const bool testnet = fTestNet)
{
return testnet ? 18333 : 8333;
}
//
// Message header
// (4) message start
// (12) command
// (4) size
// (4) checksum
extern unsigned char pchMessageStart[4];
class CMessageHeader
{
public:
CMessageHeader();
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn);
std::string GetCommand() const;
bool IsValid() const;
IMPLEMENT_SERIALIZE
(
READWRITE(FLATDATA(pchMessageStart));
READWRITE(FLATDATA(pchCommand));
READWRITE(nMessageSize);
if (nVersion >= 209)
READWRITE(nChecksum);
)
// TODO: make private (improves encapsulation)
public:
enum { COMMAND_SIZE=12 };
char pchMessageStart[sizeof(::pchMessageStart)];
char pchCommand[COMMAND_SIZE];
unsigned int nMessageSize;
unsigned int nChecksum;
};
enum
{
NODE_NETWORK = (1 << 0),
};
class CAddress
{
public:
CAddress();
- CAddress(unsigned int ipIn, unsigned short portIn=0, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(const char* pszIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(const char* pszIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(std::string strIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
- explicit CAddress(std::string strIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK);
+ CAddress(unsigned int ipIn, unsigned short portIn=0, uint64_t nServicesIn=NODE_NETWORK);
+ explicit CAddress(const struct sockaddr_in& sockaddr, uint64_t nServicesIn=NODE_NETWORK);
+ explicit CAddress(const char* pszIn, int portIn, bool fNameLookup = false, uint64_t nServicesIn=NODE_NETWORK);
+ explicit CAddress(const char* pszIn, bool fNameLookup = false, uint64_t nServicesIn=NODE_NETWORK);
+ explicit CAddress(std::string strIn, int portIn, bool fNameLookup = false, uint64_t nServicesIn=NODE_NETWORK);
+ explicit CAddress(std::string strIn, bool fNameLookup = false, uint64_t nServicesIn=NODE_NETWORK);
void Init();
IMPLEMENT_SERIALIZE
(
if (fRead)
const_cast<CAddress*>(this)->Init();
if (nType & SER_DISK)
READWRITE(nVersion);
if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH)))
READWRITE(nTime);
READWRITE(nServices);
READWRITE(FLATDATA(pchReserved)); // for IPv6
READWRITE(ip);
READWRITE(port);
)
friend bool operator==(const CAddress& a, const CAddress& b);
friend bool operator!=(const CAddress& a, const CAddress& b);
friend bool operator<(const CAddress& a, const CAddress& b);
std::vector<unsigned char> GetKey() const;
struct sockaddr_in GetSockAddr() const;
bool IsIPv4() const;
bool IsRFC1918() const;
bool IsRFC3927() const;
bool IsLocal() const;
bool IsRoutable() const;
bool IsValid() const;
unsigned char GetByte(int n) const;
std::string ToStringIPPort() const;
std::string ToStringIP() const;
std::string ToStringPort() const;
std::string ToString() const;
void print() const;
// TODO: make private (improves encapsulation)
public:
- uint64 nServices;
+ uint64_t nServices;
unsigned char pchReserved[12];
unsigned int ip;
unsigned short port;
// disk and network only
unsigned int nTime;
// memory only
unsigned int nLastTry;
};
class CInv
{
public:
CInv();
CInv(int typeIn, const uint256& hashIn);
CInv(const std::string& strType, const uint256& hashIn);
IMPLEMENT_SERIALIZE
(
READWRITE(type);
READWRITE(hash);
)
friend bool operator<(const CInv& a, const CInv& b);
bool IsKnownType() const;
const char* GetCommand() const;
std::string ToString() const;
void print() const;
// TODO: make private (improves encapsulation)
public:
int type;
uint256 hash;
};
#endif // __INCLUDED_PROTOCOL_H__
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index cba4e851b4..f696ca0f89 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -1,203 +1,204 @@
/*
* W.J. van der Laan 2011
*/
#include "bitcoingui.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "headers.h"
#include "init.h"
+#include <QtGlobal>
#include <QApplication>
#include <QMessageBox>
#include <QThread>
#include <QTextCodec>
#include <QLocale>
#include <QTranslator>
#include <QSplashScreen>
#include <QLibraryInfo>
// Need a global reference for the notifications to find the GUI
BitcoinGUI *guiref;
QSplashScreen *splashref;
int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
{
// Message from main thread
if(guiref)
{
guiref->error(QString::fromStdString(caption),
QString::fromStdString(message));
}
else
{
QMessageBox::critical(0, QString::fromStdString(caption),
QString::fromStdString(message),
QMessageBox::Ok, QMessageBox::Ok);
}
return 4;
}
int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
{
// Message from network thread
if(guiref)
{
QMetaObject::invokeMethod(guiref, "error", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)));
}
else
{
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
}
return 4;
}
-bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
+bool ThreadSafeAskFee(qint64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
{
if(!guiref)
return false;
if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
return true;
bool payFee = false;
// Call slot on GUI thread.
// If called from another thread, use a blocking QueuedConnection.
Qt::ConnectionType connectionType = Qt::DirectConnection;
if(QThread::currentThread() != QCoreApplication::instance()->thread())
{
connectionType = Qt::BlockingQueuedConnection;
}
QMetaObject::invokeMethod(guiref, "askFee", connectionType,
Q_ARG(qint64, nFeeRequired),
Q_ARG(bool*, &payFee));
return payFee;
}
void CalledSetStatusBar(const std::string& strText, int nField)
{
// Only used for built-in mining, which is disabled, simple ignore
}
void UIThreadCall(boost::function0<void> fn)
{
// Only used for built-in mining, which is disabled, simple ignore
}
void MainFrameRepaint()
{
if(guiref)
QMetaObject::invokeMethod(guiref, "refreshStatusBar", Qt::QueuedConnection);
}
void InitMessage(const std::string &message)
{
if(splashref)
{
splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(255,255,200));
QApplication::instance()->processEvents();
}
}
/*
Translate string to current locale using Qt.
*/
std::string _(const char* psz)
{
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
}
int main(int argc, char *argv[])
{
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
Q_INIT_RESOURCE(bitcoin);
QApplication app(argc, argv);
ParseParameters(argc, argv);
// Load language files for system locale:
// - First load the translator for the base language, without territory
// - Then load the more specific locale translator
QString lang_territory = QLocale::system().name(); // "en_US"
QString lang = lang_territory;
lang.truncate(lang_territory.lastIndexOf('_')); // "en"
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
qtTranslatorBase.load(QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" + lang);
if (!qtTranslatorBase.isEmpty())
app.installTranslator(&qtTranslatorBase);
qtTranslator.load(QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" + lang_territory);
if (!qtTranslator.isEmpty())
app.installTranslator(&qtTranslator);
translatorBase.load(":/translations/"+lang);
if (!translatorBase.isEmpty())
app.installTranslator(&translatorBase);
translator.load(":/translations/"+lang_territory);
if (!translator.isEmpty())
app.installTranslator(&translator);
app.setApplicationName(QApplication::translate("main", "Bitcoin-Qt"));
QSplashScreen splash(QPixmap(":/images/splash"), 0);
splash.show();
splash.setAutoFillBackground(true);
splashref = &splash;
app.processEvents();
app.setQuitOnLastWindowClosed(false);
try
{
if(AppInit2(argc, argv))
{
{
// Put this in a block, so that BitcoinGUI is cleaned up properly before
// calling Shutdown() in case of exceptions.
BitcoinGUI window;
splash.finish(&window);
OptionsModel optionsModel(pwalletMain);
ClientModel clientModel(&optionsModel);
WalletModel walletModel(pwalletMain, &optionsModel);
guiref = &window;
window.setClientModel(&clientModel);
window.setWalletModel(&walletModel);
// If -min option passed, start window minimized.
if(GetBoolArg("-min"))
{
window.showMinimized();
}
else
{
window.show();
}
app.exec();
guiref = 0;
}
Shutdown(NULL);
}
else
{
return 1;
}
} catch (std::exception& e) {
PrintException(&e, "Runaway exception");
} catch (...) {
PrintException(NULL, "Runaway exception");
}
return 0;
}
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index 19cd5655cc..f385bc55e8 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -1,167 +1,168 @@
#include "bitcoinamountfield.h"
#include "qvaluecombobox.h"
#include "bitcoinunits.h"
#include "guiconstants.h"
+#include <QtGlobal>
#include <QLabel>
#include <QLineEdit>
#include <QRegExpValidator>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QApplication>
#include <qmath.h>
BitcoinAmountField::BitcoinAmountField(QWidget *parent):
QWidget(parent), amount(0), currentUnit(-1)
{
amount = new QDoubleSpinBox(this);
amount->setLocale(QLocale::c());
amount->setDecimals(8);
amount->installEventFilter(this);
amount->setMaximumWidth(170);
QHBoxLayout *layout = new QHBoxLayout(this);
layout->addWidget(amount);
unit = new QValueComboBox(this);
unit->setModel(new BitcoinUnits(this));
layout->addWidget(unit);
layout->addStretch(1);
layout->setContentsMargins(0,0,0,0);
setLayout(layout);
setFocusPolicy(Qt::TabFocus);
setFocusProxy(amount);
// If one if the widgets changes, the combined content changes as well
connect(amount, SIGNAL(valueChanged(QString)), this, SIGNAL(textChanged()));
connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
// Set default based on configuration
unitChanged(unit->currentIndex());
}
void BitcoinAmountField::setText(const QString &text)
{
if (text.isEmpty())
amount->clear();
else
amount->setValue(text.toDouble());
}
void BitcoinAmountField::clear()
{
amount->clear();
unit->setCurrentIndex(0);
}
bool BitcoinAmountField::validate()
{
bool valid = true;
if (amount->value() == 0.0)
valid = false;
if (valid && !BitcoinUnits::parse(currentUnit, text(), 0))
valid = false;
setValid(valid);
return valid;
}
void BitcoinAmountField::setValid(bool valid)
{
if (valid)
amount->setStyleSheet("");
else
amount->setStyleSheet(STYLE_INVALID);
}
QString BitcoinAmountField::text() const
{
if (amount->text().isEmpty())
return QString();
else
return amount->text();
}
bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::FocusIn)
{
// Clear invalid flag on focus
setValid(true);
}
else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Comma)
{
// Translate a comma into a period
QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count());
qApp->sendEvent(object, &periodKeyEvent);
return true;
}
}
return QWidget::eventFilter(object, event);
}
QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
{
QWidget::setTabOrder(prev, amount);
return amount;
}
qint64 BitcoinAmountField::value(bool *valid_out) const
{
qint64 val_out = 0;
bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
if(valid_out)
{
*valid_out = valid;
}
return val_out;
}
void BitcoinAmountField::setValue(qint64 value)
{
setText(BitcoinUnits::format(currentUnit, value));
}
void BitcoinAmountField::unitChanged(int idx)
{
// Use description tooltip for current unit for the combobox
unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
// Determine new unit ID
int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
// Parse current value and convert to new unit
bool valid = false;
qint64 currentValue = value(&valid);
currentUnit = newUnit;
// Set max length after retrieving the value, to prevent truncation
amount->setDecimals(BitcoinUnits::decimals(currentUnit));
amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals()));
if(valid)
{
// If value was valid, re-place it in the widget with the new unit
setValue(currentValue);
}
else
{
// If current value is invalid, just clear field
setText("");
}
setValid(true);
}
void BitcoinAmountField::setDisplayUnit(int newUnit)
{
unit->setValue(newUnit);
}
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index ead8bdb84b..954ed1ebd0 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -1,60 +1,61 @@
#ifndef BITCOINFIELD_H
#define BITCOINFIELD_H
+#include <QtGlobal>
#include <QWidget>
QT_BEGIN_NAMESPACE
class QDoubleSpinBox;
class QValueComboBox;
QT_END_NAMESPACE
/** Widget for entering bitcoin amounts.
*/
class BitcoinAmountField: public QWidget
{
Q_OBJECT
Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY textChanged USER true)
public:
explicit BitcoinAmountField(QWidget *parent = 0);
qint64 value(bool *valid=0) const;
void setValue(qint64 value);
/** Mark current value as invalid in UI. */
void setValid(bool valid);
/** Perform input validation, mark field as invalid if entered value is not valid. */
bool validate();
/** Change unit used to display amount. */
void setDisplayUnit(int unit);
/** Make field empty and ready for new input. */
void clear();
/** Qt messes up the tab chain by default in some cases (issue http://bugreports.qt.nokia.com/browse/QTBUG-10907),
in these cases we have to set it up manually.
*/
QWidget *setupTabChain(QWidget *prev);
signals:
void textChanged();
protected:
/** Intercept focus-in event and ',' keypresses */
bool eventFilter(QObject *object, QEvent *event);
private:
QDoubleSpinBox *amount;
QValueComboBox *unit;
int currentUnit;
void setText(const QString &text);
QString text() const;
private slots:
void unitChanged(int idx);
};
#endif // BITCOINFIELD_H
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 1c49683364..fa317a25ef 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1,734 +1,735 @@
/*
* Qt4 bitcoin GUI.
*
* W.J. van der Laan 2011
* The Bitcoin Developers 2011
*/
#include "bitcoingui.h"
#include "transactiontablemodel.h"
#include "addressbookpage.h"
#include "sendcoinsdialog.h"
#include "optionsdialog.h"
#include "aboutdialog.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "editaddressdialog.h"
#include "optionsmodel.h"
#include "transactiondescdialog.h"
#include "addresstablemodel.h"
#include "transactionview.h"
#include "overviewpage.h"
#include "bitcoinunits.h"
#include "guiconstants.h"
#include "askpassphrasedialog.h"
#include "notificator.h"
#ifdef Q_WS_MAC
#include "macdockiconhandler.h"
#endif
+#include <QtGlobal>
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QIcon>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QToolBar>
#include <QStatusBar>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QLocale>
#include <QMessageBox>
#include <QProgressBar>
#include <QStackedWidget>
#include <QDateTime>
#include <QMovie>
#include <QDragEnterEvent>
#include <QUrl>
#include <iostream>
BitcoinGUI::BitcoinGUI(QWidget *parent):
QMainWindow(parent),
clientModel(0),
walletModel(0),
encryptWalletAction(0),
changePassphraseAction(0),
aboutQtAction(0),
trayIcon(0),
notificator(0)
{
resize(850, 550);
setWindowTitle(tr("Bitcoin Wallet"));
#ifndef Q_WS_MAC
setWindowIcon(QIcon(":icons/bitcoin"));
#else
setUnifiedTitleAndToolBarOnMac(true);
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
#endif
// Accept D&D of URIs
setAcceptDrops(true);
// Create actions for the toolbar, menu bar and tray/dock icon
createActions();
// Create application menu bar
createMenuBar();
// Create the toolbars
createToolBars();
// Create the tray icon (or setup the dock icon)
createTrayIcon();
// Create tabs
overviewPage = new OverviewPage();
transactionsPage = new QWidget(this);
QVBoxLayout *vbox = new QVBoxLayout();
transactionView = new TransactionView(this);
vbox->addWidget(transactionView);
transactionsPage->setLayout(vbox);
addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab);
receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab);
sendCoinsPage = new SendCoinsDialog(this);
centralWidget = new QStackedWidget(this);
centralWidget->addWidget(overviewPage);
centralWidget->addWidget(transactionsPage);
centralWidget->addWidget(addressBookPage);
centralWidget->addWidget(receiveCoinsPage);
centralWidget->addWidget(sendCoinsPage);
setCentralWidget(centralWidget);
// Create status bar
statusBar();
// Status bar notification icons
QFrame *frameBlocks = new QFrame();
//frameBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken);
frameBlocks->setContentsMargins(0,0,0,0);
frameBlocks->setMinimumWidth(56);
frameBlocks->setMaximumWidth(56);
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
labelEncryptionIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelEncryptionIcon);
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelConnectionsIcon);
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelBlocksIcon);
frameBlocksLayout->addStretch();
// Progress bar for blocks download
progressBarLabel = new QLabel(tr("Synchronizing with network..."));
progressBarLabel->setVisible(false);
progressBar = new QProgressBar();
progressBar->setToolTip(tr("Block chain synchronization in progress"));
progressBar->setVisible(false);
statusBar()->addWidget(progressBarLabel);
statusBar()->addWidget(progressBar);
statusBar()->addPermanentWidget(frameBlocks);
syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this);
// Clicking on a transaction on the overview page simply sends you to transaction history page
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage()));
// Doubleclicking on a transaction on the transaction history page shows details
connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
gotoOverviewPage();
}
BitcoinGUI::~BitcoinGUI()
{
#ifdef Q_WS_MAC
delete appMenuBar;
#endif
}
void BitcoinGUI::createActions()
{
QActionGroup *tabGroup = new QActionGroup(this);
overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
overviewAction->setToolTip(tr("Show general overview of wallet"));
overviewAction->setCheckable(true);
overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
tabGroup->addAction(overviewAction);
historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
historyAction->setToolTip(tr("Browse transaction history"));
historyAction->setCheckable(true);
historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
tabGroup->addAction(historyAction);
addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels"));
addressBookAction->setCheckable(true);
addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5));
tabGroup->addAction(addressBookAction);
receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this);
receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments"));
receiveCoinsAction->setCheckable(true);
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
sendCoinsAction->setToolTip(tr("Send coins to a bitcoin address"));
sendCoinsAction->setCheckable(true);
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
connect(overviewAction, SIGNAL(triggered()), this, SLOT(show()));
connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(show()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
connect(addressBookAction, SIGNAL(triggered()), this, SLOT(show()));
connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(show()));
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(show()));
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
quitAction->setToolTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About %1").arg(qApp->applicationName()), this);
aboutAction->setToolTip(tr("Show information about Bitcoin"));
aboutAction->setMenuRole(QAction::AboutRole);
aboutQtAction = new QAction(tr("About &Qt"), this);
aboutQtAction->setToolTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setToolTip(tr("Modify configuration options for bitcoin"));
optionsAction->setMenuRole(QAction::PreferencesRole);
openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
exportAction->setToolTip(tr("Export the current view to a file"));
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
encryptWalletAction->setCheckable(true);
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase"), this);
changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormal()));
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
}
void BitcoinGUI::createMenuBar()
{
#ifdef Q_WS_MAC
// Create a decoupled menu bar on Mac which stays even if the window is closed
appMenuBar = new QMenuBar();
#else
// Get the main window's menu bar on other platforms
appMenuBar = menuBar();
#endif
// Configure the menus
QMenu *file = appMenuBar->addMenu(tr("&File"));
file->addAction(quitAction);
QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
settings->addAction(encryptWalletAction);
settings->addAction(changePassphraseAction);
settings->addSeparator();
settings->addAction(optionsAction);
QMenu *help = appMenuBar->addMenu(tr("&Help"));
help->addAction(aboutAction);
help->addAction(aboutQtAction);
}
void BitcoinGUI::createToolBars()
{
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar->addAction(overviewAction);
toolbar->addAction(sendCoinsAction);
toolbar->addAction(receiveCoinsAction);
toolbar->addAction(historyAction);
toolbar->addAction(addressBookAction);
QToolBar *toolbar2 = addToolBar(tr("Actions toolbar"));
toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar2->addAction(exportAction);
}
void BitcoinGUI::setClientModel(ClientModel *clientModel)
{
this->clientModel = clientModel;
if(clientModel)
{
if(clientModel->isTestNet())
{
QString title_testnet = windowTitle() + QString(" ") + tr("[testnet]");
setWindowTitle(title_testnet);
#ifndef Q_WS_MAC
setWindowIcon(QIcon(":icons/bitcoin_testnet"));
#else
MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
#endif
if(trayIcon)
{
trayIcon->setToolTip(title_testnet);
trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
}
}
// Keep up to date with client
setNumConnections(clientModel->getNumConnections());
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
setNumBlocks(clientModel->getNumBlocks());
connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
// Report errors from network/worker thread
connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
}
}
void BitcoinGUI::setWalletModel(WalletModel *walletModel)
{
this->walletModel = walletModel;
if(walletModel)
{
// Report errors from wallet thread
connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
// Put transaction list in tabs
transactionView->setModel(walletModel);
overviewPage->setModel(walletModel);
addressBookPage->setModel(walletModel->getAddressTableModel());
receiveCoinsPage->setModel(walletModel->getAddressTableModel());
sendCoinsPage->setModel(walletModel);
setEncryptionStatus(walletModel->getEncryptionStatus());
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
// Balloon popup for new transaction
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(incomingTransaction(QModelIndex,int,int)));
// Ask for passphrase if needed
connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
}
}
void BitcoinGUI::createTrayIcon()
{
QMenu *trayIconMenu;
#ifndef Q_WS_MAC
trayIcon = new QSystemTrayIcon(this);
trayIconMenu = new QMenu(this);
trayIcon->setContextMenu(trayIconMenu);
trayIcon->setToolTip("Bitcoin client");
trayIcon->setIcon(QIcon(":/icons/toolbar"));
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
trayIcon->show();
#else
// Note: On Mac, the dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
connect(dockIconHandler, SIGNAL(dockIconClicked()), openBitcoinAction, SLOT(trigger()));
trayIconMenu = dockIconHandler->dockMenu();
#endif
// Configuration of the tray icon (or dock icon) icon menu
trayIconMenu->addAction(openBitcoinAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(receiveCoinsAction);
trayIconMenu->addAction(sendCoinsAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(optionsAction);
#ifndef Q_WS_MAC // This is built-in on Mac
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
#endif
notificator = new Notificator(tr("bitcoin-qt"), trayIcon);
}
#ifndef Q_WS_MAC
void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
{
if(reason == QSystemTrayIcon::Trigger)
{
// Click on system tray icon triggers "open bitcoin"
openBitcoinAction->trigger();
}
}
#endif
void BitcoinGUI::optionsClicked()
{
if(!clientModel || !clientModel->getOptionsModel())
return;
OptionsDialog dlg;
dlg.setModel(clientModel->getOptionsModel());
dlg.exec();
}
void BitcoinGUI::aboutClicked()
{
AboutDialog dlg;
dlg.setModel(clientModel);
dlg.exec();
}
void BitcoinGUI::setNumConnections(int count)
{
QString icon;
switch(count)
{
case 0: icon = ":/icons/connect_0"; break;
case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
default: icon = ":/icons/connect_4"; break;
}
labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
}
void BitcoinGUI::setNumBlocks(int count)
{
if(!clientModel)
return;
int initTotal = clientModel->getNumBlocksAtStartup();
int total = clientModel->getNumBlocksOfPeers();
QString tooltip;
if(count < total)
{
if (clientModel->getStatusBarWarnings() == "")
{
progressBarLabel->setVisible(true);
progressBarLabel->setText(tr("Synchronizing with network..."));
progressBar->setVisible(true);
progressBar->setMaximum(total - initTotal);
progressBar->setValue(count - initTotal);
}
else
{
progressBarLabel->setText(clientModel->getStatusBarWarnings());
progressBarLabel->setVisible(true);
progressBar->setVisible(false);
}
tooltip = tr("Downloaded %1 of %2 blocks of transaction history.").arg(count).arg(total);
}
else
{
if (clientModel->getStatusBarWarnings() == "")
progressBarLabel->setVisible(false);
else
{
progressBarLabel->setText(clientModel->getStatusBarWarnings());
progressBarLabel->setVisible(true);
}
progressBar->setVisible(false);
tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count);
}
QDateTime now = QDateTime::currentDateTime();
QDateTime lastBlockDate = clientModel->getLastBlockDate();
int secs = lastBlockDate.secsTo(now);
QString text;
// Represent time from last generated block in human readable text
if(secs < 60)
{
text = tr("%n second(s) ago","",secs);
}
else if(secs < 60*60)
{
text = tr("%n minute(s) ago","",secs/60);
}
else if(secs < 24*60*60)
{
text = tr("%n hour(s) ago","",secs/(60*60));
}
else
{
text = tr("%n day(s) ago","",secs/(60*60*24));
}
// Set icon state: spinning if catching up, tick otherwise
if(secs < 30*60)
{
tooltip = tr("Up to date") + QString("\n") + tooltip;
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
}
else
{
tooltip = tr("Catching up...") + QString("\n") + tooltip;
labelBlocksIcon->setMovie(syncIconMovie);
syncIconMovie->start();
}
tooltip += QString("\n");
tooltip += tr("Last received block was generated %1.").arg(text);
labelBlocksIcon->setToolTip(tooltip);
progressBarLabel->setToolTip(tooltip);
progressBar->setToolTip(tooltip);
}
void BitcoinGUI::refreshStatusBar()
{
/* Might display multiple times in the case of multiple alerts
static QString prevStatusBar;
QString newStatusBar = clientModel->getStatusBarWarnings();
if (prevStatusBar != newStatusBar)
{
prevStatusBar = newStatusBar;
error(tr("Network Alert"), newStatusBar);
}*/
setNumBlocks(clientModel->getNumBlocks());
}
void BitcoinGUI::error(const QString &title, const QString &message)
{
// Report errors from network/worker thread
notificator->notify(Notificator::Critical, title, message);
}
void BitcoinGUI::changeEvent(QEvent *e)
{
#ifndef Q_WS_MAC // Ignored on Mac
if(e->type() == QEvent::WindowStateChange)
{
if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray())
{
if(isMinimized())
{
hide();
e->ignore();
}
else
{
show();
e->accept();
}
}
}
#endif
QMainWindow::changeEvent(e);
}
void BitcoinGUI::closeEvent(QCloseEvent *event)
{
if(clientModel)
{
#ifndef Q_WS_MAC // Ignored on Mac
if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
!clientModel->getOptionsModel()->getMinimizeOnClose())
{
qApp->quit();
}
#endif
}
QMainWindow::closeEvent(event);
}
void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
{
QString strMessage =
tr("This transaction is over the size limit. You can still send it for a fee of %1, "
"which goes to the nodes that process your transaction and helps to support the network. "
"Do you want to pay the fee?").arg(
BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
QMessageBox::StandardButton retval = QMessageBox::question(
this, tr("Sending..."), strMessage,
QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
*payFee = (retval == QMessageBox::Yes);
}
void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end)
{
if(!walletModel || !clientModel)
return;
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
.data(Qt::EditRole).toULongLong();
if(!clientModel->inInitialBlockDownload())
{
// On new transaction, make an info balloon
// Unless the initial block download is in progress, to prevent balloon-spam
QString date = ttm->index(start, TransactionTableModel::Date, parent)
.data().toString();
QString type = ttm->index(start, TransactionTableModel::Type, parent)
.data().toString();
QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
.data().toString();
QIcon icon = qvariant_cast<QIcon>(ttm->index(start,
TransactionTableModel::ToAddress, parent)
.data(Qt::DecorationRole));
notificator->notify(Notificator::Information,
(amount)<0 ? tr("Sent transaction") :
tr("Incoming transaction"),
tr("Date: %1\n"
"Amount: %2\n"
"Type: %3\n"
"Address: %4\n")
.arg(date)
.arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true))
.arg(type)
.arg(address), icon);
}
}
void BitcoinGUI::gotoOverviewPage()
{
overviewAction->setChecked(true);
centralWidget->setCurrentWidget(overviewPage);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
}
void BitcoinGUI::gotoHistoryPage()
{
historyAction->setChecked(true);
centralWidget->setCurrentWidget(transactionsPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked()));
}
void BitcoinGUI::gotoAddressBookPage()
{
addressBookAction->setChecked(true);
centralWidget->setCurrentWidget(addressBookPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked()));
}
void BitcoinGUI::gotoReceiveCoinsPage()
{
receiveCoinsAction->setChecked(true);
centralWidget->setCurrentWidget(receiveCoinsPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked()));
}
void BitcoinGUI::gotoSendCoinsPage()
{
sendCoinsAction->setChecked(true);
centralWidget->setCurrentWidget(sendCoinsPage);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
}
void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
{
// Accept only URLs
if(event->mimeData()->hasUrls())
event->acceptProposedAction();
}
void BitcoinGUI::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasUrls())
{
gotoSendCoinsPage();
QList<QUrl> urls = event->mimeData()->urls();
foreach(const QUrl &url, urls)
{
sendCoinsPage->handleURL(&url);
}
}
event->acceptProposedAction();
}
void BitcoinGUI::setEncryptionStatus(int status)
{
switch(status)
{
case WalletModel::Unencrypted:
labelEncryptionIcon->hide();
encryptWalletAction->setChecked(false);
changePassphraseAction->setEnabled(false);
encryptWalletAction->setEnabled(true);
break;
case WalletModel::Unlocked:
labelEncryptionIcon->show();
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
break;
case WalletModel::Locked:
labelEncryptionIcon->show();
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
break;
}
}
void BitcoinGUI::encryptWallet(bool status)
{
if(!walletModel)
return;
AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
AskPassphraseDialog::Decrypt, this);
dlg.setModel(walletModel);
dlg.exec();
setEncryptionStatus(walletModel->getEncryptionStatus());
}
void BitcoinGUI::changePassphrase()
{
AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
dlg.setModel(walletModel);
dlg.exec();
}
void BitcoinGUI::unlockWallet()
{
if(!walletModel)
return;
// Unlock wallet when requested by wallet model
if(walletModel->getEncryptionStatus() == WalletModel::Locked)
{
AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
dlg.setModel(walletModel);
dlg.exec();
}
}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index a0905e44ad..a0b3652fc0 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -1,160 +1,161 @@
#ifndef BITCOINGUI_H
#define BITCOINGUI_H
+#include <QtGlobal>
#include <QMainWindow>
#include <QSystemTrayIcon>
class TransactionTableModel;
class ClientModel;
class WalletModel;
class TransactionView;
class OverviewPage;
class AddressBookPage;
class SendCoinsDialog;
class Notificator;
QT_BEGIN_NAMESPACE
class QLabel;
class QLineEdit;
class QTableView;
class QAbstractItemModel;
class QModelIndex;
class QProgressBar;
class QStackedWidget;
class QUrl;
QT_END_NAMESPACE
/**
Bitcoin GUI main class. This class represents the main window of the Bitcoin UI. It communicates with both the client and
wallet models to give the user an up-to-date view of the current core state.
*/
class BitcoinGUI : public QMainWindow
{
Q_OBJECT
public:
explicit BitcoinGUI(QWidget *parent = 0);
~BitcoinGUI();
/** Set the client model.
The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic.
*/
void setClientModel(ClientModel *clientModel);
/** Set the wallet model.
The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending
functionality.
*/
void setWalletModel(WalletModel *walletModel);
protected:
void changeEvent(QEvent *e);
void closeEvent(QCloseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
private:
ClientModel *clientModel;
WalletModel *walletModel;
QStackedWidget *centralWidget;
OverviewPage *overviewPage;
QWidget *transactionsPage;
AddressBookPage *addressBookPage;
AddressBookPage *receiveCoinsPage;
SendCoinsDialog *sendCoinsPage;
QLabel *labelEncryptionIcon;
QLabel *labelConnectionsIcon;
QLabel *labelBlocksIcon;
QLabel *progressBarLabel;
QProgressBar *progressBar;
QMenuBar *appMenuBar;
QAction *overviewAction;
QAction *historyAction;
QAction *quitAction;
QAction *sendCoinsAction;
QAction *addressBookAction;
QAction *aboutAction;
QAction *receiveCoinsAction;
QAction *optionsAction;
QAction *openBitcoinAction;
QAction *exportAction;
QAction *encryptWalletAction;
QAction *changePassphraseAction;
QAction *aboutQtAction;
QSystemTrayIcon *trayIcon;
Notificator *notificator;
TransactionView *transactionView;
QMovie *syncIconMovie;
/** Create the main UI actions. */
void createActions();
/** Create the menu bar and submenus. */
void createMenuBar();
/** Create the toolbars */
void createToolBars();
/** Create system tray (notification) icon */
void createTrayIcon();
public slots:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks shown in the UI */
void setNumBlocks(int count);
/** Set the encryption status as shown in the UI.
@param[in] status current encryption status
@see WalletModel::EncryptionStatus
*/
void setEncryptionStatus(int status);
/** Set the status bar text if there are any warnings (removes sync progress bar if applicable) */
void refreshStatusBar();
/** Notify the user of an error in the network or transaction handling code. */
void error(const QString &title, const QString &message);
/** Asks the user whether to pay the transaction fee or to cancel the transaction.
It is currently not possible to pass a return value to another thread through
BlockingQueuedConnection, so an indirected pointer is used.
http://bugreports.qt.nokia.com/browse/QTBUG-10440
@param[in] nFeeRequired the required fee
@param[out] payFee true to pay the fee, false to not pay the fee
*/
void askFee(qint64 nFeeRequired, bool *payFee);
private slots:
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
void gotoHistoryPage();
/** Switch to address book page */
void gotoAddressBookPage();
/** Switch to receive coins page */
void gotoReceiveCoinsPage();
/** Switch to send coins page */
void gotoSendCoinsPage();
/** Show configuration dialog */
void optionsClicked();
/** Show about dialog */
void aboutClicked();
#ifndef Q_WS_MAC
/** Handle tray icon clicked */
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
#endif
/** Show incoming transaction notification for new transactions.
The new items are those between start and end inclusive, under the given parent item.
*/
void incomingTransaction(const QModelIndex & parent, int start, int end);
/** Encrypt the wallet */
void encryptWallet(bool status);
/** Change encrypted wallet passphrase */
void changePassphrase();
/** Ask for pass phrase to unlock wallet temporarily */
void unlockWallet();
};
#endif
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 624ff58ce5..b4ebe9d723 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -1,85 +1,85 @@
#include <QtGlobal>
// Automatically generated by extract_strings.py
static const char *bitcoin_strings[] = {QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"),
QT_TRANSLATE_NOOP("bitcoin-core", "Usage:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send command to -server or bitcoind"),
QT_TRANSLATE_NOOP("bitcoin-core", "List commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"),
QT_TRANSLATE_NOOP("bitcoin-core", "Options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: bitcoin.conf)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: bitcoind.pid)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Start minimized"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout (in milliseconds)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks4 proxy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for addnode and connect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: 8333 or testnet: 18333)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (default: 125)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't accept connections from outside"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't bootstrap list of peers using DNS"),
QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Number of seconds to keep misbehaving peers from reconnecting (default: "
"86400)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't attempt to use UPnP to map the listening port"),
QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to use UPnP to map the listening port"),
QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"),
QT_TRANSLATE_NOOP("bitcoin-core", "Output extra debugging information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to debugger"),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: 8332)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send commands to node running on <ip> (default: 127.0.0.1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"\n"
"SSL options: (see the Bitcoin Wiki for SSL setup instructions)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use OpenSSL (https) for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:"
"@STRENGTH)"),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. Bitcoin is probably already "
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading addr.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading blkindex.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of Bitcoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoin to complete"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: -paytxfee is set very high. This is the transaction fee you will "
"pay if you send a transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: CreateThread(StartNode) failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low "),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to bind to port %d on this computer. Bitcoin is probably already "
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Please check that your computer's date and time are correct. If "
"your clock is wrong Bitcoin will not work properly."),
QT_TRANSLATE_NOOP("bitcoin-core", "beta"),
-};
\ No newline at end of file
+};
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 9a9a4890dc..0845d2104b 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -1,181 +1,182 @@
#include "bitcoinunits.h"
+#include <QtGlobal>
#include <QStringList>
BitcoinUnits::BitcoinUnits(QObject *parent):
QAbstractListModel(parent),
unitlist(availableUnits())
{
}
QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits()
{
QList<BitcoinUnits::Unit> unitlist;
unitlist.append(BTC);
unitlist.append(mBTC);
unitlist.append(uBTC);
return unitlist;
}
bool BitcoinUnits::valid(int unit)
{
switch(unit)
{
case BTC:
case mBTC:
case uBTC:
return true;
default:
return false;
}
}
QString BitcoinUnits::name(int unit)
{
switch(unit)
{
case BTC: return QString("BTC");
case mBTC: return QString("mBTC");
case uBTC: return QString::fromUtf8("μBTC");
default: return QString("???");
}
}
QString BitcoinUnits::description(int unit)
{
switch(unit)
{
case BTC: return QString("Bitcoins");
case mBTC: return QString("Milli-Bitcoins (1 / 1,000)");
case uBTC: return QString("Micro-Bitcoins (1 / 1,000,000)");
default: return QString("???");
}
}
qint64 BitcoinUnits::factor(int unit)
{
switch(unit)
{
case BTC: return 100000000;
case mBTC: return 100000;
case uBTC: return 100;
default: return 100000000;
}
}
int BitcoinUnits::amountDigits(int unit)
{
switch(unit)
{
case BTC: return 8; // 21,000,000 (# digits, without commas)
case mBTC: return 11; // 21,000,000,000
case uBTC: return 14; // 21,000,000,000,000
default: return 0;
}
}
int BitcoinUnits::decimals(int unit)
{
switch(unit)
{
case BTC: return 8;
case mBTC: return 5;
case uBTC: return 2;
default: return 0;
}
}
QString BitcoinUnits::format(int unit, qint64 n, bool fPlus)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
if(!valid(unit))
return QString(); // Refuse to format invalid unit
qint64 coin = factor(unit);
int num_decimals = decimals(unit);
qint64 n_abs = (n > 0 ? n : -n);
qint64 quotient = n_abs / coin;
qint64 remainder = n_abs % coin;
QString quotient_str = QString::number(quotient);
QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0');
// Right-trim excess 0's after the decimal point
int nTrim = 0;
for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i)
++nTrim;
remainder_str.chop(nTrim);
if (n < 0)
quotient_str.insert(0, '-');
else if (fPlus && n > 0)
quotient_str.insert(0, '+');
return quotient_str + QString(".") + remainder_str;
}
QString BitcoinUnits::formatWithUnit(int unit, qint64 amount, bool plussign)
{
return format(unit, amount, plussign) + QString(" ") + name(unit);
}
bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out)
{
if(!valid(unit) || value.isEmpty())
return false; // Refuse to parse invalid unit or empty string
int num_decimals = decimals(unit);
QStringList parts = value.split(".");
if(parts.size() > 2)
{
return false; // More than one dot
}
QString whole = parts[0];
QString decimals;
if(parts.size() > 1)
{
decimals = parts[1];
}
if(decimals.size() > num_decimals)
{
return false; // Exceeds max precision
}
bool ok = false;
QString str = whole + decimals.leftJustified(num_decimals, '0');
if(str.size() > 18)
{
return false; // Longer numbers will exceed 63 bits
}
qint64 retvalue = str.toLongLong(&ok);
if(val_out)
{
*val_out = retvalue;
}
return ok;
}
int BitcoinUnits::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return unitlist.size();
}
QVariant BitcoinUnits::data(const QModelIndex &index, int role) const
{
int row = index.row();
if(row >= 0 && row < unitlist.size())
{
Unit unit = unitlist.at(row);
switch(role)
{
case Qt::EditRole:
case Qt::DisplayRole:
return QVariant(name(unit));
case Qt::ToolTipRole:
return QVariant(description(unit));
case UnitRole:
return QVariant(static_cast<int>(unit));
}
}
return QVariant();
}
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 18fa36a0b7..35c0d8ea0d 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -1,66 +1,67 @@
#ifndef BITCOINUNITS_H
#define BITCOINUNITS_H
+#include <QtGlobal>
#include <QString>
#include <QAbstractListModel>
/** Bitcoin unit definitions. Encapsulates parsing and formatting
and serves as list model for dropdown selection boxes.
*/
class BitcoinUnits: public QAbstractListModel
{
public:
explicit BitcoinUnits(QObject *parent);
/** Bitcoin units.
@note Source: https://en.bitcoin.it/wiki/Units . Please add only sensible ones
*/
enum Unit
{
BTC,
mBTC,
uBTC
};
//! @name Static API
//! Unit conversion and formatting
///@{
//! Get list of units, for dropdown box
static QList<Unit> availableUnits();
//! Is unit ID valid?
static bool valid(int unit);
//! Short name
static QString name(int unit);
//! Longer description
static QString description(int unit);
//! Number of Satoshis (1e-8) per unit
static qint64 factor(int unit);
//! Number of amount digits (to represent max number of coins)
static int amountDigits(int unit);
//! Number of decimals left
static int decimals(int unit);
//! Format as string
static QString format(int unit, qint64 amount, bool plussign=false);
//! Format as string (with unit)
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false);
//! Parse string to coin amount
static bool parse(int unit, const QString &value, qint64 *val_out);
///@}
//! @name AbstractListModel implementation
//! List model for unit dropdown selection box.
///@{
enum RoleIndex {
/** Unit identifier */
UnitRole = Qt::UserRole
};
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
///@}
private:
QList<BitcoinUnits::Unit> unitlist;
};
typedef BitcoinUnits::Unit BitcoinUnit;
#endif // BITCOINUNITS_H
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 158b84a285..378660b049 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -1,74 +1,75 @@
#include "guiutil.h"
#include "bitcoinaddressvalidator.h"
#include "walletmodel.h"
#include "bitcoinunits.h"
#include "headers.h"
+#include <QtGlobal>
#include <QString>
#include <QDateTime>
#include <QDoubleValidator>
#include <QFont>
#include <QLineEdit>
#include <QUrl>
QString GUIUtil::dateTimeStr(qint64 nTime)
{
return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
}
QString GUIUtil::dateTimeStr(const QDateTime &date)
{
return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
}
QFont GUIUtil::bitcoinAddressFont()
{
QFont font("Monospace");
font.setStyleHint(QFont::TypeWriter);
return font;
}
void GUIUtil::setupAddressWidget(QLineEdit *widget, QWidget *parent)
{
widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
widget->setValidator(new BitcoinAddressValidator(parent));
widget->setFont(bitcoinAddressFont());
}
void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent)
{
QDoubleValidator *amountValidator = new QDoubleValidator(parent);
amountValidator->setDecimals(8);
amountValidator->setBottom(0.0);
widget->setValidator(amountValidator);
widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
}
bool GUIUtil::parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out)
{
if(url->scheme() != QString("bitcoin"))
return false;
SendCoinsRecipient rv;
rv.address = url->path();
rv.label = url->queryItemValue("label");
QString amount = url->queryItemValue("amount");
if(amount.isEmpty())
{
rv.amount = 0;
}
else // Amount is non-empty
{
if(!BitcoinUnits::parse(BitcoinUnits::BTC, amount, &rv.amount))
{
return false;
}
}
if(out)
{
*out = rv;
}
return true;
}
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 94e3314d14..4a4cc62345 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -1,36 +1,37 @@
#ifndef GUIUTIL_H
#define GUIUTIL_H
+#include <QtGlobal>
#include <QString>
QT_BEGIN_NAMESPACE
class QFont;
class QLineEdit;
class QWidget;
class QDateTime;
class QUrl;
QT_END_NAMESPACE
class SendCoinsRecipient;
/** Static utility functions used by the Bitcoin Qt UI.
*/
class GUIUtil
{
public:
// Create human-readable string from date
static QString dateTimeStr(qint64 nTime);
static QString dateTimeStr(const QDateTime &datetime);
// Render bitcoin addresses in monospace font
static QFont bitcoinAddressFont();
// Set up widgets for address and amounts
static void setupAddressWidget(QLineEdit *widget, QWidget *parent);
static void setupAmountWidget(QLineEdit *widget, QWidget *parent);
// Parse "bitcoin:" URL into recipient object, return true on succesful parsing
// See Bitcoin URL definition discussion here: https://bitcointalk.org/index.php?topic=33490.0
static bool parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out);
};
#endif // GUIUTIL_H
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index a2314caa47..5e9969bf9e 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -1,297 +1,298 @@
#include "notificator.h"
+#include <QtGlobal>
#include <QMetaType>
#include <QVariant>
#include <QIcon>
#include <QApplication>
#include <QStyle>
#include <QByteArray>
#include <QSystemTrayIcon>
#include <QMessageBox>
#include <QTemporaryFile>
#include <QImageWriter>
#ifdef USE_DBUS
#include <QtDBus/QtDBus>
#include <stdint.h>
#endif
#ifdef Q_WS_MAC
#include <ApplicationServices/ApplicationServices.h>
extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret);
#endif
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent):
QObject(parent),
parent(parent),
programName(programName),
mode(None),
trayIcon(trayicon)
#ifdef USE_DBUS
,interface(0)
#endif
{
if(trayicon && trayicon->supportsMessages())
{
mode = QSystemTray;
}
#ifdef USE_DBUS
interface = new QDBusInterface("org.freedesktop.Notifications",
"/org/freedesktop/Notifications", "org.freedesktop.Notifications");
if(interface->isValid())
{
mode = Freedesktop;
}
#endif
#ifdef Q_WS_MAC
// Check if Growl is installed (based on Qt's tray icon implementation)
CFURLRef cfurl;
OSStatus status = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("growlTicket"), kLSRolesAll, 0, &cfurl);
if (status != kLSApplicationNotFoundErr) {
CFBundleRef bundle = CFBundleCreate(0, cfurl);
CFRelease(cfurl);
if (CFStringCompare(CFBundleGetIdentifier(bundle), CFSTR("com.Growl.GrowlHelperApp"), kCFCompareCaseInsensitive | kCFCompareBackwards) == kCFCompareEqualTo) {
mode = Growl;
}
CFRelease(bundle);
}
#endif
}
Notificator::~Notificator()
{
#ifdef USE_DBUS
delete interface;
#endif
}
#ifdef USE_DBUS
// Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
class FreedesktopImage
{
public:
FreedesktopImage() {}
FreedesktopImage(const QImage &img);
static int metaType();
// Image to variant that can be marshaled over DBus
static QVariant toVariant(const QImage &img);
private:
int width, height, stride;
bool hasAlpha;
int channels;
int bitsPerSample;
QByteArray image;
friend QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i);
friend const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i);
};
Q_DECLARE_METATYPE(FreedesktopImage);
// Image configuration settings
const int CHANNELS = 4;
const int BYTES_PER_PIXEL = 4;
const int BITS_PER_SAMPLE = 8;
FreedesktopImage::FreedesktopImage(const QImage &img):
width(img.width()),
height(img.height()),
stride(img.width() * BYTES_PER_PIXEL),
hasAlpha(true),
channels(CHANNELS),
bitsPerSample(BITS_PER_SAMPLE)
{
// Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
QImage tmp = img.convertToFormat(QImage::Format_ARGB32);
const uint32_t *data = reinterpret_cast<const uint32_t*>(tmp.constBits());
unsigned int num_pixels = width * height;
image.resize(num_pixels * BYTES_PER_PIXEL);
for(unsigned int ptr = 0; ptr < num_pixels; ++ptr)
{
image[ptr*BYTES_PER_PIXEL+0] = data[ptr] >> 16; // R
image[ptr*BYTES_PER_PIXEL+1] = data[ptr] >> 8; // G
image[ptr*BYTES_PER_PIXEL+2] = data[ptr]; // B
image[ptr*BYTES_PER_PIXEL+3] = data[ptr] >> 24; // A
}
}
QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i)
{
a.beginStructure();
a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample << i.channels << i.image;
a.endStructure();
return a;
}
const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i)
{
a.beginStructure();
a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >> i.channels >> i.image;
a.endStructure();
return a;
}
int FreedesktopImage::metaType()
{
return qDBusRegisterMetaType<FreedesktopImage>();
}
QVariant FreedesktopImage::toVariant(const QImage &img)
{
FreedesktopImage fimg(img);
return QVariant(FreedesktopImage::metaType(), &fimg);
}
void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
Q_UNUSED(cls);
// Arguments for DBus call:
QList<QVariant> args;
// Program Name:
args.append(programName);
// Unique ID of this notification type:
args.append(0U);
// Application Icon, empty string
args.append(QString());
// Summary
args.append(title);
// Body
args.append(text);
// Actions (none, actions are deprecated)
QStringList actions;
args.append(actions);
// Hints
QVariantMap hints;
// If no icon specified, set icon based on class
QIcon tmpicon;
if(icon.isNull())
{
QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
switch(cls)
{
case Information: sicon = QStyle::SP_MessageBoxInformation; break;
case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
default: break;
}
tmpicon = QApplication::style()->standardIcon(sicon);
}
else
{
tmpicon = icon;
}
hints["icon_data"] = FreedesktopImage::toVariant(tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage());
args.append(hints);
// Timeout (in msec)
args.append(millisTimeout);
// "Fire and forget"
interface->callWithArgumentList(QDBus::NoBlock, "Notify", args);
}
#endif
void Notificator::notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
Q_UNUSED(icon);
QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon;
switch(cls) // Set icon based on class
{
case Information: sicon = QSystemTrayIcon::Information; break;
case Warning: sicon = QSystemTrayIcon::Warning; break;
case Critical: sicon = QSystemTrayIcon::Critical; break;
}
trayIcon->showMessage(title, text, sicon, millisTimeout);
}
// Based on Qt's tray icon implementation
#ifdef Q_WS_MAC
void Notificator::notifyGrowl(Class cls, const QString &title, const QString &text, const QIcon &icon)
{
const QString script(
"tell application \"GrowlHelperApp\"\n"
" set the allNotificationsList to {\"Notification\"}\n" // -- Make a list of all the notification types (all)
" set the enabledNotificationsList to {\"Notification\"}\n" // -- Make a list of the notifications (enabled)
" register as application \"%1\" all notifications allNotificationsList default notifications enabledNotificationsList\n" // -- Register our script with Growl
" notify with name \"Notification\" title \"%2\" description \"%3\" application name \"%1\"%4\n" // -- Send a Notification
"end tell"
);
QString notificationApp(QApplication::applicationName());
if (notificationApp.isEmpty())
notificationApp = "Application";
QPixmap notificationIconPixmap;
if (icon.isNull()) { // If no icon specified, set icon based on class
QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
switch (cls)
{
case Information: sicon = QStyle::SP_MessageBoxInformation; break;
case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
}
notificationIconPixmap = QApplication::style()->standardPixmap(sicon);
}
else {
QSize size = icon.actualSize(QSize(48, 48));
notificationIconPixmap = icon.pixmap(size);
}
QString notificationIcon;
QTemporaryFile notificationIconFile;
if (!notificationIconPixmap.isNull() && notificationIconFile.open()) {
QImageWriter writer(&notificationIconFile, "PNG");
if (writer.write(notificationIconPixmap.toImage()))
notificationIcon = QString(" image from location \"file://%1\"").arg(notificationIconFile.fileName());
}
QString quotedTitle(title), quotedText(text);
quotedTitle.replace("\\", "\\\\").replace("\"", "\\");
quotedText.replace("\\", "\\\\").replace("\"", "\\");
qt_mac_execute_apple_script(script.arg(notificationApp, quotedTitle, quotedText, notificationIcon), 0);
}
#endif
void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
{
switch(mode)
{
#ifdef USE_DBUS
case Freedesktop:
notifyDBus(cls, title, text, icon, millisTimeout);
break;
#endif
case QSystemTray:
notifySystray(cls, title, text, icon, millisTimeout);
break;
#ifdef Q_WS_MAC
case Growl:
notifyGrowl(cls, title, text, icon);
break;
#endif
default:
if(cls == Critical)
{
// Fall back to old fashioned popup dialog if critical and no other notification available
QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok);
}
break;
}
}
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index a68c84c957..bc56bdea03 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -1,163 +1,165 @@
+#include <QtGlobal>
+
#include "optionsmodel.h"
#include "bitcoinunits.h"
#include "headers.h"
#include "init.h"
OptionsModel::OptionsModel(CWallet *wallet, QObject *parent) :
QAbstractListModel(parent),
wallet(wallet),
nDisplayUnit(BitcoinUnits::BTC),
bDisplayAddresses(false)
{
// Read our specific settings from the wallet db
CWalletDB walletdb(wallet->strWalletFile);
walletdb.ReadSetting("nDisplayUnit", nDisplayUnit);
walletdb.ReadSetting("bDisplayAddresses", bDisplayAddresses);
}
int OptionsModel::rowCount(const QModelIndex & parent) const
{
return OptionIDRowCount;
}
QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
if(role == Qt::EditRole)
{
switch(index.row())
{
case StartAtStartup:
return QVariant(GetStartOnSystemStartup());
case MinimizeToTray:
return QVariant(fMinimizeToTray);
case MapPortUPnP:
return QVariant(fUseUPnP);
case MinimizeOnClose:
return QVariant(fMinimizeOnClose);
case ConnectSOCKS4:
return QVariant(fUseProxy);
case ProxyIP:
return QVariant(QString::fromStdString(addrProxy.ToStringIP()));
case ProxyPort:
return QVariant(QString::fromStdString(addrProxy.ToStringPort()));
case Fee:
return QVariant(nTransactionFee);
case DisplayUnit:
return QVariant(nDisplayUnit);
case DisplayAddresses:
return QVariant(bDisplayAddresses);
default:
return QVariant();
}
}
return QVariant();
}
bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
bool successful = true; /* set to false on parse error */
if(role == Qt::EditRole)
{
CWalletDB walletdb(wallet->strWalletFile);
switch(index.row())
{
case StartAtStartup:
successful = SetStartOnSystemStartup(value.toBool());
break;
case MinimizeToTray:
fMinimizeToTray = value.toBool();
walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
break;
case MapPortUPnP:
fUseUPnP = value.toBool();
walletdb.WriteSetting("fUseUPnP", fUseUPnP);
#ifdef USE_UPNP
MapPort(fUseUPnP);
#endif
break;
case MinimizeOnClose:
fMinimizeOnClose = value.toBool();
walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
break;
case ConnectSOCKS4:
fUseProxy = value.toBool();
walletdb.WriteSetting("fUseProxy", fUseProxy);
break;
case ProxyIP:
{
// Use CAddress to parse and check IP
CAddress addr(value.toString().toStdString() + ":1");
if (addr.ip != INADDR_NONE)
{
addrProxy.ip = addr.ip;
walletdb.WriteSetting("addrProxy", addrProxy);
}
else
{
successful = false;
}
}
break;
case ProxyPort:
{
int nPort = atoi(value.toString().toAscii().data());
if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max())
{
addrProxy.port = htons(nPort);
walletdb.WriteSetting("addrProxy", addrProxy);
}
else
{
successful = false;
}
}
break;
case Fee: {
nTransactionFee = value.toLongLong();
walletdb.WriteSetting("nTransactionFee", nTransactionFee);
}
break;
case DisplayUnit: {
int unit = value.toInt();
nDisplayUnit = unit;
walletdb.WriteSetting("nDisplayUnit", nDisplayUnit);
emit displayUnitChanged(unit);
}
case DisplayAddresses: {
bDisplayAddresses = value.toBool();
walletdb.WriteSetting("bDisplayAddresses", bDisplayAddresses);
}
default:
break;
}
}
emit dataChanged(index, index);
return successful;
}
qint64 OptionsModel::getTransactionFee()
{
return nTransactionFee;
}
bool OptionsModel::getMinimizeToTray()
{
return fMinimizeToTray;
}
bool OptionsModel::getMinimizeOnClose()
{
return fMinimizeOnClose;
}
int OptionsModel::getDisplayUnit()
{
return nDisplayUnit;
}
bool OptionsModel::getDisplayAddresses()
{
return bDisplayAddresses;
}
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 775362d636..13d964b256 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -1,56 +1,57 @@
#ifndef OPTIONSMODEL_H
#define OPTIONSMODEL_H
+#include <QtGlobal>
#include <QAbstractListModel>
class CWallet;
/** Interface from QT to configuration data structure for bitcoin client.
To QT, the options are presented as a list with the different options
laid out vertically.
This can be changed to a tree once the settings become sufficiently
complex.
*/
class OptionsModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit OptionsModel(CWallet *wallet, QObject *parent = 0);
enum OptionID {
StartAtStartup, // bool
MinimizeToTray, // bool
MapPortUPnP, // bool
MinimizeOnClose, // bool
ConnectSOCKS4, // bool
ProxyIP, // QString
ProxyPort, // QString
Fee, // qint64
DisplayUnit, // BitcoinUnits::Unit
DisplayAddresses, // bool
OptionIDRowCount
};
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
/* Explicit getters */
qint64 getTransactionFee();
bool getMinimizeToTray();
bool getMinimizeOnClose();
int getDisplayUnit();
bool getDisplayAddresses();
private:
// Wallet stores persistent options
CWallet *wallet;
int nDisplayUnit;
bool bDisplayAddresses;
signals:
void displayUnitChanged(int unit);
public slots:
};
#endif // OPTIONSMODEL_H
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 5b5a8f5271..1710519e0d 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -1,179 +1,180 @@
#include "overviewpage.h"
#include "ui_overviewpage.h"
#include "walletmodel.h"
#include "bitcoinunits.h"
#include "optionsmodel.h"
#include "transactiontablemodel.h"
#include "transactionfilterproxy.h"
#include "guiutil.h"
#include "guiconstants.h"
+#include <QtGlobal>
#include <QAbstractItemDelegate>
#include <QPainter>
#define DECORATION_SIZE 64
#define NUM_ITEMS 3
class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
TxViewDelegate(): QAbstractItemDelegate(), unit(BitcoinUnits::BTC)
{
}
inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{
painter->save();
QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
QRect mainRect = option.rect;
QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
int xspace = DECORATION_SIZE + 8;
int ypad = 6;
int halfheight = (mainRect.height() - 2*ypad)/2;
QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
icon.paint(painter, decorationRect);
QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
QString address = index.data(Qt::DisplayRole).toString();
qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
QVariant value = index.data(Qt::ForegroundRole);
QColor foreground = option.palette.color(QPalette::Text);
if(qVariantCanConvert<QColor>(value))
{
foreground = qvariant_cast<QColor>(value);
}
painter->setPen(foreground);
painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address);
if(amount < 0)
{
foreground = COLOR_NEGATIVE;
}
else if(!confirmed)
{
foreground = COLOR_UNCONFIRMED;
}
else
{
foreground = option.palette.color(QPalette::Text);
}
painter->setPen(foreground);
QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true);
if(!confirmed)
{
amountText = QString("[") + amountText + QString("]");
}
painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);
painter->setPen(option.palette.color(QPalette::Text));
painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));
painter->restore();
}
inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return QSize(DECORATION_SIZE, DECORATION_SIZE);
}
int unit;
};
#include "overviewpage.moc"
OverviewPage::OverviewPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::OverviewPage),
currentBalance(-1),
currentUnconfirmedBalance(-1),
txdelegate(new TxViewDelegate())
{
ui->setupUi(this);
// Balance: <balance>
ui->labelBalance->setFont(QFont("Monospace", -1, QFont::Bold));
ui->labelBalance->setToolTip(tr("Your current balance"));
ui->labelBalance->setTextInteractionFlags(Qt::TextSelectableByMouse|Qt::TextSelectableByKeyboard);
// Unconfirmed balance: <balance>
ui->labelUnconfirmed->setFont(QFont("Monospace", -1, QFont::Bold));
ui->labelUnconfirmed->setToolTip(tr("Total of transactions that have yet to be confirmed, and do not yet count toward the current balance"));
ui->labelUnconfirmed->setTextInteractionFlags(Qt::TextSelectableByMouse|Qt::TextSelectableByKeyboard);
ui->labelNumTransactions->setToolTip(tr("Total number of transactions in wallet"));
// Recent transactions
ui->listTransactions->setStyleSheet("QListView { background:transparent }");
ui->listTransactions->setItemDelegate(txdelegate);
ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
ui->listTransactions->setSelectionMode(QAbstractItemView::NoSelection);
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SIGNAL(transactionClicked(QModelIndex)));
}
OverviewPage::~OverviewPage()
{
delete ui;
}
void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance)
{
int unit = model->getOptionsModel()->getDisplayUnit();
currentBalance = balance;
currentUnconfirmedBalance = unconfirmedBalance;
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance));
}
void OverviewPage::setNumTransactions(int count)
{
ui->labelNumTransactions->setText(QLocale::system().toString(count));
}
void OverviewPage::setModel(WalletModel *model)
{
this->model = model;
if(model)
{
// Set up transaction list
TransactionFilterProxy *filter = new TransactionFilterProxy();
filter->setSourceModel(model->getTransactionTableModel());
filter->setLimit(NUM_ITEMS);
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
ui->listTransactions->setModel(filter);
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
// Keep up to date with wallet
setBalance(model->getBalance(), model->getUnconfirmedBalance());
connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64)));
setNumTransactions(model->getNumTransactions());
connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(displayUnitChanged()));
}
}
void OverviewPage::displayUnitChanged()
{
if(!model || !model->getOptionsModel())
return;
if(currentBalance != -1)
setBalance(currentBalance, currentUnconfirmedBalance);
txdelegate->unit = model->getOptionsModel()->getDisplayUnit();
ui->listTransactions->update();
}
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 1199227168..46317d9b9e 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -1,46 +1,47 @@
#ifndef OVERVIEWPAGE_H
#define OVERVIEWPAGE_H
+#include <QtGlobal>
#include <QWidget>
QT_BEGIN_NAMESPACE
class QModelIndex;
QT_END_NAMESPACE
namespace Ui {
class OverviewPage;
}
class WalletModel;
class TxViewDelegate;
/** Overview ("home") page widget */
class OverviewPage : public QWidget
{
Q_OBJECT
public:
explicit OverviewPage(QWidget *parent = 0);
~OverviewPage();
void setModel(WalletModel *model);
public slots:
void setBalance(qint64 balance, qint64 unconfirmedBalance);
void setNumTransactions(int count);
signals:
void transactionClicked(const QModelIndex &index);
private:
Ui::OverviewPage *ui;
WalletModel *model;
qint64 currentBalance;
qint64 currentUnconfirmedBalance;
TxViewDelegate *txdelegate;
private slots:
void displayUnitChanged();
};
#endif // OVERVIEWPAGE_H
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 762f27dfa6..e6b500cfde 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -1,269 +1,270 @@
#include "sendcoinsdialog.h"
#include "ui_sendcoinsdialog.h"
#include "walletmodel.h"
#include "bitcoinunits.h"
#include "addressbookpage.h"
#include "optionsmodel.h"
#include "sendcoinsentry.h"
#include "guiutil.h"
#include "askpassphrasedialog.h"
+#include <QtGlobal>
#include <QMessageBox>
#include <QLocale>
#include <QTextDocument>
SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SendCoinsDialog),
model(0)
{
ui->setupUi(this);
#ifdef Q_WS_MAC // Icons on push buttons are very uncommon on Mac
ui->addButton->setIcon(QIcon());
ui->clearButton->setIcon(QIcon());
ui->sendButton->setIcon(QIcon());
#endif
addEntry();
connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry()));
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
}
void SendCoinsDialog::setModel(WalletModel *model)
{
this->model = model;
for(int i = 0; i < ui->entries->count(); ++i)
{
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if(entry)
{
entry->setModel(model);
}
}
if(model)
{
setBalance(model->getBalance(), model->getUnconfirmedBalance());
connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64)));
}
}
SendCoinsDialog::~SendCoinsDialog()
{
delete ui;
}
void SendCoinsDialog::on_sendButton_clicked()
{
QList<SendCoinsRecipient> recipients;
bool valid = true;
if(!model)
return;
for(int i = 0; i < ui->entries->count(); ++i)
{
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if(entry)
{
if(entry->validate())
{
recipients.append(entry->getValue());
}
else
{
valid = false;
}
}
}
if(!valid || recipients.isEmpty())
{
return;
}
// Format confirmation message
QStringList formatted;
foreach(const SendCoinsRecipient &rcp, recipients)
{
formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address));
}
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
tr("Are you sure you want to send %1?").arg(formatted.join(tr(" and "))),
QMessageBox::Yes|QMessageBox::Cancel,
QMessageBox::Cancel);
if(retval != QMessageBox::Yes)
{
return;
}
WalletModel::UnlockContext ctx(model->requestUnlock());
if(!ctx.isValid())
{
// Unlock wallet was cancelled
return;
}
WalletModel::SendCoinsReturn sendstatus = model->sendCoins(recipients);
switch(sendstatus.status)
{
case WalletModel::InvalidAddress:
QMessageBox::warning(this, tr("Send Coins"),
tr("The recepient address is not valid, please recheck."),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::InvalidAmount:
QMessageBox::warning(this, tr("Send Coins"),
tr("The amount to pay must be larger than 0."),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::AmountExceedsBalance:
QMessageBox::warning(this, tr("Send Coins"),
tr("Amount exceeds your balance"),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::AmountWithFeeExceedsBalance:
QMessageBox::warning(this, tr("Send Coins"),
tr("Total exceeds your balance when the %1 transaction fee is included").
arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::DuplicateAddress:
QMessageBox::warning(this, tr("Send Coins"),
tr("Duplicate address found, can only send to each address once in one send operation"),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::TransactionCreationFailed:
QMessageBox::warning(this, tr("Send Coins"),
tr("Error: Transaction creation failed "),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::TransactionCommitFailed:
QMessageBox::warning(this, tr("Send Coins"),
tr("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::OK:
accept();
break;
}
}
void SendCoinsDialog::clear()
{
// Remove entries until only one left
while(ui->entries->count())
{
delete ui->entries->takeAt(0)->widget();
}
addEntry();
updateRemoveEnabled();
ui->sendButton->setDefault(true);
}
void SendCoinsDialog::reject()
{
clear();
}
void SendCoinsDialog::accept()
{
clear();
}
SendCoinsEntry *SendCoinsDialog::addEntry()
{
SendCoinsEntry *entry = new SendCoinsEntry(this);
entry->setModel(model);
ui->entries->addWidget(entry);
connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
updateRemoveEnabled();
// Focus the field, so that entry can start immediately
entry->clear();
return entry;
}
void SendCoinsDialog::updateRemoveEnabled()
{
// Remove buttons are enabled as soon as there is more than one send-entry
bool enabled = (ui->entries->count() > 1);
for(int i = 0; i < ui->entries->count(); ++i)
{
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if(entry)
{
entry->setRemoveEnabled(enabled);
}
}
setupTabChain(0);
}
void SendCoinsDialog::removeEntry(SendCoinsEntry* entry)
{
delete entry;
updateRemoveEnabled();
}
QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
{
for(int i = 0; i < ui->entries->count(); ++i)
{
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if(entry)
{
prev = entry->setupTabChain(prev);
}
}
QWidget::setTabOrder(prev, ui->addButton);
QWidget::setTabOrder(ui->addButton, ui->sendButton);
return ui->sendButton;
}
void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
{
SendCoinsEntry *entry = 0;
// Replace the first entry if it is still unused
if(ui->entries->count() == 1)
{
SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
if(first->isClear())
{
entry = first;
}
}
if(!entry)
{
entry = addEntry();
}
entry->setValue(rv);
}
void SendCoinsDialog::handleURL(const QUrl *url)
{
SendCoinsRecipient rv;
if(!GUIUtil::parseBitcoinURL(url, &rv))
{
return;
}
pasteEntry(rv);
}
void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance)
{
Q_UNUSED(unconfirmedBalance);
if(!model || !model->getOptionsModel())
return;
int unit = model->getOptionsModel()->getDisplayUnit();
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 82910257f0..d879fbe973 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -1,53 +1,54 @@
#ifndef SENDCOINSDIALOG_H
#define SENDCOINSDIALOG_H
+#include <QtGlobal>
#include <QDialog>
namespace Ui {
class SendCoinsDialog;
}
class WalletModel;
class SendCoinsEntry;
class SendCoinsRecipient;
QT_BEGIN_NAMESPACE
class QUrl;
QT_END_NAMESPACE
/** Dialog for sending bitcoins */
class SendCoinsDialog : public QDialog
{
Q_OBJECT
public:
explicit SendCoinsDialog(QWidget *parent = 0);
~SendCoinsDialog();
void setModel(WalletModel *model);
/** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue http://bugreports.qt.nokia.com/browse/QTBUG-10907).
*/
QWidget *setupTabChain(QWidget *prev);
void pasteEntry(const SendCoinsRecipient &rv);
void handleURL(const QUrl *url);
public slots:
void clear();
void reject();
void accept();
SendCoinsEntry *addEntry();
void updateRemoveEnabled();
void setBalance(qint64 balance, qint64 unconfirmedBalance);
private:
Ui::SendCoinsDialog *ui;
WalletModel *model;
private slots:
void on_sendButton_clicked();
void removeEntry(SendCoinsEntry* entry);
};
#endif // SENDCOINSDIALOG_H
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 6ca3ac8c4b..a19ec875d9 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -1,292 +1,293 @@
#include <transactiondesc.h>
#include "guiutil.h"
#include "bitcoinunits.h"
#include "headers.h"
#include "qtui.h"
+#include <QtGlobal>
#include <QString>
#include <QTextDocument> // For Qt::escape
using namespace std;
QString TransactionDesc::HtmlEscape(const QString& str, bool fMultiLine)
{
QString escaped = Qt::escape(str);
if(fMultiLine)
{
escaped = escaped.replace("\n", "<br>\n");
}
return escaped;
}
QString TransactionDesc::HtmlEscape(const std::string& str, bool fMultiLine)
{
return HtmlEscape(QString::fromStdString(str), fMultiLine);
}
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
if (!wtx.IsFinal())
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
return tr("Open for %1 blocks").arg(nBestHeight - wtx.nLockTime);
else
return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
}
else
{
int nDepth = wtx.GetDepthInMainChain();
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
return tr("%1/offline?").arg(nDepth);
else if (nDepth < 6)
return tr("%1/unconfirmed").arg(nDepth);
else
return tr("%1 confirmations").arg(nDepth);
}
}
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{
QString strHTML;
CRITICAL_BLOCK(wallet->cs_wallet)
{
strHTML.reserve(4000);
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
- int64 nTime = wtx.GetTxTime();
- int64 nCredit = wtx.GetCredit();
- int64 nDebit = wtx.GetDebit();
- int64 nNet = nCredit - nDebit;
+ qint64 nTime = wtx.GetTxTime();
+ qint64 nCredit = wtx.GetCredit();
+ qint64 nDebit = wtx.GetDebit();
+ qint64 nNet = nCredit - nDebit;
strHTML += tr("<b>Status:</b> ") + FormatTxStatus(wtx);
int nRequests = wtx.GetRequestCount();
if (nRequests != -1)
{
if (nRequests == 0)
strHTML += tr(", has not been successfully broadcast yet");
else if (nRequests == 1)
strHTML += tr(", broadcast through %1 node").arg(nRequests);
else
strHTML += tr(", broadcast through %1 nodes").arg(nRequests);
}
strHTML += "<br>";
strHTML += tr("<b>Date:</b> ") + (nTime ? GUIUtil::dateTimeStr(nTime) : QString("")) + "<br>";
//
// From
//
if (wtx.IsCoinBase())
{
strHTML += tr("<b>Source:</b> Generated<br>");
}
else if (!wtx.mapValue["from"].empty())
{
// Online transaction
if (!wtx.mapValue["from"].empty())
strHTML += tr("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
}
else
{
// Offline transaction
if (nNet > 0)
{
// Credit
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
if (wallet->IsMine(txout))
{
CBitcoinAddress address;
if (ExtractAddress(txout.scriptPubKey, wallet, address))
{
if (wallet->mapAddressBook.count(address))
{
strHTML += tr("<b>From:</b> ") + tr("unknown") + "<br>";
strHTML += tr("<b>To:</b> ");
strHTML += HtmlEscape(address.ToString());
if (!wallet->mapAddressBook[address].empty())
strHTML += tr(" (yours, label: ") + HtmlEscape(wallet->mapAddressBook[address]) + ")";
else
strHTML += tr(" (yours)");
strHTML += "<br>";
}
}
break;
}
}
}
}
//
// To
//
string strAddress;
if (!wtx.mapValue["to"].empty())
{
// Online transaction
strAddress = wtx.mapValue["to"];
strHTML += tr("<b>To:</b> ");
if (wallet->mapAddressBook.count(strAddress) && !wallet->mapAddressBook[strAddress].empty())
strHTML += HtmlEscape(wallet->mapAddressBook[strAddress]) + " ";
strHTML += HtmlEscape(strAddress) + "<br>";
}
//
// Amount
//
if (wtx.IsCoinBase() && nCredit == 0)
{
//
// Coinbase
//
- int64 nUnmatured = 0;
+ qint64 nUnmatured = 0;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
nUnmatured += wallet->GetCredit(txout);
strHTML += tr("<b>Credit:</b> ");
if (wtx.IsInMainChain())
strHTML += tr("(%1 matures in %2 more blocks)")
.arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured))
.arg(wtx.GetBlocksToMaturity());
else
strHTML += tr("(not accepted)");
strHTML += "<br>";
}
else if (nNet > 0)
{
//
// Credit
//
strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>";
}
else
{
bool fAllFromMe = true;
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
fAllFromMe = fAllFromMe && wallet->IsMine(txin);
bool fAllToMe = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
fAllToMe = fAllToMe && wallet->IsMine(txout);
if (fAllFromMe)
{
//
// Debit
//
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
if (wallet->IsMine(txout))
continue;
if (wtx.mapValue["to"].empty())
{
// Offline transaction
CBitcoinAddress address;
if (ExtractAddress(txout.scriptPubKey, 0, address))
{
strHTML += tr("<b>To:</b> ");
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
strHTML += HtmlEscape(wallet->mapAddressBook[address]) + " ";
strHTML += HtmlEscape(address.ToString());
strHTML += "<br>";
}
}
strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>";
}
if (fAllToMe)
{
// Payment to self
- int64 nChange = wtx.GetChange();
- int64 nValue = nCredit - nChange;
+ qint64 nChange = wtx.GetChange();
+ qint64 nValue = nCredit - nChange;
strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>";
strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>";
}
- int64 nTxFee = nDebit - wtx.GetValueOut();
+ qint64 nTxFee = nDebit - wtx.GetValueOut();
if (nTxFee > 0)
strHTML += tr("<b>Transaction fee:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-nTxFee) + "<br>";
}
else
{
//
// Mixed debit transaction
//
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
if (wallet->IsMine(txin))
strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>";
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (wallet->IsMine(txout))
strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>";
}
}
strHTML += tr("<b>Net amount:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,nNet, true) + "<br>";
//
// Message
//
if (!wtx.mapValue["message"].empty())
strHTML += QString("<br><b>") + tr("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
if (!wtx.mapValue["comment"].empty())
strHTML += QString("<br><b>") + tr("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
if (wtx.IsCoinBase())
strHTML += QString("<br>") + tr("Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
//
// Debug view
//
if (fDebug)
{
strHTML += "<hr><br>Debug information<br><br>";
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
if(wallet->IsMine(txin))
strHTML += "<b>Debit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>";
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if(wallet->IsMine(txout))
strHTML += "<b>Credit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>";
strHTML += "<br><b>Transaction:</b><br>";
strHTML += HtmlEscape(wtx.ToString(), true);
CTxDB txdb("r"); // To fetch source txouts
strHTML += "<br><b>Inputs:</b>";
strHTML += "<ul>";
CRITICAL_BLOCK(wallet->cs_wallet)
{
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{
COutPoint prevout = txin.prevout;
CTransaction prev;
if(txdb.ReadDiskTx(prevout.hash, prev))
{
if (prevout.n < prev.vout.size())
{
strHTML += "<li>";
const CTxOut &vout = prev.vout[prevout.n];
CBitcoinAddress address;
if (ExtractAddress(vout.scriptPubKey, 0, address))
{
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
strHTML += HtmlEscape(wallet->mapAddressBook[address]) + " ";
strHTML += QString::fromStdString(address.ToString());
}
strHTML = strHTML + " Amount=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,vout.nValue);
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? "true" : "false") + "</li>";
}
}
}
}
strHTML += "</ul>";
}
strHTML += "</font></html>";
}
return strHTML;
}
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
index 16fb4dab92..278186fe6e 100644
--- a/src/qt/transactionfilterproxy.cpp
+++ b/src/qt/transactionfilterproxy.cpp
@@ -1,86 +1,87 @@
#include "transactionfilterproxy.h"
#include "transactiontablemodel.h"
+#include <QtGlobal>
#include <QDateTime>
#include <cstdlib>
// Earliest date that can be represented (far in the past)
const QDateTime TransactionFilterProxy::MIN_DATE = QDateTime::fromTime_t(0);
// Last date that can be represented (far in the future)
const QDateTime TransactionFilterProxy::MAX_DATE = QDateTime::fromTime_t(0xFFFFFFFF);
TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
QSortFilterProxyModel(parent),
dateFrom(MIN_DATE),
dateTo(MAX_DATE),
addrPrefix(),
typeFilter(ALL_TYPES),
minAmount(0),
limitRows(-1)
{
}
bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
int type = index.data(TransactionTableModel::TypeRole).toInt();
QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime();
QString address = index.data(TransactionTableModel::AddressRole).toString();
QString label = index.data(TransactionTableModel::LabelRole).toString();
qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong());
if(!(TYPE(type) & typeFilter))
return false;
if(datetime < dateFrom || datetime > dateTo)
return false;
if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive))
return false;
if(amount < minAmount)
return false;
return true;
}
void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime &to)
{
this->dateFrom = from;
this->dateTo = to;
invalidateFilter();
}
void TransactionFilterProxy::setAddressPrefix(const QString &addrPrefix)
{
this->addrPrefix = addrPrefix;
invalidateFilter();
}
void TransactionFilterProxy::setTypeFilter(quint32 modes)
{
this->typeFilter = modes;
invalidateFilter();
}
void TransactionFilterProxy::setMinAmount(qint64 minimum)
{
this->minAmount = minimum;
invalidateFilter();
}
void TransactionFilterProxy::setLimit(int limit)
{
this->limitRows = limit;
}
int TransactionFilterProxy::rowCount(const QModelIndex &parent) const
{
if(limitRows != -1)
{
return std::min(QSortFilterProxyModel::rowCount(parent), limitRows);
}
else
{
return QSortFilterProxyModel::rowCount(parent);
}
}
diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h
index 76cf46f156..e33b5e5fb0 100644
--- a/src/qt/transactionfilterproxy.h
+++ b/src/qt/transactionfilterproxy.h
@@ -1,52 +1,53 @@
#ifndef TRANSACTIONFILTERPROXY_H
#define TRANSACTIONFILTERPROXY_H
+#include <QtGlobal>
#include <QSortFilterProxyModel>
#include <QDateTime>
/** Filter the transaction list according to pre-specified rules. */
class TransactionFilterProxy : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit TransactionFilterProxy(QObject *parent = 0);
/** Earliest date that can be represented (far in the past) */
static const QDateTime MIN_DATE;
/** Last date that can be represented (far in the future) */
static const QDateTime MAX_DATE;
/** Type filter bit field (all types) */
static const quint32 ALL_TYPES = 0xFFFFFFFF;
static quint32 TYPE(int type) { return 1<<type; }
void setDateRange(const QDateTime &from, const QDateTime &to);
void setAddressPrefix(const QString &addrPrefix);
/**
@note Type filter takes a bitfield created with TYPE() or ALL_TYPES
*/
void setTypeFilter(quint32 modes);
void setMinAmount(qint64 minimum);
/** Set maximum number of rows returned, -1 if unlimited. */
void setLimit(int limit);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const;
private:
QDateTime dateFrom;
QDateTime dateTo;
QString addrPrefix;
quint32 typeFilter;
qint64 minAmount;
int limitRows;
signals:
public slots:
};
#endif // TRANSACTIONFILTERPROXY_H
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 53cd35b2da..8a1f1b6772 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -1,264 +1,266 @@
+#include <QtGlobal>
+
#include "transactionrecord.h"
#include "headers.h"
/* Return positive answer if transaction should be shown in list.
*/
bool TransactionRecord::showTransaction(const CWalletTx &wtx)
{
if (wtx.IsCoinBase())
{
// Don't show generated coin until confirmed by at least one block after it
// so we don't get the user's hopes up until it looks like it's probably accepted.
//
// It is not an error when generated blocks are not accepted. By design,
// some percentage of blocks, like 10% or more, will end up not accepted.
// This is the normal mechanism by which the network copes with latency.
//
// We display regular transactions right away before any confirmation
// because they can always get into some block eventually. Generated coins
// are special because if their block is not accepted, they are not valid.
//
if (wtx.GetDepthInMainChain() < 2)
{
return false;
}
}
return true;
}
/*
* Decompose CWallet transaction to model transaction records.
*/
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
{
QList<TransactionRecord> parts;
- int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
- int64 nCredit = wtx.GetCredit(true);
- int64 nDebit = wtx.GetDebit();
- int64 nNet = nCredit - nDebit;
+ qint64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
+ qint64 nCredit = wtx.GetCredit(true);
+ qint64 nDebit = wtx.GetDebit();
+ qint64 nNet = nCredit - nDebit;
uint256 hash = wtx.GetHash();
std::map<std::string, std::string> mapValue = wtx.mapValue;
if (showTransaction(wtx))
{
if (nNet > 0 || wtx.IsCoinBase())
{
//
// Credit
//
TransactionRecord sub(hash, nTime);
sub.credit = nNet;
if (wtx.IsCoinBase())
{
// Generated
sub.type = TransactionRecord::Generated;
if (nCredit == 0)
{
- int64 nUnmatured = 0;
+ qint64 nUnmatured = 0;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
nUnmatured += wallet->GetCredit(txout);
sub.credit = nUnmatured;
}
}
else if (!mapValue["from"].empty() || !mapValue["message"].empty())
{
// Received by IP connection
sub.type = TransactionRecord::RecvFromIP;
if (!mapValue["from"].empty())
sub.address = mapValue["from"];
}
else
{
// Received by Bitcoin Address
sub.type = TransactionRecord::RecvWithAddress;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
if(wallet->IsMine(txout))
{
CBitcoinAddress address;
if (ExtractAddress(txout.scriptPubKey, wallet, address))
{
sub.address = address.ToString();
}
break;
}
}
}
parts.append(sub);
}
else
{
bool fAllFromMe = true;
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
fAllFromMe = fAllFromMe && wallet->IsMine(txin);
bool fAllToMe = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
fAllToMe = fAllToMe && wallet->IsMine(txout);
if (fAllFromMe && fAllToMe)
{
// Payment to self
- int64 nChange = wtx.GetChange();
+ qint64 nChange = wtx.GetChange();
parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
-(nDebit - nChange), nCredit - nChange));
}
else if (fAllFromMe)
{
//
// Debit
//
- int64 nTxFee = nDebit - wtx.GetValueOut();
+ qint64 nTxFee = nDebit - wtx.GetValueOut();
for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
{
const CTxOut& txout = wtx.vout[nOut];
TransactionRecord sub(hash, nTime);
sub.idx = parts.size();
if(wallet->IsMine(txout))
{
// Ignore parts sent to self, as this is usually the change
// from a transaction sent back to our own address.
continue;
}
else if(!mapValue["to"].empty())
{
// Sent to IP
sub.type = TransactionRecord::SendToIP;
sub.address = mapValue["to"];
}
else
{
// Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress;
CBitcoinAddress address;
if (ExtractAddress(txout.scriptPubKey, 0, address))
{
sub.address = address.ToString();
}
}
- int64 nValue = txout.nValue;
+ qint64 nValue = txout.nValue;
/* Add fee to first output */
if (nTxFee > 0)
{
nValue += nTxFee;
nTxFee = 0;
}
sub.debit = -nValue;
parts.append(sub);
}
}
else
{
//
// Mixed debit transaction, can't break down payees
//
bool fAllMine = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
fAllMine = fAllMine && wallet->IsMine(txout);
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
fAllMine = fAllMine && wallet->IsMine(txin);
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
}
}
}
return parts;
}
void TransactionRecord::updateStatus(const CWalletTx &wtx)
{
// Determine transaction status
// Find the block the tx is in
CBlockIndex* pindex = NULL;
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
if (mi != mapBlockIndex.end())
pindex = (*mi).second;
// Sort order, unrecorded transactions sort to the top
status.sortKey = strprintf("%010d-%01d-%010u-%03d",
(pindex ? pindex->nHeight : std::numeric_limits<int>::max()),
(wtx.IsCoinBase() ? 1 : 0),
wtx.nTimeReceived,
idx);
status.confirmed = wtx.IsConfirmed();
status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = nBestHeight;
if (!wtx.IsFinal())
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
{
status.status = TransactionStatus::OpenUntilBlock;
status.open_for = nBestHeight - wtx.nLockTime;
}
else
{
status.status = TransactionStatus::OpenUntilDate;
status.open_for = wtx.nLockTime;
}
}
else
{
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
{
status.status = TransactionStatus::Offline;
}
else if (status.depth < NumConfirmations)
{
status.status = TransactionStatus::Unconfirmed;
}
else
{
status.status = TransactionStatus::HaveConfirmations;
}
}
// For generated transactions, determine maturity
if(type == TransactionRecord::Generated)
{
- int64 nCredit = wtx.GetCredit(true);
+ qint64 nCredit = wtx.GetCredit(true);
if (nCredit == 0)
{
status.maturity = TransactionStatus::Immature;
if (wtx.IsInMainChain())
{
status.matures_in = wtx.GetBlocksToMaturity();
// Check if the block was requested by anyone
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
status.maturity = TransactionStatus::MaturesWarning;
}
else
{
status.maturity = TransactionStatus::NotAccepted;
}
}
else
{
status.maturity = TransactionStatus::Mature;
}
}
}
bool TransactionRecord::statusUpdateNeeded()
{
return status.cur_num_blocks != nBestHeight;
}
std::string TransactionRecord::getTxID()
{
return hash.ToString() + strprintf("-%03d", idx);
}
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index 704cfe65b7..db29b94576 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -1,129 +1,130 @@
#ifndef TRANSACTIONRECORD_H
#define TRANSACTIONRECORD_H
#include "uint256.h"
+#include <QtGlobal>
#include <QList>
class CWallet;
class CWalletTx;
/** UI model for transaction status. The transaction status is the part of a transaction that will change over time.
*/
class TransactionStatus
{
public:
TransactionStatus():
confirmed(false), sortKey(""), maturity(Mature),
matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1)
{ }
enum Maturity
{
Immature,
Mature,
MaturesWarning, /**< Transaction will likely not mature because no nodes have confirmed */
NotAccepted
};
enum Status {
OpenUntilDate,
OpenUntilBlock,
Offline,
Unconfirmed,
HaveConfirmations
};
bool confirmed;
std::string sortKey;
/** @name Generated (mined) transactions
@{*/
Maturity maturity;
int matures_in;
/**@}*/
/** @name Reported status
@{*/
Status status;
- int64 depth;
- int64 open_for; /**< Timestamp if status==OpenUntilDate, otherwise number of blocks */
+ qint64 depth;
+ qint64 open_for; /**< Timestamp if status==OpenUntilDate, otherwise number of blocks */
/**@}*/
/** Current number of blocks (to know whether cached status is still valid) */
int cur_num_blocks;
};
/** UI model for a transaction. A core transaction can be represented by multiple UI transactions if it has
multiple outputs.
*/
class TransactionRecord
{
public:
enum Type
{
Other,
Generated,
SendToAddress,
SendToIP,
RecvWithAddress,
RecvFromIP,
SendToSelf
};
/** Number of confirmation needed for transaction */
static const int NumConfirmations = 6;
TransactionRecord():
hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0)
{
}
- TransactionRecord(uint256 hash, int64 time):
+ TransactionRecord(uint256 hash, qint64 time):
hash(hash), time(time), type(Other), address(""), debit(0),
credit(0), idx(0)
{
}
- TransactionRecord(uint256 hash, int64 time,
+ TransactionRecord(uint256 hash, qint64 time,
Type type, const std::string &address,
- int64 debit, int64 credit):
+ qint64 debit, qint64 credit):
hash(hash), time(time), type(type), address(address), debit(debit), credit(credit),
idx(0)
{
}
/** Decompose CWallet transaction to model transaction records.
*/
static bool showTransaction(const CWalletTx &wtx);
static QList<TransactionRecord> decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx);
/** @name Immutable transaction attributes
@{*/
uint256 hash;
- int64 time;
+ qint64 time;
Type type;
std::string address;
- int64 debit;
- int64 credit;
+ qint64 debit;
+ qint64 credit;
/**@}*/
/** Subtransaction index, for sort key */
int idx;
/** Status: can change with block chain update */
TransactionStatus status;
/** Return the unique identifier for this transaction (part) */
std::string getTxID();
/** Update status from core wallet tx.
*/
void updateStatus(const CWalletTx &wtx);
/** Return whether a status update is needed.
*/
bool statusUpdateNeeded();
};
#endif // TRANSACTIONRECORD_H
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 2dcbf1ea8a..af9597117d 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -1,427 +1,428 @@
#include "transactionview.h"
#include "transactionfilterproxy.h"
#include "transactionrecord.h"
#include "walletmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"
#include "bitcoinunits.h"
#include "csvmodelwriter.h"
#include "transactiondescdialog.h"
#include "editaddressdialog.h"
#include "optionsmodel.h"
+#include <QtGlobal>
#include <QScrollBar>
#include <QComboBox>
#include <QDoubleValidator>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QTableView>
#include <QHeaderView>
#include <QPushButton>
#include <QFileDialog>
#include <QMessageBox>
#include <QPoint>
#include <QMenu>
#include <QApplication>
#include <QClipboard>
#include <QLabel>
#include <QDateTimeEdit>
TransactionView::TransactionView(QWidget *parent) :
QWidget(parent), model(0), transactionProxyModel(0),
transactionView(0)
{
// Build filter row
setContentsMargins(0,0,0,0);
QHBoxLayout *hlayout = new QHBoxLayout();
hlayout->setContentsMargins(0,0,0,0);
#ifdef Q_WS_MAC
hlayout->setSpacing(5);
hlayout->addSpacing(26);
#else
hlayout->setSpacing(0);
hlayout->addSpacing(23);
#endif
dateWidget = new QComboBox(this);
#ifdef Q_WS_MAC
dateWidget->setFixedWidth(121);
#else
dateWidget->setFixedWidth(120);
#endif
dateWidget->addItem(tr("All"), All);
dateWidget->addItem(tr("Today"), Today);
dateWidget->addItem(tr("This week"), ThisWeek);
dateWidget->addItem(tr("This month"), ThisMonth);
dateWidget->addItem(tr("Last month"), LastMonth);
dateWidget->addItem(tr("This year"), ThisYear);
dateWidget->addItem(tr("Range..."), Range);
hlayout->addWidget(dateWidget);
typeWidget = new QComboBox(this);
#ifdef Q_WS_MAC
typeWidget->setFixedWidth(121);
#else
typeWidget->setFixedWidth(120);
#endif
typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
TransactionFilterProxy::TYPE(TransactionRecord::RecvFromIP));
typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
TransactionFilterProxy::TYPE(TransactionRecord::SendToIP));
typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
hlayout->addWidget(typeWidget);
addressWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
addressWidget->setPlaceholderText(tr("Enter address or label to search"));
#endif
hlayout->addWidget(addressWidget);
amountWidget = new QLineEdit(this);
#if QT_VERSION >= 0x040700
amountWidget->setPlaceholderText(tr("Min amount"));
#endif
#ifdef Q_WS_MAC
amountWidget->setFixedWidth(97);
#else
amountWidget->setFixedWidth(100);
#endif
amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
hlayout->addWidget(amountWidget);
QVBoxLayout *vlayout = new QVBoxLayout(this);
vlayout->setContentsMargins(0,0,0,0);
vlayout->setSpacing(0);
//vlayout->addLayout(hlayout2);
QTableView *view = new QTableView(this);
vlayout->addLayout(hlayout);
vlayout->addWidget(createDateRangeWidget());
vlayout->addWidget(view);
vlayout->setSpacing(0);
int width = view->verticalScrollBar()->sizeHint().width();
// Cover scroll bar width with spacing
#ifdef Q_WS_MAC
hlayout->addSpacing(width+2);
#else
hlayout->addSpacing(width);
#endif
// Always show scroll bar
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
view->setTabKeyNavigation(false);
view->setContextMenuPolicy(Qt::CustomContextMenu);
transactionView = view;
// Actions
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
QAction *editLabelAction = new QAction(tr("Edit label"), this);
QAction *showDetailsAction = new QAction(tr("Show details..."), this);
contextMenu = new QMenu();
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(editLabelAction);
contextMenu->addAction(showDetailsAction);
// Connect actions
connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
connect(view,
SIGNAL(customContextMenuRequested(QPoint)),
this,
SLOT(contextualMenu(QPoint)));
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel()));
connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
}
void TransactionView::setModel(WalletModel *model)
{
this->model = model;
if(model)
{
transactionProxyModel = new TransactionFilterProxy(this);
transactionProxyModel->setSourceModel(model->getTransactionTableModel());
transactionProxyModel->setDynamicSortFilter(true);
transactionProxyModel->setSortRole(Qt::EditRole);
transactionView->setModel(transactionProxyModel);
transactionView->setAlternatingRowColors(true);
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
transactionView->setSortingEnabled(true);
transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
transactionView->verticalHeader()->hide();
transactionView->horizontalHeader()->resizeSection(
TransactionTableModel::Status, 23);
transactionView->horizontalHeader()->resizeSection(
TransactionTableModel::Date, 120);
transactionView->horizontalHeader()->resizeSection(
TransactionTableModel::Type, 120);
transactionView->horizontalHeader()->setResizeMode(
TransactionTableModel::ToAddress, QHeaderView::Stretch);
transactionView->horizontalHeader()->resizeSection(
TransactionTableModel::Amount, 100);
}
}
void TransactionView::chooseDate(int idx)
{
if(!transactionProxyModel)
return;
QDate current = QDate::currentDate();
dateRangeWidget->setVisible(false);
switch(dateWidget->itemData(idx).toInt())
{
case All:
transactionProxyModel->setDateRange(
TransactionFilterProxy::MIN_DATE,
TransactionFilterProxy::MAX_DATE);
break;
case Today:
transactionProxyModel->setDateRange(
QDateTime(current),
TransactionFilterProxy::MAX_DATE);
break;
case ThisWeek: {
// Find last monday
QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
transactionProxyModel->setDateRange(
QDateTime(startOfWeek),
TransactionFilterProxy::MAX_DATE);
} break;
case ThisMonth:
transactionProxyModel->setDateRange(
QDateTime(QDate(current.year(), current.month(), 1)),
TransactionFilterProxy::MAX_DATE);
break;
case LastMonth:
transactionProxyModel->setDateRange(
QDateTime(QDate(current.year(), current.month()-1, 1)),
QDateTime(QDate(current.year(), current.month(), 1)));
break;
case ThisYear:
transactionProxyModel->setDateRange(
QDateTime(QDate(current.year(), 1, 1)),
TransactionFilterProxy::MAX_DATE);
break;
case Range:
dateRangeWidget->setVisible(true);
dateRangeChanged();
break;
}
}
void TransactionView::chooseType(int idx)
{
if(!transactionProxyModel)
return;
transactionProxyModel->setTypeFilter(
typeWidget->itemData(idx).toInt());
}
void TransactionView::changedPrefix(const QString &prefix)
{
if(!transactionProxyModel)
return;
transactionProxyModel->setAddressPrefix(prefix);
}
void TransactionView::changedAmount(const QString &amount)
{
if(!transactionProxyModel)
return;
qint64 amount_parsed = 0;
if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
{
transactionProxyModel->setMinAmount(amount_parsed);
}
else
{
transactionProxyModel->setMinAmount(0);
}
}
void TransactionView::exportClicked()
{
// CSV is currently the only supported format
QString filename = QFileDialog::getSaveFileName(
this,
tr("Export Transaction Data"),
QDir::currentPath(),
tr("Comma separated file (*.csv)"));
if (filename.isNull()) return;
CSVModelWriter writer(filename);
// name, column, role
writer.setModel(transactionProxyModel);
writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole);
writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);
if(!writer.write())
{
QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
QMessageBox::Abort, QMessageBox::Abort);
}
}
void TransactionView::contextualMenu(const QPoint &point)
{
QModelIndex index = transactionView->indexAt(point);
if(index.isValid())
{
contextMenu->exec(QCursor::pos());
}
}
void TransactionView::copyAddress()
{
if(!transactionView->selectionModel())
return;
QModelIndexList selection = transactionView->selectionModel()->selectedRows();
if(!selection.isEmpty())
{
QApplication::clipboard()->setText(selection.at(0).data(TransactionTableModel::AddressRole).toString());
}
}
void TransactionView::copyLabel()
{
if(!transactionView->selectionModel())
return;
QModelIndexList selection = transactionView->selectionModel()->selectedRows();
if(!selection.isEmpty())
{
QApplication::clipboard()->setText(selection.at(0).data(TransactionTableModel::LabelRole).toString());
}
}
void TransactionView::editLabel()
{
if(!transactionView->selectionModel() ||!model)
return;
QModelIndexList selection = transactionView->selectionModel()->selectedRows();
if(!selection.isEmpty())
{
AddressTableModel *addressBook = model->getAddressTableModel();
if(!addressBook)
return;
QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
if(address.isEmpty())
{
// If this transaction has no associated address, exit
return;
}
// Is address in address book? Address book can miss address when a transaction is
// sent from outside the UI.
int idx = addressBook->lookupAddress(address);
if(idx != -1)
{
// Edit sending / receiving address
QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
// Determine type of address, launch appropriate editor dialog type
QString type = modelIdx.data(AddressTableModel::TypeRole).toString();
EditAddressDialog dlg(type==AddressTableModel::Receive
? EditAddressDialog::EditReceivingAddress
: EditAddressDialog::EditSendingAddress,
this);
dlg.setModel(addressBook);
dlg.loadRow(idx);
dlg.exec();
}
else
{
// Add sending address
EditAddressDialog dlg(EditAddressDialog::NewSendingAddress,
this);
dlg.setModel(addressBook);
dlg.setAddress(address);
dlg.exec();
}
}
}
void TransactionView::showDetails()
{
if(!transactionView->selectionModel())
return;
QModelIndexList selection = transactionView->selectionModel()->selectedRows();
if(!selection.isEmpty())
{
TransactionDescDialog dlg(selection.at(0));
dlg.exec();
}
}
QWidget *TransactionView::createDateRangeWidget()
{
dateRangeWidget = new QFrame();
dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
dateRangeWidget->setContentsMargins(1,1,1,1);
QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
layout->setContentsMargins(0,0,0,0);
layout->addSpacing(23);
layout->addWidget(new QLabel(tr("Range:")));
dateFrom = new QDateTimeEdit(this);
dateFrom->setDisplayFormat("dd/MM/yy");
dateFrom->setCalendarPopup(true);
dateFrom->setMinimumWidth(100);
dateFrom->setDate(QDate::currentDate().addDays(-7));
layout->addWidget(dateFrom);
layout->addWidget(new QLabel(tr("to")));
dateTo = new QDateTimeEdit(this);
dateTo->setDisplayFormat("dd/MM/yy");
dateTo->setCalendarPopup(true);
dateTo->setMinimumWidth(100);
dateTo->setDate(QDate::currentDate());
layout->addWidget(dateTo);
layout->addStretch();
// Hide by default
dateRangeWidget->setVisible(false);
// Notify on change
connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
return dateRangeWidget;
}
void TransactionView::dateRangeChanged()
{
if(!transactionProxyModel)
return;
transactionProxyModel->setDateRange(
QDateTime(dateFrom->date()),
QDateTime(dateTo->date()).addDays(1));
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index f028f10f6c..b71256a23d 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -1,277 +1,278 @@
#include "walletmodel.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"
#include "headers.h"
+#include <QtGlobal>
#include <QTimer>
#include <QSet>
WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
transactionTableModel(0),
cachedBalance(0), cachedUnconfirmedBalance(0), cachedNumTransactions(0),
cachedEncryptionStatus(Unencrypted)
{
// Until signal notifications is built into the bitcoin core,
// simply update everything after polling using a timer.
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(MODEL_UPDATE_DELAY);
addressTableModel = new AddressTableModel(wallet, this);
transactionTableModel = new TransactionTableModel(wallet, this);
}
qint64 WalletModel::getBalance() const
{
return wallet->GetBalance();
}
qint64 WalletModel::getUnconfirmedBalance() const
{
return wallet->GetUnconfirmedBalance();
}
int WalletModel::getNumTransactions() const
{
int numTransactions = 0;
CRITICAL_BLOCK(wallet->cs_wallet)
{
numTransactions = wallet->mapWallet.size();
}
return numTransactions;
}
void WalletModel::update()
{
qint64 newBalance = getBalance();
qint64 newUnconfirmedBalance = getUnconfirmedBalance();
int newNumTransactions = getNumTransactions();
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance)
emit balanceChanged(newBalance, newUnconfirmedBalance);
if(cachedNumTransactions != newNumTransactions)
emit numTransactionsChanged(newNumTransactions);
if(cachedEncryptionStatus != newEncryptionStatus)
emit encryptionStatusChanged(newEncryptionStatus);
cachedBalance = newBalance;
cachedUnconfirmedBalance = newUnconfirmedBalance;
cachedNumTransactions = newNumTransactions;
addressTableModel->update();
}
bool WalletModel::validateAddress(const QString &address)
{
CBitcoinAddress addressParsed(address.toStdString());
return addressParsed.IsValid();
}
WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients)
{
qint64 total = 0;
QSet<QString> setAddress;
QString hex;
if(recipients.empty())
{
return OK;
}
// Pre-check input data for validity
foreach(const SendCoinsRecipient &rcp, recipients)
{
if(!validateAddress(rcp.address))
{
return InvalidAddress;
}
setAddress.insert(rcp.address);
if(rcp.amount <= 0)
{
return InvalidAmount;
}
total += rcp.amount;
}
if(recipients.size() > setAddress.size())
{
return DuplicateAddress;
}
if(total > getBalance())
{
return AmountExceedsBalance;
}
if((total + nTransactionFee) > getBalance())
{
return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
}
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(wallet->cs_wallet)
{
// Sendmany
- std::vector<std::pair<CScript, int64> > vecSend;
+ std::vector<std::pair<CScript, qint64> > vecSend;
foreach(const SendCoinsRecipient &rcp, recipients)
{
CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(rcp.address.toStdString());
vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
}
CWalletTx wtx;
CReserveKey keyChange(wallet);
- int64 nFeeRequired = 0;
+ qint64 nFeeRequired = 0;
bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
if(!fCreated)
{
if((total + nFeeRequired) > wallet->GetBalance())
{
return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
}
return TransactionCreationFailed;
}
if(!ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString(), NULL))
{
return Aborted;
}
if(!wallet->CommitTransaction(wtx, keyChange))
{
return TransactionCommitFailed;
}
hex = QString::fromStdString(wtx.GetHash().GetHex());
}
// Add addresses that we've sent to to the address book
foreach(const SendCoinsRecipient &rcp, recipients)
{
std::string strAddress = rcp.address.toStdString();
CRITICAL_BLOCK(wallet->cs_wallet)
{
if (!wallet->mapAddressBook.count(strAddress))
wallet->SetAddressBookName(strAddress, rcp.label.toStdString());
}
}
// Update our model of the address table
addressTableModel->updateList();
return SendCoinsReturn(OK, 0, hex);
}
OptionsModel *WalletModel::getOptionsModel()
{
return optionsModel;
}
AddressTableModel *WalletModel::getAddressTableModel()
{
return addressTableModel;
}
TransactionTableModel *WalletModel::getTransactionTableModel()
{
return transactionTableModel;
}
WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
if(!wallet->IsCrypted())
{
return Unencrypted;
}
else if(wallet->IsLocked())
{
return Locked;
}
else
{
return Unlocked;
}
}
bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
{
if(encrypted)
{
// Encrypt
return wallet->EncryptWallet(passphrase);
}
else
{
// Decrypt -- TODO; not supported yet
return false;
}
}
bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
{
if(locked)
{
// Lock
return wallet->Lock();
}
else
{
// Unlock
return wallet->Unlock(passPhrase);
}
}
bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
{
bool retval;
CRITICAL_BLOCK(wallet->cs_wallet)
{
wallet->Lock(); // Make sure wallet is locked before attempting pass change
retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
}
return retval;
}
// WalletModel::UnlockContext implementation
WalletModel::UnlockContext WalletModel::requestUnlock()
{
bool was_locked = getEncryptionStatus() == Locked;
if(was_locked)
{
// Request UI to unlock wallet
emit requireUnlock();
}
// If wallet is still locked, unlock was failed or cancelled, mark context as invalid
bool valid = getEncryptionStatus() != Locked;
return UnlockContext(this, valid, was_locked);
}
WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
wallet(wallet),
valid(valid),
relock(relock)
{
}
WalletModel::UnlockContext::~UnlockContext()
{
if(valid && relock)
{
wallet->setWalletLocked(true);
}
}
void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
{
// Transfer context; old object no longer relocks wallet
*this = rhs;
rhs.relock = false;
}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 89e8cdd2a0..6c0d6d2afd 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -1,144 +1,145 @@
#ifndef WALLETMODEL_H
#define WALLETMODEL_H
+#include <QtGlobal>
#include <QObject>
#include "util.h"
class OptionsModel;
class AddressTableModel;
class TransactionTableModel;
class CWallet;
struct SendCoinsRecipient
{
QString address;
QString label;
qint64 amount;
};
/** Interface to Bitcoin wallet from Qt view code. */
class WalletModel : public QObject
{
Q_OBJECT
public:
explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
enum StatusCode // Returned by sendCoins
{
OK,
InvalidAmount,
InvalidAddress,
AmountExceedsBalance,
AmountWithFeeExceedsBalance,
DuplicateAddress,
TransactionCreationFailed, // Error returned when wallet is still locked
TransactionCommitFailed,
Aborted,
MiscError
};
enum EncryptionStatus
{
Unencrypted, // !wallet->IsCrypted()
Locked, // wallet->IsCrypted() && wallet->IsLocked()
Unlocked // wallet->IsCrypted() && !wallet->IsLocked()
};
OptionsModel *getOptionsModel();
AddressTableModel *getAddressTableModel();
TransactionTableModel *getTransactionTableModel();
qint64 getBalance() const;
qint64 getUnconfirmedBalance() const;
int getNumTransactions() const;
EncryptionStatus getEncryptionStatus() const;
// Check address for validity
bool validateAddress(const QString &address);
// Return status record for SendCoins, contains error id + information
struct SendCoinsReturn
{
SendCoinsReturn(StatusCode status,
qint64 fee=0,
QString hex=QString()):
status(status), fee(fee), hex(hex) {}
StatusCode status;
qint64 fee; // is used in case status is "AmountWithFeeExceedsBalance"
QString hex; // is filled with the transaction hash if status is "OK"
};
// Send coins to a list of recipients
SendCoinsReturn sendCoins(const QList<SendCoinsRecipient> &recipients);
// Wallet encryption
bool setWalletEncrypted(bool encrypted, const SecureString &passphrase);
// Passphrase only needed when unlocking
bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString());
bool changePassphrase(const SecureString &oldPass, const SecureString &newPass);
// RAI object for unlocking wallet, returned by requestUnlock()
class UnlockContext
{
public:
UnlockContext(WalletModel *wallet, bool valid, bool relock);
~UnlockContext();
bool isValid() const { return valid; }
// Copy operator and constructor transfer the context
UnlockContext(const UnlockContext& obj) { CopyFrom(obj); }
UnlockContext& operator=(const UnlockContext& rhs) { CopyFrom(rhs); return *this; }
private:
WalletModel *wallet;
bool valid;
mutable bool relock; // mutable, as it can be set to false by copying
void CopyFrom(const UnlockContext& rhs);
};
UnlockContext requestUnlock();
private:
CWallet *wallet;
// Wallet has an options model for wallet-specific options
// (transaction fee, for example)
OptionsModel *optionsModel;
AddressTableModel *addressTableModel;
TransactionTableModel *transactionTableModel;
// Cache some values to be able to detect changes
qint64 cachedBalance;
qint64 cachedUnconfirmedBalance;
qint64 cachedNumTransactions;
EncryptionStatus cachedEncryptionStatus;
signals:
// Signal that balance in wallet changed
void balanceChanged(qint64 balance, qint64 unconfirmedBalance);
// Number of transactions in wallet changed
void numTransactionsChanged(int count);
// Encryption status of wallet changed
void encryptionStatusChanged(int status);
// Signal emitted when wallet needs to be unlocked
// It is valid behaviour for listeners to keep the wallet locked after this signal;
// this means that the unlocking failed or was cancelled.
void requireUnlock();
// Asynchronous error notification
void error(const QString &title, const QString &message);
public slots:
private slots:
void update();
};
#endif // WALLETMODEL_H
diff --git a/src/qtui.h b/src/qtui.h
index 17fc44e94b..3eef1ce5e0 100644
--- a/src/qtui.h
+++ b/src/qtui.h
@@ -1,49 +1,51 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_EXTERNUI_H
#define BITCOIN_EXTERNUI_H
+#include <stdint.h>
+
#include <string>
#include <boost/function/function0.hpp>
#include "wallet.h"
typedef void wxWindow;
#define wxYES 0x00000002
#define wxOK 0x00000004
#define wxNO 0x00000008
#define wxYES_NO (wxYES|wxNO)
#define wxCANCEL 0x00000010
#define wxAPPLY 0x00000020
#define wxCLOSE 0x00000040
#define wxOK_DEFAULT 0x00000000
#define wxYES_DEFAULT 0x00000000
#define wxNO_DEFAULT 0x00000080
#define wxCANCEL_DEFAULT 0x80000000
#define wxICON_EXCLAMATION 0x00000100
#define wxICON_HAND 0x00000200
#define wxICON_WARNING wxICON_EXCLAMATION
#define wxICON_ERROR wxICON_HAND
#define wxICON_QUESTION 0x00000400
#define wxICON_INFORMATION 0x00000800
#define wxICON_STOP wxICON_HAND
#define wxICON_ASTERISK wxICON_INFORMATION
#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800)
#define wxFORWARD 0x00001000
#define wxBACKWARD 0x00002000
#define wxRESET 0x00004000
#define wxHELP 0x00008000
#define wxMORE 0x00010000
#define wxSETUP 0x00020000
extern int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
#define wxMessageBox MyMessageBox
extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
-extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent);
+extern bool ThreadSafeAskFee(int64_t nFeeRequired, const std::string& strCaption, wxWindow* parent);
extern void CalledSetStatusBar(const std::string& strText, int nField);
extern void UIThreadCall(boost::function0<void> fn);
extern void MainFrameRepaint();
extern void InitMessage(const std::string &message);
extern std::string _(const char* psz);
#endif
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index f3978fbce8..c7c5b1d36c 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -1,101 +1,103 @@
// Copyright (c) 2011 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 <stdint.h>
+
#include "headers.h"
#include "init.h" // for pwalletMain
#include "bitcoinrpc.h"
// #include <boost/asio.hpp>
// #include <boost/iostreams/concepts.hpp>
// #include <boost/iostreams/stream.hpp>
#include <boost/lexical_cast.hpp>
// #ifdef USE_SSL
// #include <boost/asio/ssl.hpp>
// typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
// #endif
// #include <boost/xpressive/xpressive_dynamic.hpp>
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"
#define printf OutputDebugStringF
// using namespace boost::asio;
using namespace json_spirit;
using namespace std;
extern Object JSONRPCError(int code, const string& message);
class CTxDump
{
public:
CBlockIndex *pindex;
- int64 nValue;
+ int64_t nValue;
bool fSpent;
CWalletTx* ptx;
int nOut;
CTxDump(CWalletTx* ptx = NULL, int nOut = -1)
{
pindex = NULL;
nValue = 0;
fSpent = false;
this->ptx = ptx;
this->nOut = nOut;
}
};
Value importprivkey(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"importprivkey <bitcoinprivkey> [label]\n"
"Adds a private key (as returned by dumpprivkey) to your wallet.");
string strSecret = params[0].get_str();
string strLabel = "";
if (params.size() > 1)
strLabel = params[1].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strSecret);
if (!fGood) throw JSONRPCError(-5,"Invalid private key");
CKey key;
key.SetSecret(vchSecret.GetSecret());
CBitcoinAddress vchAddress = CBitcoinAddress(key.GetPubKey());
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
pwalletMain->MarkDirty();
pwalletMain->SetAddressBookName(vchAddress, strLabel);
if (!pwalletMain->AddKey(key))
throw JSONRPCError(-4,"Error adding key to wallet");
pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
pwalletMain->ReacceptWalletTransactions();
}
MainFrameRepaint();
return Value::null;
}
Value dumpprivkey(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"dumpprivkey <bitcoinaddress>\n"
"Reveals the private key corresponding to <bitcoinaddress>.");
string strAddress = params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
throw JSONRPCError(-5, "Invalid bitcoin address");
CSecret vchSecret;
if (!pwalletMain->GetSecret(address, vchSecret))
throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known");
return CBitcoinSecret(vchSecret).ToString();
}
diff --git a/src/script.h b/src/script.h
index b671e15963..e3c6b15b6d 100644
--- a/src/script.h
+++ b/src/script.h
@@ -1,580 +1,582 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef H_BITCOIN_SCRIPT
#define H_BITCOIN_SCRIPT
+#include <stdint.h>
+
#include "base58.h"
#include <string>
#include <vector>
#include <boost/foreach.hpp>
class CTransaction;
class CKeyStore;
enum
{
SIGHASH_ALL = 1,
SIGHASH_NONE = 2,
SIGHASH_SINGLE = 3,
SIGHASH_ANYONECANPAY = 0x80,
};
enum txnouttype
{
TX_NONSTANDARD,
// 'standard' transaction types:
TX_PUBKEY,
TX_PUBKEYHASH,
TX_SCRIPTHASH,
TX_MULTISIG,
};
const char* GetTxnOutputType(txnouttype t);
enum opcodetype
{
// push value
OP_0=0,
OP_FALSE=OP_0,
OP_PUSHDATA1=76,
OP_PUSHDATA2,
OP_PUSHDATA4,
OP_1NEGATE,
OP_RESERVED,
OP_1,
OP_TRUE=OP_1,
OP_2,
OP_3,
OP_4,
OP_5,
OP_6,
OP_7,
OP_8,
OP_9,
OP_10,
OP_11,
OP_12,
OP_13,
OP_14,
OP_15,
OP_16,
// control
OP_NOP,
OP_VER,
OP_IF,
OP_NOTIF,
OP_VERIF,
OP_VERNOTIF,
OP_ELSE,
OP_ENDIF,
OP_VERIFY,
OP_RETURN,
// stack ops
OP_TOALTSTACK,
OP_FROMALTSTACK,
OP_2DROP,
OP_2DUP,
OP_3DUP,
OP_2OVER,
OP_2ROT,
OP_2SWAP,
OP_IFDUP,
OP_DEPTH,
OP_DROP,
OP_DUP,
OP_NIP,
OP_OVER,
OP_PICK,
OP_ROLL,
OP_ROT,
OP_SWAP,
OP_TUCK,
// splice ops
OP_CAT,
OP_SUBSTR,
OP_LEFT,
OP_RIGHT,
OP_SIZE,
// bit logic
OP_INVERT,
OP_AND,
OP_OR,
OP_XOR,
OP_EQUAL,
OP_EQUALVERIFY,
OP_RESERVED1,
OP_RESERVED2,
// numeric
OP_1ADD,
OP_1SUB,
OP_2MUL,
OP_2DIV,
OP_NEGATE,
OP_ABS,
OP_NOT,
OP_0NOTEQUAL,
OP_ADD,
OP_SUB,
OP_MUL,
OP_DIV,
OP_MOD,
OP_LSHIFT,
OP_RSHIFT,
OP_BOOLAND,
OP_BOOLOR,
OP_NUMEQUAL,
OP_NUMEQUALVERIFY,
OP_NUMNOTEQUAL,
OP_LESSTHAN,
OP_GREATERTHAN,
OP_LESSTHANOREQUAL,
OP_GREATERTHANOREQUAL,
OP_MIN,
OP_MAX,
OP_WITHIN,
// crypto
OP_RIPEMD160,
OP_SHA1,
OP_SHA256,
OP_HASH160,
OP_HASH256,
OP_CODESEPARATOR,
OP_CHECKSIG,
OP_CHECKSIGVERIFY,
OP_CHECKMULTISIG,
OP_CHECKMULTISIGVERIFY,
// meta
OP_EVAL, // Was OP_NOP1
// expansion
OP_NOP2,
OP_NOP3,
OP_NOP4,
OP_NOP5,
OP_NOP6,
OP_NOP7,
OP_NOP8,
OP_NOP9,
OP_NOP10,
// template matching params
OP_SMALLINTEGER = 0xfa,
OP_PUBKEYS = 0xfb,
OP_SCRIPTHASH = 0xfc,
OP_PUBKEYHASH = 0xfd,
OP_PUBKEY = 0xfe,
OP_INVALIDOPCODE = 0xff,
};
const char* GetOpName(opcodetype opcode);
inline std::string ValueString(const std::vector<unsigned char>& vch)
{
if (vch.size() <= 4)
return strprintf("%d", CBigNum(vch).getint());
else
return HexStr(vch);
}
inline std::string StackString(const std::vector<std::vector<unsigned char> >& vStack)
{
std::string str;
BOOST_FOREACH(const std::vector<unsigned char>& vch, vStack)
{
if (!str.empty())
str += " ";
str += ValueString(vch);
}
return str;
}
class CScript : public std::vector<unsigned char>
{
protected:
- CScript& push_int64(int64 n)
+ CScript& push_int64(int64_t n)
{
if (n == -1 || (n >= 1 && n <= 16))
{
push_back(n + (OP_1 - 1));
}
else
{
CBigNum bn(n);
*this << bn.getvch();
}
return *this;
}
- CScript& push_uint64(uint64 n)
+ CScript& push_uint64(uint64_t n)
{
if (n >= 1 && n <= 16)
{
push_back(n + (OP_1 - 1));
}
else
{
CBigNum bn(n);
*this << bn.getvch();
}
return *this;
}
public:
CScript() { }
CScript(const CScript& b) : std::vector<unsigned char>(b.begin(), b.end()) { }
CScript(const_iterator pbegin, const_iterator pend) : std::vector<unsigned char>(pbegin, pend) { }
#ifndef _MSC_VER
CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector<unsigned char>(pbegin, pend) { }
#endif
CScript& operator+=(const CScript& b)
{
insert(end(), b.begin(), b.end());
return *this;
}
friend CScript operator+(const CScript& a, const CScript& b)
{
CScript ret = a;
ret += b;
return ret;
}
explicit CScript(char b) { operator<<(b); }
explicit CScript(short b) { operator<<(b); }
explicit CScript(int b) { operator<<(b); }
explicit CScript(long b) { operator<<(b); }
- explicit CScript(int64 b) { operator<<(b); }
+ explicit CScript(int64_t b) { operator<<(b); }
explicit CScript(unsigned char b) { operator<<(b); }
explicit CScript(unsigned int b) { operator<<(b); }
explicit CScript(unsigned short b) { operator<<(b); }
explicit CScript(unsigned long b) { operator<<(b); }
- explicit CScript(uint64 b) { operator<<(b); }
+ explicit CScript(uint64_t b) { operator<<(b); }
explicit CScript(opcodetype b) { operator<<(b); }
explicit CScript(const uint256& b) { operator<<(b); }
explicit CScript(const CBigNum& b) { operator<<(b); }
explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); }
CScript& operator<<(char b) { return push_int64(b); }
CScript& operator<<(short b) { return push_int64(b); }
CScript& operator<<(int b) { return push_int64(b); }
CScript& operator<<(long b) { return push_int64(b); }
- CScript& operator<<(int64 b) { return push_int64(b); }
+ CScript& operator<<(int64_t b) { return push_int64(b); }
CScript& operator<<(unsigned char b) { return push_uint64(b); }
CScript& operator<<(unsigned int b) { return push_uint64(b); }
CScript& operator<<(unsigned short b) { return push_uint64(b); }
CScript& operator<<(unsigned long b) { return push_uint64(b); }
- CScript& operator<<(uint64 b) { return push_uint64(b); }
+ CScript& operator<<(uint64_t b) { return push_uint64(b); }
CScript& operator<<(opcodetype opcode)
{
if (opcode < 0 || opcode > 0xff)
throw std::runtime_error("CScript::operator<<() : invalid opcode");
insert(end(), (unsigned char)opcode);
return *this;
}
CScript& operator<<(const uint160& b)
{
insert(end(), sizeof(b));
insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b));
return *this;
}
CScript& operator<<(const uint256& b)
{
insert(end(), sizeof(b));
insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b));
return *this;
}
CScript& operator<<(const CBigNum& b)
{
*this << b.getvch();
return *this;
}
CScript& operator<<(const std::vector<unsigned char>& b)
{
if (b.size() < OP_PUSHDATA1)
{
insert(end(), (unsigned char)b.size());
}
else if (b.size() <= 0xff)
{
insert(end(), OP_PUSHDATA1);
insert(end(), (unsigned char)b.size());
}
else if (b.size() <= 0xffff)
{
insert(end(), OP_PUSHDATA2);
unsigned short nSize = b.size();
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
}
else
{
insert(end(), OP_PUSHDATA4);
unsigned int nSize = b.size();
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
}
insert(end(), b.begin(), b.end());
return *this;
}
CScript& operator<<(const CScript& b)
{
// I'm not sure if this should push the script or concatenate scripts.
// If there's ever a use for pushing a script onto a script, delete this member fn
assert(!"warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate");
return *this;
}
bool GetOp(iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet)
{
// Wrapper so it can be called with either iterator or const_iterator
const_iterator pc2 = pc;
bool fRet = GetOp2(pc2, opcodeRet, &vchRet);
pc = begin() + (pc2 - begin());
return fRet;
}
bool GetOp(iterator& pc, opcodetype& opcodeRet)
{
const_iterator pc2 = pc;
bool fRet = GetOp2(pc2, opcodeRet, NULL);
pc = begin() + (pc2 - begin());
return fRet;
}
bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const
{
return GetOp2(pc, opcodeRet, &vchRet);
}
bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const
{
return GetOp2(pc, opcodeRet, NULL);
}
bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet) const
{
opcodeRet = OP_INVALIDOPCODE;
if (pvchRet)
pvchRet->clear();
if (pc >= end())
return false;
// Read instruction
if (end() - pc < 1)
return false;
unsigned int opcode = *pc++;
// Immediate operand
if (opcode <= OP_PUSHDATA4)
{
unsigned int nSize;
if (opcode < OP_PUSHDATA1)
{
nSize = opcode;
}
else if (opcode == OP_PUSHDATA1)
{
if (end() - pc < 1)
return false;
nSize = *pc++;
}
else if (opcode == OP_PUSHDATA2)
{
if (end() - pc < 2)
return false;
nSize = 0;
memcpy(&nSize, &pc[0], 2);
pc += 2;
}
else if (opcode == OP_PUSHDATA4)
{
if (end() - pc < 4)
return false;
memcpy(&nSize, &pc[0], 4);
pc += 4;
}
if (end() - pc < nSize)
return false;
if (pvchRet)
pvchRet->assign(pc, pc + nSize);
pc += nSize;
}
opcodeRet = (opcodetype)opcode;
return true;
}
// Encode/decode small integers:
static int DecodeOP_N(opcodetype opcode)
{
if (opcode == OP_0)
return 0;
assert(opcode >= OP_1 && opcode <= OP_16);
return (int)opcode - (int)(OP_1 - 1);
}
static opcodetype EncodeOP_N(int n)
{
assert(n >= 0 && n <= 16);
if (n == 0)
return OP_0;
return (opcodetype)(OP_1+n-1);
}
int FindAndDelete(const CScript& b)
{
int nFound = 0;
if (b.empty())
return nFound;
iterator pc = begin();
opcodetype opcode;
do
{
while (end() - pc >= b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
{
erase(pc, pc + b.size());
++nFound;
}
}
while (GetOp(pc, opcode));
return nFound;
}
int Find(opcodetype op) const
{
int nFound = 0;
opcodetype opcode;
for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);)
if (opcode == op)
++nFound;
return nFound;
}
// This method should be removed when a compatibility-breaking block chain split has passed.
// Compatibility method for old clients that count sigops differently:
int GetSigOpCount() const
{
int n = 0;
const_iterator pc = begin();
while (pc < end())
{
opcodetype opcode;
if (!GetOp(pc, opcode))
break;
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
n++;
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
n += 20;
}
return n;
}
// Called by CTransaction::IsStandard
bool IsPushOnly() const
{
const_iterator pc = begin();
while (pc < end())
{
opcodetype opcode;
if (!GetOp(pc, opcode))
return false;
if (opcode > OP_16)
return false;
}
return true;
}
void SetBitcoinAddress(const CBitcoinAddress& address);
void SetBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
{
SetBitcoinAddress(CBitcoinAddress(vchPubKey));
}
void SetMultisig(int nRequired, const std::vector<CKey>& keys);
void SetEval(const CScript& subscript);
void PrintHex() const
{
printf("CScript(%s)\n", HexStr(begin(), end(), true).c_str());
}
std::string ToString() const
{
std::string str;
opcodetype opcode;
std::vector<unsigned char> vch;
const_iterator pc = begin();
while (pc < end())
{
if (!str.empty())
str += " ";
if (!GetOp(pc, opcode, vch))
{
str += "[error]";
return str;
}
if (0 <= opcode && opcode <= OP_PUSHDATA4)
str += ValueString(vch);
else
str += GetOpName(opcode);
}
return str;
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType, bool fStrictOpEval, int& nSigOpCountRet);
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
bool IsStandard(const CScript& scriptPubKey);
bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* pkeystore, CBitcoinAddress& addressRet);
bool ExtractAddresses(const CScript& scriptPubKey, const CKeyStore* pkeystore, txnouttype& typeRet, std::vector<CBitcoinAddress>& addressRet, int& nRequiredRet);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript());
bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int& nSigOpCountRet, int nHashType=0, bool fStrictOpEval=true);
#endif
diff --git a/src/serialize.h b/src/serialize.h
index 54555907d8..4bfff0a1a2 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1,1304 +1,1303 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_SERIALIZE_H
#define BITCOIN_SERIALIZE_H
+#include <stdint.h>
+
#include <string>
#include <vector>
#include <map>
#include <set>
#include <cassert>
#include <limits>
#include <cstring>
#include <cstdio>
#include <boost/type_traits/is_fundamental.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/tuple/tuple_io.hpp>
-typedef long long int64;
-typedef unsigned long long uint64;
-
#ifdef WIN32
#include <windows.h>
// This is used to attempt to keep keying material out of swap
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
#include <windows.h>
#define mlock(p, n) VirtualLock((p), (n));
#define munlock(p, n) VirtualUnlock((p), (n));
#else
#include <sys/mman.h>
#include <limits.h>
/* This comes from limits.h if it's not defined there set a sane default */
#ifndef PAGESIZE
#include <unistd.h>
#define PAGESIZE sysconf(_SC_PAGESIZE)
#endif
#define mlock(a,b) \
mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
(((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
#define munlock(a,b) \
munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
(((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
#endif
class CScript;
class CDataStream;
class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000;
static const int PROTOCOL_VERSION = 60000;
// Used to bypass the rule against non-const reference to temporary
// where it makes sense with wrappers such as CFlatData or CTxDB
template<typename T>
inline T& REF(const T& val)
{
return const_cast<T&>(val);
}
/////////////////////////////////////////////////////////////////
//
// Templates for serializing to anything that looks like a stream,
// i.e. anything that supports .read(char*, int) and .write(char*, int)
//
enum
{
// primary actions
SER_NETWORK = (1 << 0),
SER_DISK = (1 << 1),
SER_GETHASH = (1 << 2),
// modifiers
SER_SKIPSIG = (1 << 16),
SER_BLOCKHEADERONLY = (1 << 17),
};
#define IMPLEMENT_SERIALIZE(statements) \
unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const \
{ \
CSerActionGetSerializeSize ser_action; \
const bool fGetSize = true; \
const bool fWrite = false; \
const bool fRead = false; \
unsigned int nSerSize = 0; \
ser_streamplaceholder s; \
s.nType = nType; \
s.nVersion = nVersion; \
{statements} \
return nSerSize; \
} \
template<typename Stream> \
void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const \
{ \
CSerActionSerialize ser_action; \
const bool fGetSize = false; \
const bool fWrite = true; \
const bool fRead = false; \
unsigned int nSerSize = 0; \
{statements} \
} \
template<typename Stream> \
void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) \
{ \
CSerActionUnserialize ser_action; \
const bool fGetSize = false; \
const bool fWrite = false; \
const bool fRead = true; \
unsigned int nSerSize = 0; \
{statements} \
}
#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))
//
// Basic types
//
#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj))
#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj))
inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); }
-inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); }
-inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(int64_t a, int, int=0) { return sizeof(a); }
+inline unsigned int GetSerializeSize(uint64_t a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); }
template<typename Stream> inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); }
-template<typename Stream> inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, int64_t a, int, int=0) { WRITEDATA(s, a); }
+template<typename Stream> inline void Serialize(Stream& s, uint64_t a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); }
-template<typename Stream> inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); }
-template<typename Stream> inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, int64_t& a, int, int=0) { READDATA(s, a); }
+template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); }
inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); }
template<typename Stream> inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); }
template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; }
//
// Compact size
// size < 253 -- 1 byte
// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes)
// size <= UINT_MAX -- 5 bytes (254 + 4 bytes)
// size > UINT_MAX -- 9 bytes (255 + 8 bytes)
//
-inline unsigned int GetSizeOfCompactSize(uint64 nSize)
+inline unsigned int GetSizeOfCompactSize(uint64_t nSize)
{
if (nSize < 253) return sizeof(unsigned char);
else if (nSize <= std::numeric_limits<unsigned short>::max()) return sizeof(unsigned char) + sizeof(unsigned short);
else if (nSize <= std::numeric_limits<unsigned int>::max()) return sizeof(unsigned char) + sizeof(unsigned int);
- else return sizeof(unsigned char) + sizeof(uint64);
+ else return sizeof(unsigned char) + sizeof(uint64_t);
}
template<typename Stream>
-void WriteCompactSize(Stream& os, uint64 nSize)
+void WriteCompactSize(Stream& os, uint64_t nSize)
{
if (nSize < 253)
{
unsigned char chSize = nSize;
WRITEDATA(os, chSize);
}
else if (nSize <= std::numeric_limits<unsigned short>::max())
{
unsigned char chSize = 253;
unsigned short xSize = nSize;
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
}
else if (nSize <= std::numeric_limits<unsigned int>::max())
{
unsigned char chSize = 254;
unsigned int xSize = nSize;
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
}
else
{
unsigned char chSize = 255;
- uint64 xSize = nSize;
+ uint64_t xSize = nSize;
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
}
return;
}
template<typename Stream>
-uint64 ReadCompactSize(Stream& is)
+uint64_t ReadCompactSize(Stream& is)
{
unsigned char chSize;
READDATA(is, chSize);
- uint64 nSizeRet = 0;
+ uint64_t nSizeRet = 0;
if (chSize < 253)
{
nSizeRet = chSize;
}
else if (chSize == 253)
{
unsigned short xSize;
READDATA(is, xSize);
nSizeRet = xSize;
}
else if (chSize == 254)
{
unsigned int xSize;
READDATA(is, xSize);
nSizeRet = xSize;
}
else
{
- uint64 xSize;
+ uint64_t xSize;
READDATA(is, xSize);
nSizeRet = xSize;
}
- if (nSizeRet > (uint64)MAX_SIZE)
+ if (nSizeRet > (uint64_t)MAX_SIZE)
throw std::ios_base::failure("ReadCompactSize() : size too large");
return nSizeRet;
}
//
// Wrapper for serializing arrays and POD
// There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it
//
#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
class CFlatData
{
protected:
char* pbegin;
char* pend;
public:
CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { }
char* begin() { return pbegin; }
const char* begin() const { return pbegin; }
char* end() { return pend; }
const char* end() const { return pend; }
unsigned int GetSerializeSize(int, int=0) const
{
return pend - pbegin;
}
template<typename Stream>
void Serialize(Stream& s, int, int=0) const
{
s.write(pbegin, pend - pbegin);
}
template<typename Stream>
void Unserialize(Stream& s, int, int=0)
{
s.read(pbegin, pend - pbegin);
}
};
//
// string stored as a fixed length field
//
template<std::size_t LEN>
class CFixedFieldString
{
protected:
const std::string* pcstr;
std::string* pstr;
public:
explicit CFixedFieldString(const std::string& str) : pcstr(&str), pstr(NULL) { }
explicit CFixedFieldString(std::string& str) : pcstr(&str), pstr(&str) { }
unsigned int GetSerializeSize(int, int=0) const
{
return LEN;
}
template<typename Stream>
void Serialize(Stream& s, int, int=0) const
{
char pszBuf[LEN];
strncpy(pszBuf, pcstr->c_str(), LEN);
s.write(pszBuf, LEN);
}
template<typename Stream>
void Unserialize(Stream& s, int, int=0)
{
if (pstr == NULL)
throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string");
char pszBuf[LEN+1];
s.read(pszBuf, LEN);
pszBuf[LEN] = '\0';
*pstr = pszBuf;
}
};
//
// Forward declarations
//
// string
template<typename C> unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int=0);
template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str, int, int=0);
template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str, int, int=0);
// vector
template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion=PROTOCOL_VERSION);
// others derived from vector
extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion=PROTOCOL_VERSION);
// pair
template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion=PROTOCOL_VERSION);
// 3 tuple
template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion=PROTOCOL_VERSION);
// 4 tuple
template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion=PROTOCOL_VERSION);
// map
template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
// set
template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion=PROTOCOL_VERSION);
//
// If none of the specialized versions above matched, default to calling member function.
// "int nType" is changed to "long nType" to keep from getting an ambiguous overload error.
// The compiler will only cast int to long if none of the other templates matched.
// Thanks to Boost serialization for this idea.
//
template<typename T>
inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=PROTOCOL_VERSION)
{
return a.GetSerializeSize((int)nType, nVersion);
}
template<typename Stream, typename T>
inline void Serialize(Stream& os, const T& a, long nType, int nVersion=PROTOCOL_VERSION)
{
a.Serialize(os, (int)nType, nVersion);
}
template<typename Stream, typename T>
inline void Unserialize(Stream& is, T& a, long nType, int nVersion=PROTOCOL_VERSION)
{
a.Unserialize(is, (int)nType, nVersion);
}
//
// string
//
template<typename C>
unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int)
{
return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]);
}
template<typename Stream, typename C>
void Serialize(Stream& os, const std::basic_string<C>& str, int, int)
{
WriteCompactSize(os, str.size());
if (!str.empty())
os.write((char*)&str[0], str.size() * sizeof(str[0]));
}
template<typename Stream, typename C>
void Unserialize(Stream& is, std::basic_string<C>& str, int, int)
{
unsigned int nSize = ReadCompactSize(is);
str.resize(nSize);
if (nSize != 0)
is.read((char*)&str[0], nSize * sizeof(str[0]));
}
//
// vector
//
template<typename T, typename A>
unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
{
return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T));
}
template<typename T, typename A>
unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
{
unsigned int nSize = GetSizeOfCompactSize(v.size());
for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
nSize += GetSerializeSize((*vi), nType, nVersion);
return nSize;
}
template<typename T, typename A>
inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion)
{
return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental<T>());
}
template<typename Stream, typename T, typename A>
void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
{
WriteCompactSize(os, v.size());
if (!v.empty())
os.write((char*)&v[0], v.size() * sizeof(T));
}
template<typename Stream, typename T, typename A>
void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
{
WriteCompactSize(os, v.size());
for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
::Serialize(os, (*vi), nType, nVersion);
}
template<typename Stream, typename T, typename A>
inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion)
{
Serialize_impl(os, v, nType, nVersion, boost::is_fundamental<T>());
}
template<typename Stream, typename T, typename A>
void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
{
//unsigned int nSize = ReadCompactSize(is);
//v.resize(nSize);
//is.read((char*)&v[0], nSize * sizeof(T));
// Limit size per read so bogus size value won't cause out of memory
v.clear();
unsigned int nSize = ReadCompactSize(is);
unsigned int i = 0;
while (i < nSize)
{
unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
v.resize(i + blk);
is.read((char*)&v[i], blk * sizeof(T));
i += blk;
}
}
template<typename Stream, typename T, typename A>
void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
{
//unsigned int nSize = ReadCompactSize(is);
//v.resize(nSize);
//for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi)
// Unserialize(is, (*vi), nType, nVersion);
v.clear();
unsigned int nSize = ReadCompactSize(is);
unsigned int i = 0;
unsigned int nMid = 0;
while (nMid < nSize)
{
nMid += 5000000 / sizeof(T);
if (nMid > nSize)
nMid = nSize;
v.resize(nMid);
for (; i < nMid; i++)
Unserialize(is, v[i], nType, nVersion);
}
}
template<typename Stream, typename T, typename A>
inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion)
{
Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental<T>());
}
//
// others derived from vector
//
inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion)
{
return GetSerializeSize((const std::vector<unsigned char>&)v, nType, nVersion);
}
template<typename Stream>
void Serialize(Stream& os, const CScript& v, int nType, int nVersion)
{
Serialize(os, (const std::vector<unsigned char>&)v, nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream& is, CScript& v, int nType, int nVersion)
{
Unserialize(is, (std::vector<unsigned char>&)v, nType, nVersion);
}
//
// pair
//
template<typename K, typename T>
unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion)
{
return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion);
}
template<typename Stream, typename K, typename T>
void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion)
{
Serialize(os, item.first, nType, nVersion);
Serialize(os, item.second, nType, nVersion);
}
template<typename Stream, typename K, typename T>
void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion)
{
Unserialize(is, item.first, nType, nVersion);
Unserialize(is, item.second, nType, nVersion);
}
//
// 3 tuple
//
template<typename T0, typename T1, typename T2>
unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
{
unsigned int nSize = 0;
nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion);
nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion);
nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion);
return nSize;
}
template<typename Stream, typename T0, typename T1, typename T2>
void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
{
Serialize(os, boost::get<0>(item), nType, nVersion);
Serialize(os, boost::get<1>(item), nType, nVersion);
Serialize(os, boost::get<2>(item), nType, nVersion);
}
template<typename Stream, typename T0, typename T1, typename T2>
void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion)
{
Unserialize(is, boost::get<0>(item), nType, nVersion);
Unserialize(is, boost::get<1>(item), nType, nVersion);
Unserialize(is, boost::get<2>(item), nType, nVersion);
}
//
// 4 tuple
//
template<typename T0, typename T1, typename T2, typename T3>
unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
{
unsigned int nSize = 0;
nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion);
nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion);
nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion);
nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion);
return nSize;
}
template<typename Stream, typename T0, typename T1, typename T2, typename T3>
void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
{
Serialize(os, boost::get<0>(item), nType, nVersion);
Serialize(os, boost::get<1>(item), nType, nVersion);
Serialize(os, boost::get<2>(item), nType, nVersion);
Serialize(os, boost::get<3>(item), nType, nVersion);
}
template<typename Stream, typename T0, typename T1, typename T2, typename T3>
void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion)
{
Unserialize(is, boost::get<0>(item), nType, nVersion);
Unserialize(is, boost::get<1>(item), nType, nVersion);
Unserialize(is, boost::get<2>(item), nType, nVersion);
Unserialize(is, boost::get<3>(item), nType, nVersion);
}
//
// map
//
template<typename K, typename T, typename Pred, typename A>
unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion)
{
unsigned int nSize = GetSizeOfCompactSize(m.size());
for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
nSize += GetSerializeSize((*mi), nType, nVersion);
return nSize;
}
template<typename Stream, typename K, typename T, typename Pred, typename A>
void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion)
{
WriteCompactSize(os, m.size());
for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
Serialize(os, (*mi), nType, nVersion);
}
template<typename Stream, typename K, typename T, typename Pred, typename A>
void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion)
{
m.clear();
unsigned int nSize = ReadCompactSize(is);
typename std::map<K, T, Pred, A>::iterator mi = m.begin();
for (unsigned int i = 0; i < nSize; i++)
{
std::pair<K, T> item;
Unserialize(is, item, nType, nVersion);
mi = m.insert(mi, item);
}
}
//
// set
//
template<typename K, typename Pred, typename A>
unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion)
{
unsigned int nSize = GetSizeOfCompactSize(m.size());
for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
nSize += GetSerializeSize((*it), nType, nVersion);
return nSize;
}
template<typename Stream, typename K, typename Pred, typename A>
void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion)
{
WriteCompactSize(os, m.size());
for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
Serialize(os, (*it), nType, nVersion);
}
template<typename Stream, typename K, typename Pred, typename A>
void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion)
{
m.clear();
unsigned int nSize = ReadCompactSize(is);
typename std::set<K, Pred, A>::iterator it = m.begin();
for (unsigned int i = 0; i < nSize; i++)
{
K key;
Unserialize(is, key, nType, nVersion);
it = m.insert(it, key);
}
}
//
// Support for IMPLEMENT_SERIALIZE and READWRITE macro
//
class CSerActionGetSerializeSize { };
class CSerActionSerialize { };
class CSerActionUnserialize { };
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action)
{
return ::GetSerializeSize(obj, nType, nVersion);
}
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action)
{
::Serialize(s, obj, nType, nVersion);
return 0;
}
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action)
{
::Unserialize(s, obj, nType, nVersion);
return 0;
}
struct ser_streamplaceholder
{
int nType;
int nVersion;
};
//
// Allocator that locks its contents from being paged
// out of memory and clears its contents before deletion.
//
template<typename T>
struct secure_allocator : public std::allocator<T>
{
// MSVC8 default copy constructor is broken
typedef std::allocator<T> base;
typedef typename base::size_type size_type;
typedef typename base::difference_type difference_type;
typedef typename base::pointer pointer;
typedef typename base::const_pointer const_pointer;
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
secure_allocator() throw() {}
secure_allocator(const secure_allocator& a) throw() : base(a) {}
template <typename U>
secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
~secure_allocator() throw() {}
template<typename _Other> struct rebind
{ typedef secure_allocator<_Other> other; };
T* allocate(std::size_t n, const void *hint = 0)
{
T *p;
p = std::allocator<T>::allocate(n, hint);
if (p != NULL)
mlock(p, sizeof(T) * n);
return p;
}
void deallocate(T* p, std::size_t n)
{
if (p != NULL)
{
memset(p, 0, sizeof(T) * n);
munlock(p, sizeof(T) * n);
}
std::allocator<T>::deallocate(p, n);
}
};
//
// Double ended buffer combining vector and stream-like interfaces.
// >> and << read and write unformatted data using the above serialization templates.
// Fills with data in linear time; some stringstream implementations take N^2 time.
//
class CDataStream
{
protected:
typedef std::vector<char, secure_allocator<char> > vector_type;
vector_type vch;
unsigned int nReadPos;
short state;
short exceptmask;
public:
int nType;
int nVersion;
typedef vector_type::allocator_type allocator_type;
typedef vector_type::size_type size_type;
typedef vector_type::difference_type difference_type;
typedef vector_type::reference reference;
typedef vector_type::const_reference const_reference;
typedef vector_type::value_type value_type;
typedef vector_type::iterator iterator;
typedef vector_type::const_iterator const_iterator;
typedef vector_type::reverse_iterator reverse_iterator;
explicit CDataStream(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION)
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1300
CDataStream(const char* pbegin, const char* pend, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
#endif
CDataStream(const vector_type& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end())
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const std::vector<char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end())
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
{
Init(nTypeIn, nVersionIn);
}
void Init(int nTypeIn=SER_NETWORK, int nVersionIn=PROTOCOL_VERSION)
{
nReadPos = 0;
nType = nTypeIn;
nVersion = nVersionIn;
state = 0;
exceptmask = std::ios::badbit | std::ios::failbit;
}
CDataStream& operator+=(const CDataStream& b)
{
vch.insert(vch.end(), b.begin(), b.end());
return *this;
}
friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
{
CDataStream ret = a;
ret += b;
return (ret);
}
std::string str() const
{
return (std::string(begin(), end()));
}
//
// Vector subset
//
const_iterator begin() const { return vch.begin() + nReadPos; }
iterator begin() { return vch.begin() + nReadPos; }
const_iterator end() const { return vch.end(); }
iterator end() { return vch.end(); }
size_type size() const { return vch.size() - nReadPos; }
bool empty() const { return vch.size() == nReadPos; }
void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
void reserve(size_type n) { vch.reserve(n + nReadPos); }
const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
reference operator[](size_type pos) { return vch[pos + nReadPos]; }
void clear() { vch.clear(); nReadPos = 0; }
iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
void insert(iterator it, const_iterator first, const_iterator last)
{
if (it == vch.begin() + nReadPos && last - first <= nReadPos)
{
// special case for inserting at the front when there's room
nReadPos -= (last - first);
memcpy(&vch[nReadPos], &first[0], last - first);
}
else
vch.insert(it, first, last);
}
void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last)
{
if (it == vch.begin() + nReadPos && last - first <= nReadPos)
{
// special case for inserting at the front when there's room
nReadPos -= (last - first);
memcpy(&vch[nReadPos], &first[0], last - first);
}
else
vch.insert(it, first, last);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1300
void insert(iterator it, const char* first, const char* last)
{
if (it == vch.begin() + nReadPos && last - first <= nReadPos)
{
// special case for inserting at the front when there's room
nReadPos -= (last - first);
memcpy(&vch[nReadPos], &first[0], last - first);
}
else
vch.insert(it, first, last);
}
#endif
iterator erase(iterator it)
{
if (it == vch.begin() + nReadPos)
{
// special case for erasing from the front
if (++nReadPos >= vch.size())
{
// whenever we reach the end, we take the opportunity to clear the buffer
nReadPos = 0;
return vch.erase(vch.begin(), vch.end());
}
return vch.begin() + nReadPos;
}
else
return vch.erase(it);
}
iterator erase(iterator first, iterator last)
{
if (first == vch.begin() + nReadPos)
{
// special case for erasing from the front
if (last == vch.end())
{
nReadPos = 0;
return vch.erase(vch.begin(), vch.end());
}
else
{
nReadPos = (last - vch.begin());
return last;
}
}
else
return vch.erase(first, last);
}
inline void Compact()
{
vch.erase(vch.begin(), vch.begin() + nReadPos);
nReadPos = 0;
}
bool Rewind(size_type n)
{
// Rewind by n characters if the buffer hasn't been compacted yet
if (n > nReadPos)
return false;
nReadPos -= n;
return true;
}
//
// Stream subset
//
void setstate(short bits, const char* psz)
{
state |= bits;
if (state & exceptmask)
throw std::ios_base::failure(psz);
}
bool eof() const { return size() == 0; }
bool fail() const { return state & (std::ios::badbit | std::ios::failbit); }
bool good() const { return !eof() && (state == 0); }
void clear(short n) { state = n; } // name conflict with vector clear()
short exceptions() { return exceptmask; }
short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; }
CDataStream* rdbuf() { return this; }
int in_avail() { return size(); }
void SetType(int n) { nType = n; }
int GetType() { return nType; }
void SetVersion(int n) { nVersion = n; }
int GetVersion() { return nVersion; }
void ReadVersion() { *this >> nVersion; }
void WriteVersion() { *this << nVersion; }
CDataStream& read(char* pch, int nSize)
{
// Read from the beginning of the buffer
assert(nSize >= 0);
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
{
if (nReadPosNext > vch.size())
{
setstate(std::ios::failbit, "CDataStream::read() : end of data");
memset(pch, 0, nSize);
nSize = vch.size() - nReadPos;
}
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = 0;
vch.clear();
return (*this);
}
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = nReadPosNext;
return (*this);
}
CDataStream& ignore(int nSize)
{
// Ignore from the beginning of the buffer
assert(nSize >= 0);
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
{
if (nReadPosNext > vch.size())
{
setstate(std::ios::failbit, "CDataStream::ignore() : end of data");
nSize = vch.size() - nReadPos;
}
nReadPos = 0;
vch.clear();
return (*this);
}
nReadPos = nReadPosNext;
return (*this);
}
CDataStream& write(const char* pch, int nSize)
{
// Write to the end of the buffer
assert(nSize >= 0);
vch.insert(vch.end(), pch, pch + nSize);
return (*this);
}
template<typename Stream>
void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
{
// Special case: stream << stream concatenates like stream += stream
if (!vch.empty())
s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
}
template<typename T>
unsigned int GetSerializeSize(const T& obj)
{
// Tells the size of the object if serialized to this stream
return ::GetSerializeSize(obj, nType, nVersion);
}
template<typename T>
CDataStream& operator<<(const T& obj)
{
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
template<typename T>
CDataStream& operator>>(T& obj)
{
// Unserialize from this stream
::Unserialize(*this, obj, nType, nVersion);
return (*this);
}
};
#ifdef TESTCDATASTREAM
// VC6sp6
// CDataStream:
// n=1000 0 seconds
// n=2000 0 seconds
// n=4000 0 seconds
// n=8000 0 seconds
// n=16000 0 seconds
// n=32000 0 seconds
// n=64000 1 seconds
// n=128000 1 seconds
// n=256000 2 seconds
// n=512000 4 seconds
// n=1024000 8 seconds
// n=2048000 16 seconds
// n=4096000 32 seconds
// stringstream:
// n=1000 1 seconds
// n=2000 1 seconds
// n=4000 13 seconds
// n=8000 87 seconds
// n=16000 400 seconds
// n=32000 1660 seconds
// n=64000 6749 seconds
// n=128000 27241 seconds
// n=256000 109804 seconds
#include <iostream>
int main(int argc, char *argv[])
{
vector<unsigned char> vch(0xcc, 250);
printf("CDataStream:\n");
for (int n = 1000; n <= 4500000; n *= 2)
{
CDataStream ss;
time_t nStart = time(NULL);
for (int i = 0; i < n; i++)
ss.write((char*)&vch[0], vch.size());
printf("n=%-10d %d seconds\n", n, time(NULL) - nStart);
}
printf("stringstream:\n");
for (int n = 1000; n <= 4500000; n *= 2)
{
stringstream ss;
time_t nStart = time(NULL);
for (int i = 0; i < n; i++)
ss.write((char*)&vch[0], vch.size());
printf("n=%-10d %d seconds\n", n, time(NULL) - nStart);
}
}
#endif
//
// Automatic closing wrapper for FILE*
// - Will automatically close the file when it goes out of scope if not null.
// - If you're returning the file pointer, return file.release().
// - If you need to close the file early, use file.fclose() instead of fclose(file).
//
class CAutoFile
{
protected:
FILE* file;
short state;
short exceptmask;
public:
int nType;
int nVersion;
typedef FILE element_type;
CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=PROTOCOL_VERSION)
{
file = filenew;
nType = nTypeIn;
nVersion = nVersionIn;
state = 0;
exceptmask = std::ios::badbit | std::ios::failbit;
}
~CAutoFile()
{
fclose();
}
void fclose()
{
if (file != NULL && file != stdin && file != stdout && file != stderr)
::fclose(file);
file = NULL;
}
FILE* release() { FILE* ret = file; file = NULL; return ret; }
operator FILE*() { return file; }
FILE* operator->() { return file; }
FILE& operator*() { return *file; }
FILE** operator&() { return &file; }
FILE* operator=(FILE* pnew) { return file = pnew; }
bool operator!() { return (file == NULL); }
//
// Stream subset
//
void setstate(short bits, const char* psz)
{
state |= bits;
if (state & exceptmask)
throw std::ios_base::failure(psz);
}
bool fail() const { return state & (std::ios::badbit | std::ios::failbit); }
bool good() const { return state == 0; }
void clear(short n = 0) { state = n; }
short exceptions() { return exceptmask; }
short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; }
void SetType(int n) { nType = n; }
int GetType() { return nType; }
void SetVersion(int n) { nVersion = n; }
int GetVersion() { return nVersion; }
void ReadVersion() { *this >> nVersion; }
void WriteVersion() { *this << nVersion; }
CAutoFile& read(char* pch, int nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
if (fread(pch, 1, nSize, file) != nSize)
setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
return (*this);
}
CAutoFile& write(const char* pch, int nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
if (fwrite(pch, 1, nSize, file) != nSize)
setstate(std::ios::failbit, "CAutoFile::write : write failed");
return (*this);
}
template<typename T>
unsigned int GetSerializeSize(const T& obj)
{
// Tells the size of the object if serialized to this stream
return ::GetSerializeSize(obj, nType, nVersion);
}
template<typename T>
CAutoFile& operator<<(const T& obj)
{
// Serialize to this stream
if (!file)
throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL");
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
template<typename T>
CAutoFile& operator>>(T& obj)
{
// Unserialize from this stream
if (!file)
throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL");
::Unserialize(*this, obj, nType, nVersion);
return (*this);
}
};
#endif
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index e9b7b4517a..bea671c311 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -1,119 +1,121 @@
//
// Unit tests for denial-of-service detection/prevention code
//
+#include <stdint.h>
+
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include "main.h"
#include "wallet.h"
#include "net.h"
#include "util.h"
using namespace std;
BOOST_AUTO_TEST_SUITE(DoS_tests)
BOOST_AUTO_TEST_CASE(DoS_banning)
{
CNode::ClearBanned();
CAddress addr1(0xa0b0c001);
CNode dummyNode1(INVALID_SOCKET, addr1, true);
dummyNode1.Misbehaving(100); // Should get banned
BOOST_CHECK(CNode::IsBanned(addr1.ip));
BOOST_CHECK(!CNode::IsBanned(addr1.ip|0x0000ff00)); // Different ip, not banned
CAddress addr2(0xa0b0c002);
CNode dummyNode2(INVALID_SOCKET, addr2, true);
dummyNode2.Misbehaving(50);
BOOST_CHECK(!CNode::IsBanned(addr2.ip)); // 2 not banned yet...
BOOST_CHECK(CNode::IsBanned(addr1.ip)); // ... but 1 still should be
dummyNode2.Misbehaving(50);
BOOST_CHECK(CNode::IsBanned(addr2.ip));
}
BOOST_AUTO_TEST_CASE(DoS_banscore)
{
CNode::ClearBanned();
mapArgs["-banscore"] = "111"; // because 11 is my favorite number
CAddress addr1(0xa0b0c001);
CNode dummyNode1(INVALID_SOCKET, addr1, true);
dummyNode1.Misbehaving(100);
BOOST_CHECK(!CNode::IsBanned(addr1.ip));
dummyNode1.Misbehaving(10);
BOOST_CHECK(!CNode::IsBanned(addr1.ip));
dummyNode1.Misbehaving(1);
BOOST_CHECK(CNode::IsBanned(addr1.ip));
mapArgs["-banscore"] = "100";
}
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
CNode::ClearBanned();
- int64 nStartTime = GetTime();
+ int64_t nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(0xa0b0c001);
CNode dummyNode(INVALID_SOCKET, addr, true);
dummyNode.Misbehaving(100);
BOOST_CHECK(CNode::IsBanned(addr.ip));
SetMockTime(nStartTime+60*60);
BOOST_CHECK(CNode::IsBanned(addr.ip));
SetMockTime(nStartTime+60*60*24+1);
BOOST_CHECK(!CNode::IsBanned(addr.ip));
}
-static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, int64 time2)
+static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, int64_t time2)
{
if (time1 > time2)
return CheckNBits(nbits2, time2, nbits1, time1);
- int64 deltaTime = time2-time1;
+ int64_t deltaTime = time2-time1;
CBigNum required;
required.SetCompact(ComputeMinWork(nbits1, deltaTime));
CBigNum have;
have.SetCompact(nbits2);
return (have <= required);
}
BOOST_AUTO_TEST_CASE(DoS_checknbits)
{
using namespace boost::assign; // for 'map_list_of()'
// Timestamps,nBits from the bitcoin blockchain.
// These are the block-chain checkpoint blocks
- typedef std::map<int64, unsigned int> BlockData;
+ typedef std::map<int64_t, unsigned int> BlockData;
BlockData chainData =
map_list_of(1239852051,486604799)(1262749024,486594666)
(1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
(1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
(1313172719,436789733);
// Make sure CheckNBits considers every combination of block-chain-lock-in-points
// "sane":
BOOST_FOREACH(const BlockData::value_type& i, chainData)
{
BOOST_FOREACH(const BlockData::value_type& j, chainData)
{
BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
}
}
// Test a couple of insane combinations:
BlockData::value_type firstcheck = *(chainData.begin());
BlockData::value_type lastcheck = *(chainData.rbegin());
// First checkpoint difficulty at or a while after the last checkpoint time should fail when
// compared to last checkpoint
BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first));
BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first));
// ... but OK if enough time passed for difficulty to adjust downward:
BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index d52ac74982..0ceff9f28f 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -1,89 +1,91 @@
+#include <stdint.h>
+
#include <boost/test/unit_test.hpp>
#include "main.h"
#include "wallet.h"
#include "util.h"
BOOST_AUTO_TEST_SUITE(base58_tests)
// TODO:
// EncodeBase58Check
// DecodeBase58Check
// CBase58Data
// bool SetString(const char* psz)
// bool SetString(const std::string& str)
// std::string ToString() const
// int CompareTo(const CBase58Data& b58) const
// bool operator==(const CBase58Data& b58) const
// bool operator<=(const CBase58Data& b58) const
// bool operator>=(const CBase58Data& b58) const
// bool operator< (const CBase58Data& b58) const
// bool operator> (const CBase58Data& b58) const
// CBitcoinAddress
// bool SetHash160(const uint160& hash160)
// bool SetPubKey(const std::vector<unsigned char>& vchPubKey)
// bool IsValid() const
// CBitcoinAddress()
// CBitcoinAddress(uint160 hash160In)
// CBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
// CBitcoinAddress(const std::string& strAddress)
// CBitcoinAddress(const char* pszAddress)
// uint160 GetHash160() const
#define U(x) (reinterpret_cast<const unsigned char*>(x))
static struct {
const unsigned char *data;
int size;
} vstrIn[] = {
{U(""), 0},
{U("\x61"), 1},
{U("\x62\x62\x62"), 3},
{U("\x63\x63\x63"), 3},
{U("\x73\x69\x6d\x70\x6c\x79\x20\x61\x20\x6c\x6f\x6e\x67\x20\x73\x74\x72\x69\x6e\x67"), 20},
{U("\x00\xeb\x15\x23\x1d\xfc\xeb\x60\x92\x58\x86\xb6\x7d\x06\x52\x99\x92\x59\x15\xae\xb1\x72\xc0\x66\x47"), 25},
{U("\x51\x6b\x6f\xcd\x0f"), 5},
{U("\xbf\x4f\x89\x00\x1e\x67\x02\x74\xdd"), 9},
{U("\x57\x2e\x47\x94"), 4},
{U("\xec\xac\x89\xca\xd9\x39\x23\xc0\x23\x21"), 10},
{U("\x10\xc8\x51\x1e"), 4},
{U("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), 10},
};
const char *vstrOut[] = {
"",
"2g",
"a3gV",
"aPEr",
"2cFupjhnEsSn59qHXstmK2ffpLv2",
"1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L",
"ABnLTmg",
"3SEo3LWLoPntC",
"3EFU7m",
"EJDM8drfXA6uyA",
"Rt5zm",
"1111111111"
};
BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
{
for (int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
{
BOOST_CHECK_EQUAL(EncodeBase58(vstrIn[i].data, vstrIn[i].data + vstrIn[i].size), vstrOut[i]);
}
}
BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
{
std::vector<unsigned char> result;
for (int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
{
std::vector<unsigned char> expected(vstrIn[i].data, vstrIn[i].data + vstrIn[i].size);
BOOST_CHECK(DecodeBase58(vstrOut[i], result));
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
}
BOOST_CHECK(!DecodeBase58("invalid", result));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_op_eval_tests.cpp b/src/test/script_op_eval_tests.cpp
index c44642c6e9..14c025b425 100644
--- a/src/test/script_op_eval_tests.cpp
+++ b/src/test/script_op_eval_tests.cpp
@@ -1,234 +1,236 @@
+#include <stdint.h>
+
#include <boost/assert.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/assign/list_inserter.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include "../main.h"
#include "../script.h"
#include "../wallet.h"
using namespace std;
// Test routines internal to script.cpp:
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int& nSigOps,
int nHashType, bool fStrictOpEval);
BOOST_AUTO_TEST_SUITE(script_op_eval_tests)
BOOST_AUTO_TEST_CASE(script_op_eval1)
{
// OP_EVAL looks like this:
// scriptSig: <sig> <sig...> <serialized_script>
// scriptPubKey: DUP HASH160 <hash> EQUALVERIFY EVAL
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
CBasicKeyStore keystore;
CKey key[4];
for (int i = 0; i < 4; i++)
{
key[i].MakeNewKey();
keystore.AddKey(key[i]);
}
// 8 Scripts: checking all combinations of
// different keys, straight/EVAL, pubkey/pubkeyhash
CScript standardScripts[4];
standardScripts[0] << key[0].GetPubKey() << OP_CHECKSIG;
standardScripts[1].SetBitcoinAddress(key[1].GetPubKey());
standardScripts[2] << key[1].GetPubKey() << OP_CHECKSIG;
standardScripts[3].SetBitcoinAddress(key[2].GetPubKey());
CScript evalScripts[4];
uint160 sigScriptHashes[4];
for (int i = 0; i < 4; i++)
{
sigScriptHashes[i] = Hash160(standardScripts[i]);
keystore.AddCScript(sigScriptHashes[i], standardScripts[i]);
evalScripts[i] << OP_DUP << OP_HASH160 << sigScriptHashes[i] << OP_EQUALVERIFY << OP_EVAL;
}
CTransaction txFrom; // Funding transaction:
txFrom.vout.resize(8);
for (int i = 0; i < 4; i++)
{
txFrom.vout[i].scriptPubKey = evalScripts[i];
txFrom.vout[i+4].scriptPubKey = standardScripts[i];
}
BOOST_CHECK(txFrom.IsStandard());
CTransaction txTo[8]; // Spending transactions
for (int i = 0; i < 8; i++)
{
txTo[i].vin.resize(1);
txTo[i].vout.resize(1);
txTo[i].vin[0].prevout.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1;
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
}
for (int i = 0; i < 8; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
int nUnused = 0;
bool sigOK = VerifySignature(txFrom, txTo[i], 0, nUnused);
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
txTo[i].vin[0].scriptSig = sigSave;
}
}
BOOST_AUTO_TEST_CASE(script_op_eval2)
{
// Test OP_EVAL edge cases
CScript recurse;
recurse << OP_DUP << OP_EVAL;
uint160 recurseHash = Hash160(recurse);
CScript fund;
fund << OP_DUP << OP_HASH160 << recurseHash << OP_EQUALVERIFY << OP_EVAL;
CTransaction txFrom; // Funding transaction:
txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey = fund;
BOOST_CHECK(txFrom.IsStandard()); // Looks like a standard transaction until you try to spend it
CTransaction txTo;
txTo.vin.resize(1);
txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0;
txTo.vin[0].prevout.hash = txFrom.GetHash();
txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(recurse);
txTo.vout[0].nValue = 1;
int nUnused = 0;
BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, true));
BOOST_CHECK(!VerifySignature(txFrom, txTo, 0, nUnused, true));
}
BOOST_AUTO_TEST_CASE(script_op_eval3)
{
// Test the CScript::Set* methods
CBasicKeyStore keystore;
CKey key[4];
std::vector<CKey> keys;
for (int i = 0; i < 4; i++)
{
key[i].MakeNewKey();
keystore.AddKey(key[i]);
keys.push_back(key[i]);
}
CScript inner[4];
inner[0].SetBitcoinAddress(key[0].GetPubKey());
inner[1].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+2));
inner[2].SetMultisig(1, std::vector<CKey>(keys.begin(), keys.begin()+2));
inner[3].SetMultisig(2, std::vector<CKey>(keys.begin(), keys.begin()+3));
CScript outer[4];
for (int i = 0; i < 4; i++)
{
outer[i].SetEval(inner[i]);
keystore.AddCScript(Hash160(inner[i]), inner[i]);
}
CTransaction txFrom; // Funding transaction:
txFrom.vout.resize(4);
for (int i = 0; i < 4; i++)
{
txFrom.vout[i].scriptPubKey = outer[i];
}
BOOST_CHECK(txFrom.IsStandard());
CTransaction txTo[4]; // Spending transactions
for (int i = 0; i < 4; i++)
{
txTo[i].vin.resize(1);
txTo[i].vout.resize(1);
txTo[i].vin[0].prevout.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1;
txTo[i].vout[0].scriptPubKey = inner[i];
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
}
for (int i = 0; i < 4; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(txTo[i].IsStandard(), strprintf("txTo[%d].IsStandard", i));
}
}
BOOST_AUTO_TEST_CASE(script_op_eval_backcompat1)
{
// Check backwards-incompatibility-testing code
CScript returnsEleven;
returnsEleven << OP_11;
// This should validate on new clients, but will
// be invalid on old clients (that interpret OP_EVAL as a no-op)
// ... except there's a special rule that makes new clients reject
// it.
CScript fund;
fund << OP_EVAL << OP_11 << OP_EQUAL;
CTransaction txFrom; // Funding transaction:
txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey = fund;
CTransaction txTo;
txTo.vin.resize(1);
txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0;
txTo.vin[0].prevout.hash = txFrom.GetHash();
txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(returnsEleven);
txTo.vout[0].nValue = 1;
int nUnused = 0;
BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, true));
BOOST_CHECK(!VerifySignature(txFrom, txTo, 0, nUnused, true));
}
BOOST_AUTO_TEST_CASE(script_op_eval_switchover)
{
// Test OP_EVAL switchover code
CScript notValid;
notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
// This will be valid under old rules, invalid under new:
CScript fund;
fund << OP_EVAL;
CTransaction txFrom; // Funding transaction:
txFrom.vout.resize(1);
txFrom.vout[0].scriptPubKey = fund;
CTransaction txTo;
txTo.vin.resize(1);
txTo.vout.resize(1);
txTo.vin[0].prevout.n = 0;
txTo.vin[0].prevout.hash = txFrom.GetHash();
txTo.vin[0].scriptSig = CScript() << static_cast<std::vector<unsigned char> >(notValid);
txTo.vout[0].nValue = 1;
int nUnused = 0;
BOOST_CHECK(VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, false));
// Under strict op_eval switchover, it should be considered invalid:
BOOST_CHECK(!VerifyScript(txTo.vin[0].scriptSig, txFrom.vout[0].scriptPubKey, txTo, 0, nUnused, 0, true));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/uint160_tests.cpp b/src/test/uint160_tests.cpp
index 35cb35b25a..d986c30870 100644
--- a/src/test/uint160_tests.cpp
+++ b/src/test/uint160_tests.cpp
@@ -1,18 +1,20 @@
+#include <stdint.h>
+
#include <boost/test/unit_test.hpp>
#include "uint256.h"
BOOST_AUTO_TEST_SUITE(uint160_tests)
BOOST_AUTO_TEST_CASE(uint160_equality)
{
uint160 num1 = 10;
uint160 num2 = 11;
BOOST_CHECK(num1+1 == num2);
- uint64 num3 = 10;
+ uint64_t num3 = 10;
BOOST_CHECK(num1 == num3);
BOOST_CHECK(num1+num2 == num3+num2);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp
index efdc8a6aeb..d7e1e51379 100644
--- a/src/test/uint256_tests.cpp
+++ b/src/test/uint256_tests.cpp
@@ -1,18 +1,20 @@
+#include <stdint.h>
+
#include <boost/test/unit_test.hpp>
#include "uint256.h"
BOOST_AUTO_TEST_SUITE(uint256_tests)
BOOST_AUTO_TEST_CASE(uint256_equality)
{
uint256 num1 = 10;
uint256 num2 = 11;
BOOST_CHECK(num1+1 == num2);
- uint64 num3 = 10;
+ uint64_t num3 = 10;
BOOST_CHECK(num1 == num3);
BOOST_CHECK(num1+num2 == num3+num2);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 9571c47382..08d243751e 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1,235 +1,237 @@
+#include <stdint.h>
+
#include <vector>
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include "main.h"
#include "wallet.h"
#include "util.h"
using namespace std;
BOOST_AUTO_TEST_SUITE(util_tests)
BOOST_AUTO_TEST_CASE(util_criticalsection)
{
CCriticalSection cs;
do {
CRITICAL_BLOCK(cs)
break;
BOOST_ERROR("break was swallowed!");
} while(0);
do {
TRY_CRITICAL_BLOCK(cs)
break;
BOOST_ERROR("break was swallowed!");
} while(0);
}
BOOST_AUTO_TEST_CASE(util_MedianFilter)
{
CMedianFilter<int> filter(5, 15);
BOOST_CHECK_EQUAL(filter.median(), 15);
filter.input(20); // [15 20]
BOOST_CHECK_EQUAL(filter.median(), 17);
filter.input(30); // [15 20 30]
BOOST_CHECK_EQUAL(filter.median(), 20);
filter.input(3); // [3 15 20 30]
BOOST_CHECK_EQUAL(filter.median(), 17);
filter.input(7); // [3 7 15 20 30]
BOOST_CHECK_EQUAL(filter.median(), 15);
filter.input(18); // [3 7 18 20 30]
BOOST_CHECK_EQUAL(filter.median(), 18);
filter.input(0); // [0 3 7 18 30]
BOOST_CHECK_EQUAL(filter.median(), 7);
}
static const unsigned char ParseHex_expected[65] = {
0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7,
0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde,
0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12,
0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
0x5f
};
BOOST_AUTO_TEST_CASE(util_ParseHex)
{
std::vector<unsigned char> result;
std::vector<unsigned char> expected(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected));
// Basic test vector
result = ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
// Spaces between bytes must be supported
result = ParseHex("12 34 56 78");
BOOST_CHECK(result.size() == 4 && result[0] == 0x12 && result[1] == 0x34 && result[2] == 0x56 && result[3] == 0x78);
// Stop parsing at invalid value
result = ParseHex("1234 invalid 1234");
BOOST_CHECK(result.size() == 2 && result[0] == 0x12 && result[1] == 0x34);
}
BOOST_AUTO_TEST_CASE(util_HexStr)
{
BOOST_CHECK_EQUAL(
HexStr(ParseHex_expected, ParseHex_expected + sizeof(ParseHex_expected)),
"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
BOOST_CHECK_EQUAL(
HexStr(ParseHex_expected, ParseHex_expected + 5, true),
"04 67 8a fd b0");
}
BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat)
{
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0), "01/01/70 00:00:00");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0x7FFFFFFF), "01/19/38 03:14:07");
// Formats used within bitcoin
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 1317425777), "09/30/11 23:36:17");
BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M", 1317425777), "09/30/11 23:36");
}
BOOST_AUTO_TEST_CASE(util_ParseParameters)
{
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
ParseParameters(0, (char**)argv_test);
BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty());
ParseParameters(1, (char**)argv_test);
BOOST_CHECK(mapArgs.empty() && mapMultiArgs.empty());
ParseParameters(5, (char**)argv_test);
// expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
BOOST_CHECK(mapArgs.size() == 3 && mapMultiArgs.size() == 3);
BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc")
&& !mapArgs.count("f") && !mapArgs.count("-d"));
BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc")
&& !mapMultiArgs.count("f") && !mapMultiArgs.count("-d"));
BOOST_CHECK(mapArgs["-a"] == "" && mapArgs["-ccc"] == "multiple");
BOOST_CHECK(mapMultiArgs["-ccc"].size() == 2);
}
BOOST_AUTO_TEST_CASE(util_GetArg)
{
mapArgs.clear();
mapArgs["strtest1"] = "string...";
// strtest2 undefined on purpose
mapArgs["inttest1"] = "12345";
mapArgs["inttest2"] = "81985529216486895";
// inttest3 undefined on purpose
mapArgs["booltest1"] = "";
// booltest2 undefined on purpose
mapArgs["booltest3"] = "0";
mapArgs["booltest4"] = "1";
BOOST_CHECK_EQUAL(GetArg("strtest1", "default"), "string...");
BOOST_CHECK_EQUAL(GetArg("strtest2", "default"), "default");
BOOST_CHECK_EQUAL(GetArg("inttest1", -1), 12345);
BOOST_CHECK_EQUAL(GetArg("inttest2", -1), 81985529216486895LL);
BOOST_CHECK_EQUAL(GetArg("inttest3", -1), -1);
BOOST_CHECK_EQUAL(GetBoolArg("booltest1"), true);
BOOST_CHECK_EQUAL(GetBoolArg("booltest2"), false);
BOOST_CHECK_EQUAL(GetBoolArg("booltest3"), false);
BOOST_CHECK_EQUAL(GetBoolArg("booltest4"), true);
}
BOOST_AUTO_TEST_CASE(util_WildcardMatch)
{
BOOST_CHECK(WildcardMatch("127.0.0.1", "*"));
BOOST_CHECK(WildcardMatch("127.0.0.1", "127.*"));
BOOST_CHECK(WildcardMatch("abcdef", "a?cde?"));
BOOST_CHECK(!WildcardMatch("abcdef", "a?cde??"));
BOOST_CHECK(WildcardMatch("abcdef", "a*f"));
BOOST_CHECK(!WildcardMatch("abcdef", "a*x"));
BOOST_CHECK(WildcardMatch("", "*"));
}
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00");
BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789");
BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00");
BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00");
BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01");
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
}
BOOST_AUTO_TEST_CASE(util_ParseMoney)
{
- int64 ret = 0;
+ int64_t ret = 0;
BOOST_CHECK(ParseMoney("0.0", ret));
BOOST_CHECK_EQUAL(ret, 0);
BOOST_CHECK(ParseMoney("12345.6789", ret));
BOOST_CHECK_EQUAL(ret, (COIN/10000)*123456789);
BOOST_CHECK(ParseMoney("100000000.00", ret));
BOOST_CHECK_EQUAL(ret, COIN*100000000);
BOOST_CHECK(ParseMoney("10000000.00", ret));
BOOST_CHECK_EQUAL(ret, COIN*10000000);
BOOST_CHECK(ParseMoney("1000000.00", ret));
BOOST_CHECK_EQUAL(ret, COIN*1000000);
BOOST_CHECK(ParseMoney("100000.00", ret));
BOOST_CHECK_EQUAL(ret, COIN*100000);
BOOST_CHECK(ParseMoney("10000.00", ret));
BOOST_CHECK_EQUAL(ret, COIN*10000);
BOOST_CHECK(ParseMoney("1000.00", ret));
BOOST_CHECK_EQUAL(ret, COIN*1000);
BOOST_CHECK(ParseMoney("100.00", ret));
BOOST_CHECK_EQUAL(ret, COIN*100);
BOOST_CHECK(ParseMoney("10.00", ret));
BOOST_CHECK_EQUAL(ret, COIN*10);
BOOST_CHECK(ParseMoney("1.00", ret));
BOOST_CHECK_EQUAL(ret, COIN);
BOOST_CHECK(ParseMoney("0.1", ret));
BOOST_CHECK_EQUAL(ret, COIN/10);
BOOST_CHECK(ParseMoney("0.01", ret));
BOOST_CHECK_EQUAL(ret, COIN/100);
BOOST_CHECK(ParseMoney("0.001", ret));
BOOST_CHECK_EQUAL(ret, COIN/1000);
BOOST_CHECK(ParseMoney("0.0001", ret));
BOOST_CHECK_EQUAL(ret, COIN/10000);
BOOST_CHECK(ParseMoney("0.00001", ret));
BOOST_CHECK_EQUAL(ret, COIN/100000);
BOOST_CHECK(ParseMoney("0.000001", ret));
BOOST_CHECK_EQUAL(ret, COIN/1000000);
BOOST_CHECK(ParseMoney("0.0000001", ret));
BOOST_CHECK_EQUAL(ret, COIN/10000000);
BOOST_CHECK(ParseMoney("0.00000001", ret));
BOOST_CHECK_EQUAL(ret, COIN/100000000);
// Attempted 63 bit overflow should fail
BOOST_CHECK(!ParseMoney("92233720368.54775808", ret));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/uint256.h b/src/uint256.h
index d3da1f26d2..20438993cd 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -1,758 +1,757 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_UINT256_H
#define BITCOIN_UINT256_H
+#include <stdint.h>
+
#include "serialize.h"
#include <limits.h>
#include <string>
#include <vector>
-typedef long long int64;
-typedef unsigned long long uint64;
-
inline int Testuint256AdHoc(std::vector<std::string> vArg);
// We have to keep a separate base class without constructors
// so the compiler will let us use it in a union
template<unsigned int BITS>
class base_uint
{
protected:
enum { WIDTH=BITS/32 };
unsigned int pn[WIDTH];
public:
bool operator!() const
{
for (int i = 0; i < WIDTH; i++)
if (pn[i] != 0)
return false;
return true;
}
const base_uint operator~() const
{
base_uint ret;
for (int i = 0; i < WIDTH; i++)
ret.pn[i] = ~pn[i];
return ret;
}
const base_uint operator-() const
{
base_uint ret;
for (int i = 0; i < WIDTH; i++)
ret.pn[i] = ~pn[i];
ret++;
return ret;
}
- base_uint& operator=(uint64 b)
+ base_uint& operator=(uint64_t b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
return *this;
}
base_uint& operator^=(const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] ^= b.pn[i];
return *this;
}
base_uint& operator&=(const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] &= b.pn[i];
return *this;
}
base_uint& operator|=(const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] |= b.pn[i];
return *this;
}
- base_uint& operator^=(uint64 b)
+ base_uint& operator^=(uint64_t b)
{
pn[0] ^= (unsigned int)b;
pn[1] ^= (unsigned int)(b >> 32);
return *this;
}
- base_uint& operator&=(uint64 b)
+ base_uint& operator&=(uint64_t b)
{
pn[0] &= (unsigned int)b;
pn[1] &= (unsigned int)(b >> 32);
return *this;
}
- base_uint& operator|=(uint64 b)
+ base_uint& operator|=(uint64_t b)
{
pn[0] |= (unsigned int)b;
pn[1] |= (unsigned int)(b >> 32);
return *this;
}
base_uint& operator<<=(unsigned int shift)
{
base_uint a(*this);
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
int k = shift / 32;
shift = shift % 32;
for (int i = 0; i < WIDTH; i++)
{
if (i+k+1 < WIDTH && shift != 0)
pn[i+k+1] |= (a.pn[i] >> (32-shift));
if (i+k < WIDTH)
pn[i+k] |= (a.pn[i] << shift);
}
return *this;
}
base_uint& operator>>=(unsigned int shift)
{
base_uint a(*this);
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
int k = shift / 32;
shift = shift % 32;
for (int i = 0; i < WIDTH; i++)
{
if (i-k-1 >= 0 && shift != 0)
pn[i-k-1] |= (a.pn[i] << (32-shift));
if (i-k >= 0)
pn[i-k] |= (a.pn[i] >> shift);
}
return *this;
}
base_uint& operator+=(const base_uint& b)
{
- uint64 carry = 0;
+ uint64_t carry = 0;
for (int i = 0; i < WIDTH; i++)
{
- uint64 n = carry + pn[i] + b.pn[i];
+ uint64_t n = carry + pn[i] + b.pn[i];
pn[i] = n & 0xffffffff;
carry = n >> 32;
}
return *this;
}
base_uint& operator-=(const base_uint& b)
{
*this += -b;
return *this;
}
- base_uint& operator+=(uint64 b64)
+ base_uint& operator+=(uint64_t b64)
{
base_uint b;
b = b64;
*this += b;
return *this;
}
- base_uint& operator-=(uint64 b64)
+ base_uint& operator-=(uint64_t b64)
{
base_uint b;
b = b64;
*this += -b;
return *this;
}
base_uint& operator++()
{
// prefix operator
int i = 0;
while (++pn[i] == 0 && i < WIDTH-1)
i++;
return *this;
}
const base_uint operator++(int)
{
// postfix operator
const base_uint ret = *this;
++(*this);
return ret;
}
base_uint& operator--()
{
// prefix operator
int i = 0;
while (--pn[i] == -1 && i < WIDTH-1)
i++;
return *this;
}
const base_uint operator--(int)
{
// postfix operator
const base_uint ret = *this;
--(*this);
return ret;
}
friend inline bool operator<(const base_uint& a, const base_uint& b)
{
for (int i = base_uint::WIDTH-1; i >= 0; i--)
{
if (a.pn[i] < b.pn[i])
return true;
else if (a.pn[i] > b.pn[i])
return false;
}
return false;
}
friend inline bool operator<=(const base_uint& a, const base_uint& b)
{
for (int i = base_uint::WIDTH-1; i >= 0; i--)
{
if (a.pn[i] < b.pn[i])
return true;
else if (a.pn[i] > b.pn[i])
return false;
}
return true;
}
friend inline bool operator>(const base_uint& a, const base_uint& b)
{
for (int i = base_uint::WIDTH-1; i >= 0; i--)
{
if (a.pn[i] > b.pn[i])
return true;
else if (a.pn[i] < b.pn[i])
return false;
}
return false;
}
friend inline bool operator>=(const base_uint& a, const base_uint& b)
{
for (int i = base_uint::WIDTH-1; i >= 0; i--)
{
if (a.pn[i] > b.pn[i])
return true;
else if (a.pn[i] < b.pn[i])
return false;
}
return true;
}
friend inline bool operator==(const base_uint& a, const base_uint& b)
{
for (int i = 0; i < base_uint::WIDTH; i++)
if (a.pn[i] != b.pn[i])
return false;
return true;
}
- friend inline bool operator==(const base_uint& a, uint64 b)
+ friend inline bool operator==(const base_uint& a, uint64_t b)
{
if (a.pn[0] != (unsigned int)b)
return false;
if (a.pn[1] != (unsigned int)(b >> 32))
return false;
for (int i = 2; i < base_uint::WIDTH; i++)
if (a.pn[i] != 0)
return false;
return true;
}
friend inline bool operator!=(const base_uint& a, const base_uint& b)
{
return (!(a == b));
}
- friend inline bool operator!=(const base_uint& a, uint64 b)
+ friend inline bool operator!=(const base_uint& a, uint64_t b)
{
return (!(a == b));
}
std::string GetHex() const
{
char psz[sizeof(pn)*2 + 1];
for (int i = 0; i < sizeof(pn); i++)
sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]);
return std::string(psz, psz + sizeof(pn)*2);
}
void SetHex(const char* psz)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
// skip leading spaces
while (isspace(*psz))
psz++;
// skip 0x
if (psz[0] == '0' && tolower(psz[1]) == 'x')
psz += 2;
// hex string to uint
static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
const char* pbegin = psz;
while (phexdigit[*psz] || *psz == '0')
psz++;
psz--;
unsigned char* p1 = (unsigned char*)pn;
unsigned char* pend = p1 + WIDTH * 4;
while (psz >= pbegin && p1 < pend)
{
*p1 = phexdigit[(unsigned char)*psz--];
if (psz >= pbegin)
{
*p1 |= (phexdigit[(unsigned char)*psz--] << 4);
p1++;
}
}
}
void SetHex(const std::string& str)
{
SetHex(str.c_str());
}
std::string ToString() const
{
return (GetHex());
}
unsigned char* begin()
{
return (unsigned char*)&pn[0];
}
unsigned char* end()
{
return (unsigned char*)&pn[WIDTH];
}
unsigned int size()
{
return sizeof(pn);
}
unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
{
return sizeof(pn);
}
template<typename Stream>
void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
{
s.write((char*)pn, sizeof(pn));
}
template<typename Stream>
void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
{
s.read((char*)pn, sizeof(pn));
}
friend class uint160;
friend class uint256;
friend inline int Testuint256AdHoc(std::vector<std::string> vArg);
};
typedef base_uint<160> base_uint160;
typedef base_uint<256> base_uint256;
//
// uint160 and uint256 could be implemented as templates, but to keep
// compile errors and debugging cleaner, they're copy and pasted.
//
//////////////////////////////////////////////////////////////////////////////
//
// uint160
//
class uint160 : public base_uint160
{
public:
typedef base_uint160 basetype;
uint160()
{
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
}
uint160(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
uint160& operator=(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
return *this;
}
- uint160(uint64 b)
+ uint160(uint64_t b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
}
- uint160& operator=(uint64 b)
+ uint160& operator=(uint64_t b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
return *this;
}
explicit uint160(const std::string& str)
{
SetHex(str);
}
explicit uint160(const std::vector<unsigned char>& vch)
{
if (vch.size() == sizeof(pn))
memcpy(pn, &vch[0], sizeof(pn));
else
*this = 0;
}
};
-inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; }
-inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; }
+inline bool operator==(const uint160& a, uint64_t b) { return (base_uint160)a == b; }
+inline bool operator!=(const uint160& a, uint64_t b) { return (base_uint160)a != b; }
inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; }
inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; }
inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; }
inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; }
inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; }
inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; }
inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; }
inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; }
inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; }
inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; }
inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; }
inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; }
inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; }
inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; }
inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; }
inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; }
inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; }
inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; }
inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; }
inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; }
inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; }
inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; }
inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; }
inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; }
inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; }
inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; }
inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; }
//////////////////////////////////////////////////////////////////////////////
//
// uint256
//
class uint256 : public base_uint256
{
public:
typedef base_uint256 basetype;
uint256()
{
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
}
uint256(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
uint256& operator=(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
return *this;
}
- uint256(uint64 b)
+ uint256(uint64_t b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
}
- uint256& operator=(uint64 b)
+ uint256& operator=(uint64_t b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
return *this;
}
explicit uint256(const std::string& str)
{
SetHex(str);
}
explicit uint256(const std::vector<unsigned char>& vch)
{
if (vch.size() == sizeof(pn))
memcpy(pn, &vch[0], sizeof(pn));
else
*this = 0;
}
};
-inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; }
-inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; }
+inline bool operator==(const uint256& a, uint64_t b) { return (base_uint256)a == b; }
+inline bool operator!=(const uint256& a, uint64_t b) { return (base_uint256)a != b; }
inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; }
inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; }
inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; }
inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; }
inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; }
inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; }
inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; }
inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; }
inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; }
inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; }
inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; }
inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; }
inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; }
inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; }
inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; }
inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; }
inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; }
inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; }
inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; }
inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; }
inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; }
inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; }
inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; }
inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; }
inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; }
inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; }
inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; }
inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; }
inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; }
inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; }
inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; }
inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; }
inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; }
inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; }
inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; }
inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; }
inline bool operator!=(const uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; }
inline const uint256 operator^(const uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; }
inline const uint256 operator&(const uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; }
inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; }
inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; }
inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; }
inline int Testuint256AdHoc(std::vector<std::string> vArg)
{
uint256 g(0);
printf("%s\n", g.ToString().c_str());
g--; printf("g--\n");
printf("%s\n", g.ToString().c_str());
g--; printf("g--\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
uint256 a(7);
printf("a=7\n");
printf("%s\n", a.ToString().c_str());
uint256 b;
printf("b undefined\n");
printf("%s\n", b.ToString().c_str());
int c = 3;
a = c;
a.pn[3] = 15;
printf("%s\n", a.ToString().c_str());
uint256 k(c);
a = 5;
a.pn[3] = 15;
printf("%s\n", a.ToString().c_str());
b = 1;
b <<= 52;
a |= b;
a ^= 0x500;
printf("a %s\n", a.ToString().c_str());
a = a | b | (uint256)0x1000;
printf("a %s\n", a.ToString().c_str());
printf("b %s\n", b.ToString().c_str());
a = 0xfffffffe;
a.pn[4] = 9;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
uint256 d = a--;
printf("%s\n", d.ToString().c_str());
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
d = a;
printf("%s\n", d.ToString().c_str());
for (int i = uint256::WIDTH-1; i >= 0; i--) printf("%08x", d.pn[i]); printf("\n");
uint256 neg = d;
neg = ~neg;
printf("%s\n", neg.ToString().c_str());
uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111");
printf("\n");
printf("%s\n", e.ToString().c_str());
printf("\n");
uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111");
uint256 x2;
printf("%s\n", x1.ToString().c_str());
for (int i = 0; i < 270; i += 4)
{
x2 = x1 << i;
printf("%s\n", x2.ToString().c_str());
}
printf("\n");
printf("%s\n", x1.ToString().c_str());
for (int i = 0; i < 270; i += 4)
{
x2 = x1;
x2 >>= i;
printf("%s\n", x2.ToString().c_str());
}
for (int i = 0; i < 100; i++)
{
uint256 k = (~uint256(0) >> i);
printf("%s\n", k.ToString().c_str());
}
for (int i = 0; i < 100; i++)
{
uint256 k = (~uint256(0) << i);
printf("%s\n", k.ToString().c_str());
}
return (0);
}
#endif
diff --git a/src/util.cpp b/src/util.cpp
index a45ce33a1c..d4d4520b66 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,1163 +1,1166 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "strlcpy.h"
#include <boost/algorithm/string/join.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/foreach.hpp>
using namespace std;
using namespace boost;
map<string, string> mapArgs;
map<string, vector<string> > mapMultiArgs;
bool fDebug = false;
bool fPrintToConsole = false;
bool fPrintToDebugger = false;
char pszSetDataDir[MAX_PATH] = "";
bool fRequestShutdown = false;
bool fShutdown = false;
bool fDaemon = false;
bool fServer = false;
bool fCommandLine = false;
string strMiscWarning;
bool fTestNet = false;
bool fNoListen = false;
bool fLogTimestamps = false;
-CMedianFilter<int64> vTimeOffsets(200,0);
+CMedianFilter<int64_t> vTimeOffsets(200,0);
// Workaround for "multiple definition of `_tls_used'"
// http://svn.boost.org/trac/boost/ticket/4258
extern "C" void tss_cleanup_implemented() { }
// Init openssl library multithreading support
static boost::interprocess::interprocess_mutex** ppmutexOpenSSL;
void locking_callback(int mode, int i, const char* file, int line)
{
if (mode & CRYPTO_LOCK)
ppmutexOpenSSL[i]->lock();
else
ppmutexOpenSSL[i]->unlock();
}
// Init
class CInit
{
public:
CInit()
{
// Init openssl library multithreading support
ppmutexOpenSSL = (boost::interprocess::interprocess_mutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(boost::interprocess::interprocess_mutex*));
for (int i = 0; i < CRYPTO_num_locks(); i++)
ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex();
CRYPTO_set_locking_callback(locking_callback);
#ifdef WIN32
// Seed random number generator with screen scrape and other hardware sources
RAND_screen();
#endif
// Seed random number generator with performance counter
RandAddSeed();
}
~CInit()
{
// Shutdown openssl library multithreading support
CRYPTO_set_locking_callback(NULL);
for (int i = 0; i < CRYPTO_num_locks(); i++)
delete ppmutexOpenSSL[i];
OPENSSL_free(ppmutexOpenSSL);
}
}
instance_of_cinit;
void RandAddSeed()
{
// Seed with CPU performance counter
- int64 nCounter = GetPerformanceCounter();
+ int64_t nCounter = GetPerformanceCounter();
RAND_add(&nCounter, sizeof(nCounter), 1.5);
memset(&nCounter, 0, sizeof(nCounter));
}
void RandAddSeedPerfmon()
{
RandAddSeed();
// This can take up to 2 seconds, so only do it every 10 minutes
- static int64 nLastPerfmon;
+ static int64_t nLastPerfmon;
if (GetTime() < nLastPerfmon + 10 * 60)
return;
nLastPerfmon = GetTime();
#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];
memset(pdata, 0, sizeof(pdata));
unsigned long nSize = sizeof(pdata);
long ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
RegCloseKey(HKEY_PERFORMANCE_DATA);
if (ret == ERROR_SUCCESS)
{
RAND_add(pdata, nSize, nSize/100.0);
memset(pdata, 0, nSize);
printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize);
}
#endif
}
-uint64 GetRand(uint64 nMax)
+uint64_t GetRand(uint64_t nMax)
{
if (nMax == 0)
return 0;
// The range of the random source must be a multiple of the modulus
// to give every possible output value an equal possibility
- uint64 nRange = (std::numeric_limits<uint64>::max() / nMax) * nMax;
- uint64 nRand = 0;
+ uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax;
+ uint64_t nRand = 0;
do
RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
while (nRand >= nRange);
return (nRand % nMax);
}
int GetRandInt(int nMax)
{
return GetRand(nMax);
}
inline int OutputDebugStringF(const char* pszFormat, ...)
{
int ret = 0;
if (fPrintToConsole)
{
// print to console
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
ret = vprintf(pszFormat, arg_ptr);
va_end(arg_ptr);
}
else
{
// print to debug.log
static FILE* fileout = NULL;
if (!fileout)
{
char pszFile[MAX_PATH+100];
GetDataDir(pszFile);
strlcat(pszFile, "/debug.log", sizeof(pszFile));
fileout = fopen(pszFile, "a");
if (fileout) setbuf(fileout, NULL); // unbuffered
}
if (fileout)
{
static bool fStartedNewLine = true;
// Debug print useful for profiling
if (fLogTimestamps && fStartedNewLine)
fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
if (pszFormat[strlen(pszFormat) - 1] == '\n')
fStartedNewLine = true;
else
fStartedNewLine = false;
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
ret = vfprintf(fileout, pszFormat, arg_ptr);
va_end(arg_ptr);
}
}
#ifdef WIN32
if (fPrintToDebugger)
{
static CCriticalSection cs_OutputDebugStringF;
// accumulate a line at a time
CRITICAL_BLOCK(cs_OutputDebugStringF)
{
static char pszBuffer[50000];
static char* pend;
if (pend == NULL)
pend = pszBuffer;
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
int limit = END(pszBuffer) - pend - 2;
int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
pend = END(pszBuffer) - 2;
*pend++ = '\n';
}
else
pend += ret;
*pend = '\0';
char* p1 = pszBuffer;
char* p2;
while (p2 = strchr(p1, '\n'))
{
p2++;
char c = *p2;
*p2 = '\0';
OutputDebugStringA(p1);
*p2 = c;
p1 = p2;
}
if (p1 != pszBuffer)
memmove(pszBuffer, p1, pend - p1 + 1);
pend -= (p1 - pszBuffer);
}
}
#endif
return ret;
}
// Safer snprintf
// - prints up to limit-1 characters
// - output string is always null terminated even if limit reached
// - return value is the number of characters actually printed
int my_snprintf(char* buffer, size_t limit, const char* format, ...)
{
if (limit == 0)
return 0;
va_list arg_ptr;
va_start(arg_ptr, format);
int ret = _vsnprintf(buffer, limit, format, arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
ret = limit - 1;
buffer[limit-1] = 0;
}
return ret;
}
string strprintf(const std::string &format, ...)
{
char buffer[50000];
char* p = buffer;
int limit = sizeof(buffer);
int ret;
loop
{
va_list arg_ptr;
va_start(arg_ptr, format);
ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret >= 0 && ret < limit)
break;
if (p != buffer)
delete[] p;
limit *= 2;
p = new char[limit];
if (p == NULL)
throw std::bad_alloc();
}
string str(p, p+ret);
if (p != buffer)
delete[] p;
return str;
}
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.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
ret = limit - 1;
buffer[limit-1] = 0;
}
printf("ERROR: %s\n", buffer);
return false;
}
void ParseString(const string& str, char c, vector<string>& v)
{
if (str.empty())
return;
string::size_type i1 = 0;
string::size_type i2;
loop
{
i2 = str.find(c, i1);
if (i2 == str.npos)
{
v.push_back(str.substr(i1));
return;
}
v.push_back(str.substr(i1, i2-i1));
i1 = i2+1;
}
}
-string FormatMoney(int64 n, bool fPlus)
+string FormatMoney(int64_t n, bool fPlus)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
- int64 n_abs = (n > 0 ? n : -n);
- int64 quotient = n_abs/COIN;
- int64 remainder = n_abs%COIN;
+ int64_t n_abs = (n > 0 ? n : -n);
+ int64_t quotient = n_abs/COIN;
+ int64_t remainder = n_abs%COIN;
string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder);
// Right-trim excess 0's before the decimal point:
int nTrim = 0;
for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)
++nTrim;
if (nTrim)
str.erase(str.size()-nTrim, nTrim);
if (n < 0)
str.insert((unsigned int)0, 1, '-');
else if (fPlus && n > 0)
str.insert((unsigned int)0, 1, '+');
return str;
}
-bool ParseMoney(const string& str, int64& nRet)
+bool ParseMoney(const string& str, int64_t& nRet)
{
return ParseMoney(str.c_str(), nRet);
}
-bool ParseMoney(const char* pszIn, int64& nRet)
+bool ParseMoney(const char* pszIn, int64_t& nRet)
{
string strWhole;
- int64 nUnits = 0;
+ int64_t nUnits = 0;
const char* p = pszIn;
while (isspace(*p))
p++;
for (; *p; p++)
{
if (*p == '.')
{
p++;
- int64 nMult = CENT*10;
+ int64_t nMult = CENT*10;
while (isdigit(*p) && (nMult > 0))
{
nUnits += nMult * (*p++ - '0');
nMult /= 10;
}
break;
}
if (isspace(*p))
break;
if (!isdigit(*p))
return false;
strWhole.insert(strWhole.end(), *p);
}
for (; *p; p++)
if (!isspace(*p))
return false;
if (strWhole.size() > 10) // guard against 63 bit overflow
return false;
if (nUnits < 0 || nUnits > COIN)
return false;
- int64 nWhole = atoi64(strWhole);
- int64 nValue = nWhole*COIN + nUnits;
+ int64_t nWhole = atoi64(strWhole);
+ int64_t nValue = nWhole*COIN + nUnits;
nRet = nValue;
return true;
}
vector<unsigned char> ParseHex(const char* psz)
{
static char phexdigit[256] =
{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
-1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
// convert hex dump to vector
vector<unsigned char> vch;
loop
{
while (isspace(*psz))
psz++;
char c = phexdigit[(unsigned char)*psz++];
if (c == (char)-1)
break;
unsigned char n = (c << 4);
c = phexdigit[(unsigned char)*psz++];
if (c == (char)-1)
break;
n |= c;
vch.push_back(n);
}
return vch;
}
vector<unsigned char> ParseHex(const string& str)
{
return ParseHex(str.c_str());
}
void ParseParameters(int argc, char* argv[])
{
mapArgs.clear();
mapMultiArgs.clear();
for (int i = 1; i < argc; i++)
{
char psz[10000];
strlcpy(psz, argv[i], sizeof(psz));
char* pszValue = (char*)"";
if (strchr(psz, '='))
{
pszValue = strchr(psz, '=');
*pszValue++ = '\0';
}
#ifdef WIN32
_strlwr(psz);
if (psz[0] == '/')
psz[0] = '-';
#endif
if (psz[0] != '-')
break;
mapArgs[psz] = pszValue;
mapMultiArgs[psz].push_back(pszValue);
}
}
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;
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)
{
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)
{
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;
}
}
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());
}
bool WildcardMatch(const char* psz, const char* mask)
{
loop
{
switch (*mask)
{
case '\0':
return (*psz == '\0');
case '*':
return WildcardMatch(psz, mask+1) || (*psz && WildcardMatch(psz+1, mask));
case '?':
if (*psz == '\0')
return false;
break;
default:
if (*psz != *mask)
return false;
break;
}
psz++;
mask++;
}
}
bool WildcardMatch(const string& str, const string& mask)
{
return WildcardMatch(str.c_str(), mask.c_str());
}
void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
{
#ifdef WIN32
char pszModule[MAX_PATH];
pszModule[0] = '\0';
GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
#else
const char* pszModule = "bitcoin";
#endif
if (pex)
snprintf(pszMessage, 1000,
"EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
else
snprintf(pszMessage, 1000,
"UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
}
void LogException(std::exception* pex, const char* pszThread)
{
char pszMessage[10000];
FormatException(pszMessage, pex, pszThread);
printf("\n%s", pszMessage);
}
void PrintException(std::exception* pex, const char* pszThread)
{
char pszMessage[10000];
FormatException(pszMessage, pex, pszThread);
printf("\n\n************************\n%s\n", pszMessage);
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
strMiscWarning = pszMessage;
throw;
}
void ThreadOneMessageBox(string strMessage)
{
// Skip message boxes if one is already open
static bool fMessageBoxOpen;
if (fMessageBoxOpen)
return;
fMessageBoxOpen = true;
ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
fMessageBoxOpen = false;
}
void PrintExceptionContinue(std::exception* pex, const char* pszThread)
{
char pszMessage[10000];
FormatException(pszMessage, pex, pszThread);
printf("\n\n************************\n%s\n", pszMessage);
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
strMiscWarning = pszMessage;
}
#ifdef WIN32
typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
string MyGetSpecialFolderPath(int nFolder, bool fCreate)
{
char pszPath[MAX_PATH+100] = "";
// SHGetSpecialFolderPath isn't always available on old Windows versions
HMODULE hShell32 = LoadLibraryA("shell32.dll");
if (hShell32)
{
PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
(PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
if (pSHGetSpecialFolderPath)
(*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
FreeModule(hShell32);
}
// Backup option
if (pszPath[0] == '\0')
{
if (nFolder == CSIDL_STARTUP)
{
strcpy(pszPath, getenv("USERPROFILE"));
strcat(pszPath, "\\Start Menu\\Programs\\Startup");
}
else if (nFolder == CSIDL_APPDATA)
{
strcpy(pszPath, getenv("APPDATA"));
}
}
return pszPath;
}
#endif
string GetDefaultDataDir()
{
// Windows: C:\Documents and Settings\username\Application Data\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
// Unix: ~/.bitcoin
#ifdef WIN32
// Windows
return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
#else
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
pszHome = (char*)"/";
string strHome = pszHome;
if (strHome[strHome.size()-1] != '/')
strHome += '/';
#ifdef MAC_OSX
// Mac
strHome += "Library/Application Support/";
filesystem::create_directory(strHome.c_str());
return strHome + "Bitcoin";
#else
// Unix
return strHome + ".bitcoin";
#endif
#endif
}
void GetDataDir(char* pszDir)
{
// pszDir must be at least MAX_PATH length.
int nVariation;
if (pszSetDataDir[0] != 0)
{
strlcpy(pszDir, pszSetDataDir, MAX_PATH);
nVariation = 0;
}
else
{
// This can be called during exceptions by printf, so we cache the
// value so we don't have to do memory allocations after that.
static char pszCachedDir[MAX_PATH];
if (pszCachedDir[0] == 0)
strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
strlcpy(pszDir, pszCachedDir, MAX_PATH);
nVariation = 1;
}
if (fTestNet)
{
char* p = pszDir + strlen(pszDir);
if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
*p++ = '/';
strcpy(p, "testnet");
nVariation += 2;
}
static bool pfMkdir[4];
if (!pfMkdir[nVariation])
{
pfMkdir[nVariation] = true;
boost::filesystem::create_directory(pszDir);
}
}
string GetDataDir()
{
char pszDir[MAX_PATH];
GetDataDir(pszDir);
return pszDir;
}
string GetConfigFile()
{
namespace fs = boost::filesystem;
fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
if (!pathConfig.is_complete())
pathConfig = fs::path(GetDataDir()) / pathConfig;
return pathConfig.string();
}
void ReadConfigFile(map<string, string>& mapSettingsRet,
map<string, vector<string> >& mapMultiSettingsRet)
{
namespace fs = boost::filesystem;
namespace pod = boost::program_options::detail;
fs::ifstream streamConfig(GetConfigFile());
if (!streamConfig.good())
return;
set<string> setOptions;
setOptions.insert("*");
for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
{
// Don't overwrite existing settings so command line settings override bitcoin.conf
string strKey = string("-") + it->string_key;
if (mapSettingsRet.count(strKey) == 0)
mapSettingsRet[strKey] = it->value[0];
mapMultiSettingsRet[strKey].push_back(it->value[0]);
}
}
string GetPidFile()
{
namespace fs = boost::filesystem;
fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
if (!pathConfig.is_complete())
pathConfig = fs::path(GetDataDir()) / pathConfig;
return pathConfig.string();
}
void CreatePidFile(string pidFile, pid_t pid)
{
FILE* file = fopen(pidFile.c_str(), "w");
if (file)
{
fprintf(file, "%d\n", pid);
fclose(file);
}
}
int GetFilesize(FILE* file)
{
int nSavePos = ftell(file);
int nFilesize = -1;
if (fseek(file, 0, SEEK_END) == 0)
nFilesize = ftell(file);
fseek(file, nSavePos, SEEK_SET);
return nFilesize;
}
void ShrinkDebugFile()
{
// Scroll debug.log if it's getting too big
string strFile = GetDataDir() + "/debug.log";
FILE* file = fopen(strFile.c_str(), "r");
if (file && GetFilesize(file) > 10 * 1000000)
{
// Restart the file with some of the end
char pch[200000];
fseek(file, -sizeof(pch), SEEK_END);
int nBytes = fread(pch, 1, sizeof(pch), file);
fclose(file);
file = fopen(strFile.c_str(), "w");
if (file)
{
fwrite(pch, 1, nBytes, file);
fclose(file);
}
}
}
//
// "Never go to sea with two chronometers; take one or three."
// Our three time sources are:
// - System clock
// - 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
+static int64_t nMockTime = 0; // For unit testing
-int64 GetTime()
+int64_t GetTime()
{
if (nMockTime) return nMockTime;
return time(NULL);
}
-void SetMockTime(int64 nMockTimeIn)
+void SetMockTime(int64_t nMockTimeIn)
{
nMockTime = nMockTimeIn;
}
-static int64 nTimeOffset = 0;
+static int64_t nTimeOffset = 0;
-int64 GetAdjustedTime()
+int64_t GetAdjustedTime()
{
return GetTime() + nTimeOffset;
}
-void AddTimeData(unsigned int ip, int64 nTime)
+void AddTimeData(unsigned int ip, int64_t nTime)
{
- int64 nOffsetSample = nTime - GetTime();
+ int64_t nOffsetSample = nTime - GetTime();
// Ignore duplicates
static set<unsigned int> setKnown;
if (!setKnown.insert(ip).second)
return;
// Add data
vTimeOffsets.input(nOffsetSample);
printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
{
- int64 nMedian = vTimeOffsets.median();
- std::vector<int64> vSorted = vTimeOffsets.sorted();
+ int64_t nMedian = vTimeOffsets.median();
+ std::vector<int64_t> vSorted = vTimeOffsets.sorted();
// Only let other nodes change our time by so much
if (abs64(nMedian) < 70 * 60)
{
nTimeOffset = nMedian;
}
else
{
nTimeOffset = 0;
static bool fDone;
if (!fDone)
{
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
bool fMatch = false;
- BOOST_FOREACH(int64 nOffset, vSorted)
+ BOOST_FOREACH(int64_t nOffset, vSorted)
if (nOffset != 0 && abs64(nOffset) < 5 * 60)
fMatch = true;
if (!fMatch)
{
fDone = true;
string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
}
}
}
if (fDebug) {
- BOOST_FOREACH(int64 n, vSorted)
+ BOOST_FOREACH(int64_t n, vSorted)
printf("%+"PRI64d" ", n);
printf("| ");
}
printf("nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
}
}
string FormatVersion(int nVersion)
{
if (nVersion%100 == 0)
return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100);
else
return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100);
}
string FormatFullVersion()
{
string s = FormatVersion(CLIENT_VERSION);
if (VERSION_IS_BETA) {
s += "-";
s += _("beta");
}
return s;
}
// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
{
std::ostringstream ss;
ss << "/";
ss << name << ":" << FormatVersion(nClientVersion);
if (!comments.empty())
ss << "(" << boost::algorithm::join(comments, "; ") << ")";
ss << "/";
return ss.str();
}
#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
// Thread 1 locks A, then B, then C
// Thread 2 locks D, then C, then A
// --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread trys to lock in a different order.
//
struct CLockLocation
{
CLockLocation(const char* pszName, const char* pszFile, int nLine)
{
mutexName = pszName;
sourceFile = pszFile;
sourceLine = nLine;
}
std::string ToString() const
{
return mutexName+" "+sourceFile+":"+itostr(sourceLine);
}
private:
std::string mutexName;
std::string sourceFile;
int sourceLine;
};
typedef std::vector< std::pair<CCriticalSection*, CLockLocation> > LockStack;
static boost::interprocess::interprocess_mutex dd_mutex;
static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders;
static boost::thread_specific_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2)
{
printf("POTENTIAL DEADLOCK DETECTED\n");
printf("Previous lock order was:\n");
BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2)
{
if (i.first == mismatch.first) printf(" (1)");
if (i.first == mismatch.second) printf(" (2)");
printf(" %s\n", i.second.ToString().c_str());
}
printf("Current lock order is:\n");
BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1)
{
if (i.first == mismatch.first) printf(" (1)");
if (i.first == mismatch.second) printf(" (2)");
printf(" %s\n", i.second.ToString().c_str());
}
}
static void push_lock(CCriticalSection* c, const CLockLocation& locklocation)
{
bool fOrderOK = true;
if (lockstack.get() == NULL)
lockstack.reset(new LockStack);
if (fDebug) printf("Locking: %s\n", locklocation.ToString().c_str());
dd_mutex.lock();
(*lockstack).push_back(std::make_pair(c, locklocation));
BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack))
{
if (i.first == c) break;
std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c);
if (lockorders.count(p1))
continue;
lockorders[p1] = (*lockstack);
std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first);
if (lockorders.count(p2))
{
potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
break;
}
}
dd_mutex.unlock();
}
static void pop_lock()
{
if (fDebug)
{
const CLockLocation& locklocation = (*lockstack).rbegin()->second;
printf("Unlocked: %s\n", locklocation.ToString().c_str());
}
dd_mutex.lock();
(*lockstack).pop_back();
dd_mutex.unlock();
}
void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
{
push_lock(this, CLockLocation(pszName, pszFile, nLine));
mutex.lock();
}
void CCriticalSection::Leave()
{
mutex.unlock();
pop_lock();
}
bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine)
{
push_lock(this, CLockLocation(pszName, pszFile, nLine));
bool result = mutex.try_lock();
if (!result) pop_lock();
return result;
}
#else
void CCriticalSection::Enter(const char*, const char*, int)
{
mutex.lock();
}
void CCriticalSection::Leave()
{
mutex.unlock();
}
bool CCriticalSection::TryEnter(const char*, const char*, int)
{
bool result = mutex.try_lock();
return result;
}
#endif /* DEBUG_LOCKORDER */
diff --git a/src/util.h b/src/util.h
index bb90869962..8dd08d8a80 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,730 +1,729 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
+#include <stdint.h>
+
#include "uint256.h"
#ifndef WIN32
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include <map>
#include <vector>
#include <string>
#include <boost/thread.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
-typedef long long int64;
-typedef unsigned long long uint64;
-
#define loop for (;;)
#define BEGIN(a) ((char*)&(a))
#define END(a) ((char*)&((&(a))[1]))
#define UBEGIN(a) ((unsigned char*)&(a))
#define UEND(a) ((unsigned char*)&((&(a))[1]))
#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
#define printf OutputDebugStringF
#ifdef snprintf
#undef snprintf
#endif
#define snprintf my_snprintf
#ifndef PRI64d
#if defined(_MSC_VER) || defined(__MSVCRT__)
#define PRI64d "I64d"
#define PRI64u "I64u"
#define PRI64x "I64x"
#else
#define PRI64d "lld"
#define PRI64u "llu"
#define PRI64x "llx"
#endif
#endif
// This is needed because the foreach macro can't get over the comma in pair<t1, t2>
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
// Align by increasing pointer, must have extra space at end of buffer
template <size_t nBytes, typename T>
T* alignup(T* p)
{
union
{
T* ptr;
size_t n;
} u;
u.ptr = p;
u.n = (u.n + (nBytes-1)) & ~(nBytes-1);
return u.ptr;
}
#ifdef WIN32
#define MSG_NOSIGNAL 0
#define MSG_DONTWAIT 0
#ifndef S_IRUSR
#define S_IRUSR 0400
#define S_IWUSR 0200
#endif
#define unlink _unlink
typedef int socklen_t;
#else
#define WSAGetLastError() errno
#define WSAEINVAL EINVAL
#define WSAEALREADY EALREADY
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEMSGSIZE EMSGSIZE
#define WSAEINTR EINTR
#define WSAEINPROGRESS EINPROGRESS
#define WSAEADDRINUSE EADDRINUSE
#define WSAENOTSOCK EBADF
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR -1
typedef u_int SOCKET;
#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
#define strlwr(psz) to_lower(psz)
#define _strlwr(psz) to_lower(psz)
#define MAX_PATH 1024
#define Beep(n1,n2) (0)
-inline void Sleep(int64 n)
+inline void Sleep(int64_t n)
{
boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(n));
}
#endif
inline int myclosesocket(SOCKET& hSocket)
{
if (hSocket == INVALID_SOCKET)
return WSAENOTSOCK;
#ifdef WIN32
int ret = closesocket(hSocket);
#else
int ret = close(hSocket);
#endif
hSocket = INVALID_SOCKET;
return ret;
}
#define closesocket(s) myclosesocket(s)
#if !defined(QT_GUI)
inline const char* _(const char* psz)
{
return psz;
}
#endif
extern std::map<std::string, std::string> mapArgs;
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
extern bool fDebug;
extern bool fPrintToConsole;
extern bool fPrintToDebugger;
extern char pszSetDataDir[MAX_PATH];
extern bool fRequestShutdown;
extern bool fShutdown;
extern bool fDaemon;
extern bool fServer;
extern bool fCommandLine;
extern std::string strMiscWarning;
extern bool fTestNet;
extern bool fNoListen;
extern bool fLogTimestamps;
void RandAddSeed();
void RandAddSeedPerfmon();
int OutputDebugStringF(const char* pszFormat, ...);
int my_snprintf(char* buffer, size_t limit, const char* format, ...);
std::string strprintf(const std::string &format, ...);
bool error(const std::string &format, ...);
void LogException(std::exception* pex, const char* pszThread);
void PrintException(std::exception* pex, const char* pszThread);
void PrintExceptionContinue(std::exception* pex, const char* pszThread);
void ParseString(const std::string& str, char c, std::vector<std::string>& v);
-std::string FormatMoney(int64 n, bool fPlus=false);
-bool ParseMoney(const std::string& str, int64& nRet);
-bool ParseMoney(const char* pszIn, int64& nRet);
+std::string FormatMoney(int64_t n, bool fPlus=false);
+bool ParseMoney(const std::string& str, int64_t& nRet);
+bool ParseMoney(const char* pszIn, int64_t& nRet);
std::vector<unsigned char> ParseHex(const char* psz);
std::vector<unsigned char> ParseHex(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
std::string DecodeBase64(const std::string& str);
std::string EncodeBase64(const unsigned char* pch, size_t len);
std::string EncodeBase64(const std::string& str);
void ParseParameters(int argc, char* argv[]);
bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask);
int GetFilesize(FILE* file);
void GetDataDir(char* pszDirRet);
std::string GetConfigFile();
std::string GetPidFile();
void CreatePidFile(std::string pidFile, pid_t pid);
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
#ifdef WIN32
std::string MyGetSpecialFolderPath(int nFolder, bool fCreate);
#endif
std::string GetDefaultDataDir();
std::string GetDataDir();
void ShrinkDebugFile();
int GetRandInt(int nMax);
-uint64 GetRand(uint64 nMax);
-int64 GetTime();
-void SetMockTime(int64 nMockTimeIn);
-int64 GetAdjustedTime();
-void AddTimeData(unsigned int ip, int64 nTime);
+uint64_t GetRand(uint64_t nMax);
+int64_t GetTime();
+void SetMockTime(int64_t nMockTimeIn);
+int64_t GetAdjustedTime();
+void AddTimeData(unsigned int ip, int64_t nTime);
std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
// Wrapper to automatically initialize mutex
class CCriticalSection
{
protected:
boost::interprocess::interprocess_recursive_mutex mutex;
public:
explicit CCriticalSection() { }
~CCriticalSection() { }
void Enter(const char* pszName, const char* pszFile, int nLine);
void Leave();
bool TryEnter(const char* pszName, const char* pszFile, int nLine);
};
// Automatically leave critical section when leaving block, needed for exception safety
class CCriticalBlock
{
protected:
CCriticalSection* pcs;
public:
CCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
{
pcs = &csIn;
pcs->Enter(pszName, pszFile, nLine);
}
operator bool() const
{
return true;
}
~CCriticalBlock()
{
pcs->Leave();
}
};
#define CRITICAL_BLOCK(cs) \
if (CCriticalBlock criticalblock = CCriticalBlock(cs, #cs, __FILE__, __LINE__))
class CTryCriticalBlock
{
protected:
CCriticalSection* pcs;
public:
CTryCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
{
pcs = (csIn.TryEnter(pszName, pszFile, nLine) ? &csIn : NULL);
}
operator bool() const
{
return Entered();
}
~CTryCriticalBlock()
{
if (pcs)
{
pcs->Leave();
}
}
bool Entered() const { return pcs != NULL; }
};
#define TRY_CRITICAL_BLOCK(cs) \
if (CTryCriticalBlock criticalblock = CTryCriticalBlock(cs, #cs, __FILE__, __LINE__))
// This is exactly like std::string, but with a custom allocator.
// (secure_allocator<> is defined in serialize.h)
typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
-inline std::string i64tostr(int64 n)
+inline std::string i64tostr(int64_t n)
{
return strprintf("%"PRI64d, n);
}
inline std::string itostr(int n)
{
return strprintf("%d", n);
}
-inline int64 atoi64(const char* psz)
+inline int64_t atoi64(const char* psz)
{
#ifdef _MSC_VER
return _atoi64(psz);
#else
return strtoll(psz, NULL, 10);
#endif
}
-inline int64 atoi64(const std::string& str)
+inline int64_t atoi64(const std::string& str)
{
#ifdef _MSC_VER
return _atoi64(str.c_str());
#else
return strtoll(str.c_str(), NULL, 10);
#endif
}
inline int atoi(const std::string& str)
{
return atoi(str.c_str());
}
inline int roundint(double d)
{
return (int)(d > 0 ? d + 0.5 : d - 0.5);
}
-inline int64 roundint64(double d)
+inline int64_t roundint64(double d)
{
- return (int64)(d > 0 ? d + 0.5 : d - 0.5);
+ return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
}
-inline int64 abs64(int64 n)
+inline int64_t abs64(int64_t n)
{
return (n >= 0 ? n : -n);
}
template<typename T>
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
{
if (itbegin == itend)
return "";
const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
std::string str;
str.reserve((pend-pbegin) * (fSpaces ? 3 : 2));
for (const unsigned char* p = pbegin; p != pend; p++)
str += strprintf((fSpaces && p != pend-1 ? "%02x " : "%02x"), *p);
return str;
}
inline std::string HexStr(const std::vector<unsigned char>& vch, bool fSpaces=false)
{
return HexStr(vch.begin(), vch.end(), fSpaces);
}
template<typename T>
std::string HexNumStr(const T itbegin, const T itend, bool f0x=true)
{
if (itbegin == itend)
return "";
const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
std::string str = (f0x ? "0x" : "");
str.reserve(str.size() + (pend-pbegin) * 2);
for (const unsigned char* p = pend-1; p >= pbegin; p--)
str += strprintf("%02x", *p);
return str;
}
inline std::string HexNumStr(const std::vector<unsigned char>& vch, bool f0x=true)
{
return HexNumStr(vch.begin(), vch.end(), f0x);
}
template<typename T>
void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true)
{
printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str());
}
inline void PrintHex(const std::vector<unsigned char>& vch, const char* pszFormat="%s", bool fSpaces=true)
{
printf(pszFormat, HexStr(vch, fSpaces).c_str());
}
-inline int64 GetPerformanceCounter()
+inline int64_t GetPerformanceCounter()
{
- int64 nCounter = 0;
+ int64_t nCounter = 0;
#ifdef WIN32
QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
#else
timeval t;
gettimeofday(&t, NULL);
nCounter = t.tv_sec * 1000000 + t.tv_usec;
#endif
return nCounter;
}
-inline int64 GetTimeMillis()
+inline int64_t GetTimeMillis()
{
return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) -
boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
}
-inline std::string DateTimeStrFormat(const char* pszFormat, int64 nTime)
+inline std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
{
time_t n = nTime;
struct tm* ptmTime = gmtime(&n);
char pszTime[200];
strftime(pszTime, sizeof(pszTime), pszFormat, ptmTime);
return pszTime;
}
template<typename T>
void skipspaces(T& it)
{
while (isspace(*it))
++it;
}
inline bool IsSwitchChar(char c)
{
#ifdef WIN32
return c == '-' || c == '/';
#else
return c == '-';
#endif
}
inline std::string GetArg(const std::string& strArg, const std::string& strDefault)
{
if (mapArgs.count(strArg))
return mapArgs[strArg];
return strDefault;
}
-inline int64 GetArg(const std::string& strArg, int64 nDefault)
+inline int64_t GetArg(const std::string& strArg, int64_t nDefault)
{
if (mapArgs.count(strArg))
return atoi64(mapArgs[strArg]);
return nDefault;
}
inline bool GetBoolArg(const std::string& strArg)
{
if (mapArgs.count(strArg))
{
if (mapArgs[strArg].empty())
return true;
return (atoi(mapArgs[strArg]) != 0);
}
return false;
}
// Randomize the stack to help protect against buffer overrun exploits
#define IMPLEMENT_RANDOMIZE_STACK(ThreadFn) \
{ \
static char nLoops; \
if (nLoops <= 0) \
nLoops = GetRand(20) + 1; \
if (nLoops-- > 1) \
{ \
ThreadFn; \
return; \
} \
}
#define CATCH_PRINT_EXCEPTION(pszFn) \
catch (std::exception& e) { \
PrintException(&e, (pszFn)); \
} catch (...) { \
PrintException(NULL, (pszFn)); \
}
template<typename T1>
inline uint256 Hash(const T1 pbegin, const T1 pend)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
uint256 hash2;
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
template<typename T1, typename T2>
inline uint256 Hash(const T1 p1begin, const T1 p1end,
const T2 p2begin, const T2 p2end)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
SHA256_Final((unsigned char*)&hash1, &ctx);
uint256 hash2;
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
template<typename T1, typename T2, typename T3>
inline uint256 Hash(const T1 p1begin, const T1 p1end,
const T2 p2begin, const T2 p2end,
const T3 p3begin, const T3 p3end)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0]));
SHA256_Final((unsigned char*)&hash1, &ctx);
uint256 hash2;
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
{
// Most of the time is spent allocating and deallocating CDataStream's
// buffer. If this ever needs to be optimized further, make a CStaticStream
// class with its buffer on the stack.
CDataStream ss(nType, nVersion);
ss.reserve(10000);
ss << obj;
return Hash(ss.begin(), ss.end());
}
inline uint160 Hash160(const std::vector<unsigned char>& vch)
{
uint256 hash1;
SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
uint160 hash2;
RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
// Median filter over a stream of values
// Returns the median of the last N numbers
template <typename T> class CMedianFilter
{
private:
std::vector<T> vValues;
std::vector<T> vSorted;
int nSize;
public:
CMedianFilter(int size, T initial_value):
nSize(size)
{
vValues.reserve(size);
vValues.push_back(initial_value);
vSorted = vValues;
}
void input(T value)
{
if(vValues.size() == nSize)
{
vValues.erase(vValues.begin());
}
vValues.push_back(value);
vSorted.resize(vValues.size());
std::copy(vValues.begin(), vValues.end(), vSorted.begin());
std::sort(vSorted.begin(), vSorted.end());
}
T median() const
{
int size = vSorted.size();
assert(size>0);
if(size & 1) // Odd number of elements
{
return vSorted[size/2];
}
else // Even number of elements
{
return (vSorted[size/2-1] + vSorted[size/2]) / 2;
}
}
int size() const
{
return vValues.size();
}
std::vector<T> sorted () const
{
return vSorted;
}
};
// Note: It turns out we might have been able to use boost::thread
// by using TerminateThread(boost::thread.native_handle(), 0);
#ifdef WIN32
typedef HANDLE pthread_t;
inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
{
DWORD nUnused = 0;
HANDLE hthread =
CreateThread(
NULL, // default security
0, // inherit stack size from parent
(LPTHREAD_START_ROUTINE)pfn, // function pointer
parg, // argument
0, // creation option, start immediately
&nUnused); // thread identifier
if (hthread == NULL)
{
printf("Error: CreateThread() returned %d\n", GetLastError());
return (pthread_t)0;
}
if (!fWantHandle)
{
CloseHandle(hthread);
return (pthread_t)-1;
}
return hthread;
}
inline void SetThreadPriority(int nPriority)
{
SetThreadPriority(GetCurrentThread(), nPriority);
}
#else
inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
{
pthread_t hthread = 0;
int ret = pthread_create(&hthread, NULL, (void*(*)(void*))pfn, parg);
if (ret != 0)
{
printf("Error: pthread_create() returned %d\n", ret);
return (pthread_t)0;
}
if (!fWantHandle)
{
pthread_detach(hthread);
return (pthread_t)-1;
}
return hthread;
}
#define THREAD_PRIORITY_LOWEST PRIO_MAX
#define THREAD_PRIORITY_BELOW_NORMAL 2
#define THREAD_PRIORITY_NORMAL 0
#define THREAD_PRIORITY_ABOVE_NORMAL 0
inline void SetThreadPriority(int nPriority)
{
// It's unclear if it's even possible to change thread priorities on Linux,
// but we really and truly need it for the generation threads.
#ifdef PRIO_THREAD
setpriority(PRIO_THREAD, 0, nPriority);
#else
setpriority(PRIO_PROCESS, 0, nPriority);
#endif
}
inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)
{
return (pthread_cancel(hthread) == 0);
}
inline void ExitThread(size_t nExitCode)
{
pthread_exit((void*)nExitCode);
}
#endif
inline bool AffinityBugWorkaround(void(*pfn)(void*))
{
#ifdef WIN32
// Sometimes after a few hours affinity gets stuck on one processor
DWORD_PTR dwProcessAffinityMask = -1;
DWORD_PTR dwSystemAffinityMask = -1;
GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
if (dwPrev2 != dwProcessAffinityMask)
{
printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask);
if (!CreateThread(pfn, NULL))
printf("Error: CreateThread() failed\n");
return true;
}
#endif
return false;
}
inline uint32_t ByteReverse(uint32_t value)
{
value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
return (value<<16) | (value>>16);
}
#endif
diff --git a/src/wallet.cpp b/src/wallet.cpp
index c35081ce44..20336a380c 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -1,1495 +1,1497 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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 <stdint.h>
+
#include "headers.h"
#include "db.h"
#include "crypter.h"
using namespace std;
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
//
bool CWallet::AddKey(const CKey& key)
{
if (!CCryptoKeyStore::AddKey(key))
return false;
if (!fFileBacked)
return true;
if (!IsCrypted())
return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
return true;
}
bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
if (!fFileBacked)
return true;
CRITICAL_BLOCK(cs_wallet)
{
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
else
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
}
return false;
}
bool CWallet::AddCScript(const uint160 &hash, const CScript& redeemScript)
{
if (!CCryptoKeyStore::AddCScript(hash, redeemScript))
return false;
if (!fFileBacked)
return true;
return CWalletDB(strWalletFile).WriteCScript(hash, redeemScript);
}
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
if (!IsLocked())
return false;
CCrypter crypter;
CKeyingMaterial vMasterKey;
CRITICAL_BLOCK(cs_wallet)
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
return false;
}
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
{
bool fWasLocked = IsLocked();
CRITICAL_BLOCK(cs_wallet)
{
Lock();
CCrypter crypter;
CKeyingMaterial vMasterKey;
BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
{
- int64 nStartTime = GetTimeMillis();
+ int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (pMasterKey.second.nDeriveIterations < 25000)
pMasterKey.second.nDeriveIterations = 25000;
printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
return false;
CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
if (fWasLocked)
Lock();
return true;
}
}
}
return false;
}
// This class implements an addrIncoming entry that causes pre-0.4
// clients to crash on startup if reading a private-key-encrypted wallet.
class CCorruptAddress
{
public:
IMPLEMENT_SERIALIZE
(
if (nType & SER_DISK)
READWRITE(nVersion);
)
};
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
if (IsCrypted())
return false;
CKeyingMaterial vMasterKey;
RandAddSeedPerfmon();
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey;
RandAddSeedPerfmon();
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter;
- int64 nStartTime = GetTimeMillis();
+ int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000;
printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
return false;
if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
return false;
CRITICAL_BLOCK(cs_wallet)
{
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
pwalletdbEncryption = new CWalletDB(strWalletFile);
pwalletdbEncryption->TxnBegin();
pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
}
if (!EncryptKeys(vMasterKey))
{
if (fFileBacked)
pwalletdbEncryption->TxnAbort();
exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
}
if (fFileBacked)
{
CCorruptAddress corruptAddress;
pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
if (!pwalletdbEncryption->TxnCommit())
exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
pwalletdbEncryption->Close();
pwalletdbEncryption = NULL;
}
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;
}
void CWallet::WalletUpdateSpent(const CTransaction &tx)
{
// Anytime a signature is successfully verified, it's proof the outpoint is spent.
// Update the wallet spent flag if it doesn't know due to wallet.dat being
// restored from backup or the user making copies of wallet.dat.
CRITICAL_BLOCK(cs_wallet)
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
CWalletTx& wtx = (*mi).second;
if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
{
printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
wtx.MarkSpent(txin.prevout.n);
wtx.WriteToDisk();
vWalletUpdated.push_back(txin.prevout.hash);
}
}
}
}
}
void CWallet::MarkDirty()
{
CRITICAL_BLOCK(cs_wallet)
{
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
item.second.MarkDirty();
}
}
bool CWallet::AddToWallet(const CWalletTx& wtxIn)
{
uint256 hash = wtxIn.GetHash();
CRITICAL_BLOCK(cs_wallet)
{
// Inserts only if not already there, returns tx inserted or tx found
pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
wtx.BindWallet(this);
bool fInsertedNew = ret.second;
if (fInsertedNew)
wtx.nTimeReceived = GetAdjustedTime();
bool fUpdated = false;
if (!fInsertedNew)
{
// Merge
if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
{
wtx.hashBlock = wtxIn.hashBlock;
fUpdated = true;
}
if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
{
wtx.vMerkleBranch = wtxIn.vMerkleBranch;
wtx.nIndex = wtxIn.nIndex;
fUpdated = true;
}
if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
{
wtx.fFromMe = wtxIn.fFromMe;
fUpdated = true;
}
fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
}
//// debug print
printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
// Write to disk
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);
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
if (txout.scriptPubKey == scriptDefaultKey)
{
std::vector<unsigned char> newDefaultKey;
if (GetKeyFromPool(newDefaultKey, false))
{
SetDefaultKey(newDefaultKey);
SetAddressBookName(CBitcoinAddress(vchDefaultKey), "");
}
}
}
#endif
// Notify UI
vWalletUpdated.push_back(hash);
// since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
WalletUpdateSpent(wtx);
}
// Refresh UI
MainFrameRepaint();
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, bool fFindBlock)
{
uint256 hash = tx.GetHash();
CRITICAL_BLOCK(cs_wallet)
{
bool fExisted = mapWallet.count(hash);
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{
CWalletTx wtx(this,tx);
// Get merkle branch if transaction was found in a block
if (pblock)
wtx.SetMerkleBranch(pblock);
return AddToWallet(wtx);
}
else
WalletUpdateSpent(tx);
}
return false;
}
bool CWallet::EraseFromWallet(uint256 hash)
{
if (!fFileBacked)
return false;
CRITICAL_BLOCK(cs_wallet)
{
if (mapWallet.erase(hash))
CWalletDB(strWalletFile).EraseTx(hash);
}
return true;
}
bool CWallet::IsMine(const CTxIn &txin) const
{
CRITICAL_BLOCK(cs_wallet)
{
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.vout.size())
if (IsMine(prev.vout[txin.prevout.n]))
return true;
}
}
return false;
}
-int64 CWallet::GetDebit(const CTxIn &txin) const
+int64_t CWallet::GetDebit(const CTxIn &txin) const
{
CRITICAL_BLOCK(cs_wallet)
{
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.vout.size())
if (IsMine(prev.vout[txin.prevout.n]))
return prev.vout[txin.prevout.n].nValue;
}
}
return 0;
}
bool CWallet::IsChange(const CTxOut& txout) const
{
CBitcoinAddress address;
// TODO: fix handling of 'change' outputs. The assumption is that any
// payment to a TX_PUBKEYHASH that is mine but isn't in the address book
// is change. That assumption is likely to break when we implement multisignature
// wallets that return change back into a multi-signature-protected address;
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
if (ExtractAddress(txout.scriptPubKey, this, address))
CRITICAL_BLOCK(cs_wallet)
if (!mapAddressBook.count(address))
return true;
return false;
}
-int64 CWalletTx::GetTxTime() const
+int64_t CWalletTx::GetTxTime() const
{
return nTimeReceived;
}
int CWalletTx::GetRequestCount() const
{
// Returns -1 if it wasn't being tracked
int nRequests = -1;
CRITICAL_BLOCK(pwallet->cs_wallet)
{
if (IsCoinBase())
{
// Generated block
if (hashBlock != 0)
{
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
nRequests = (*mi).second;
}
}
else
{
// Did anyone request this transaction?
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
if (mi != pwallet->mapRequestCount.end())
{
nRequests = (*mi).second;
// How about the block it's in?
if (nRequests == 0 && hashBlock != 0)
{
map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
nRequests = (*mi).second;
else
nRequests = 1; // If it's in someone else's block it must have got out
}
}
}
}
return nRequests;
}
-void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CBitcoinAddress, int64> >& listReceived,
- list<pair<CBitcoinAddress, int64> >& listSent, int64& nFee, string& strSentAccount) const
+void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, list<pair<CBitcoinAddress, int64_t> >& listReceived,
+ list<pair<CBitcoinAddress, int64_t> >& listSent, int64_t& nFee, string& strSentAccount) const
{
nGeneratedImmature = nGeneratedMature = nFee = 0;
listReceived.clear();
listSent.clear();
strSentAccount = strFromAccount;
if (IsCoinBase())
{
if (GetBlocksToMaturity() > 0)
nGeneratedImmature = pwallet->GetCredit(*this);
else
nGeneratedMature = GetCredit();
return;
}
// Compute fee:
- int64 nDebit = GetDebit();
+ int64_t nDebit = GetDebit();
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
- int64 nValueOut = GetValueOut();
+ int64_t nValueOut = GetValueOut();
nFee = nDebit - nValueOut;
}
// Sent/received.
BOOST_FOREACH(const CTxOut& txout, vout)
{
CBitcoinAddress address;
vector<unsigned char> vchPubKey;
if (!ExtractAddress(txout.scriptPubKey, NULL, address))
{
printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString().c_str());
address = " unknown ";
}
// Don't report 'change' txouts
if (nDebit > 0 && pwallet->IsChange(txout))
continue;
if (nDebit > 0)
listSent.push_back(make_pair(address, txout.nValue));
if (pwallet->IsMine(txout))
listReceived.push_back(make_pair(address, txout.nValue));
}
}
-void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
- int64& nSent, int64& nFee) const
+void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nGenerated, int64_t& nReceived,
+ int64_t& nSent, int64_t& nFee) const
{
nGenerated = nReceived = nSent = nFee = 0;
- int64 allGeneratedImmature, allGeneratedMature, allFee;
+ int64_t allGeneratedImmature, allGeneratedMature, allFee;
allGeneratedImmature = allGeneratedMature = allFee = 0;
string strSentAccount;
- list<pair<CBitcoinAddress, int64> > listReceived;
- list<pair<CBitcoinAddress, int64> > listSent;
+ list<pair<CBitcoinAddress, int64_t> > listReceived;
+ list<pair<CBitcoinAddress, int64_t> > listSent;
GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
if (strAccount == "")
nGenerated = allGeneratedMature;
if (strAccount == strSentAccount)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& s, listSent)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& s, listSent)
nSent += s.second;
nFee = allFee;
}
CRITICAL_BLOCK(pwallet->cs_wallet)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listReceived)
{
if (pwallet->mapAddressBook.count(r.first))
{
map<CBitcoinAddress, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
nReceived += r.second;
}
else if (strAccount.empty())
{
nReceived += r.second;
}
}
}
}
void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
{
vtxPrev.clear();
const int COPY_DEPTH = 3;
if (SetMerkleBranch() < COPY_DEPTH)
{
vector<uint256> vWorkQueue;
BOOST_FOREACH(const CTxIn& txin, vin)
vWorkQueue.push_back(txin.prevout.hash);
// This critsect is OK because txdb is already open
CRITICAL_BLOCK(pwallet->cs_wallet)
{
map<uint256, const CMerkleTx*> mapWalletPrev;
set<uint256> setAlreadyDone;
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hash = vWorkQueue[i];
if (setAlreadyDone.count(hash))
continue;
setAlreadyDone.insert(hash);
CMerkleTx tx;
map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
if (mi != pwallet->mapWallet.end())
{
tx = (*mi).second;
BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
}
else if (mapWalletPrev.count(hash))
{
tx = *mapWalletPrev[hash];
}
else if (!fClient && txdb.ReadDiskTx(hash, tx))
{
;
}
else
{
printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
continue;
}
int nDepth = tx.SetMerkleBranch();
vtxPrev.push_back(tx);
if (nDepth < COPY_DEPTH)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
vWorkQueue.push_back(txin.prevout.hash);
}
}
}
reverse(vtxPrev.begin(), vtxPrev.end());
}
bool CWalletTx::WriteToDisk()
{
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;
CBlockIndex* pindex = pindexStart;
CRITICAL_BLOCK(cs_wallet)
{
while (pindex)
{
CBlock block;
block.ReadFromDisk(pindex, true);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
ret++;
}
pindex = pindex->pnext;
}
}
return ret;
}
int CWallet::ScanForWalletTransaction(const uint256& hashTx)
{
CTransaction tx;
tx.ReadFromDisk(COutPoint(hashTx, 0));
if (AddToWalletIfInvolvingMe(tx, NULL, true, true))
return 1;
return 0;
}
void CWallet::ReacceptWalletTransactions()
{
CTxDB txdb("r");
bool fRepeat = true;
while (fRepeat) CRITICAL_BLOCK(cs_wallet)
{
fRepeat = false;
vector<CDiskTxPos> vMissingTx;
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
CWalletTx& wtx = item.second;
if (wtx.IsCoinBase() && wtx.IsSpent(0))
continue;
CTxIndex txindex;
bool fUpdated = false;
if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
{
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
if (txindex.vSpent.size() != wtx.vout.size())
{
printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
continue;
}
for (int i = 0; i < txindex.vSpent.size(); i++)
{
if (wtx.IsSpent(i))
continue;
if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
{
wtx.MarkSpent(i);
fUpdated = true;
vMissingTx.push_back(txindex.vSpent[i]);
}
}
if (fUpdated)
{
printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
wtx.MarkDirty();
wtx.WriteToDisk();
}
}
else
{
// Reaccept any txes of ours that aren't already in a block
if (!wtx.IsCoinBase())
wtx.AcceptWalletTransaction(txdb, false);
}
}
if (!vMissingTx.empty())
{
// TODO: optimize this to scan just part of the block chain?
if (ScanForWalletTransactions(pindexGenesisBlock))
fRepeat = true; // Found missing transactions: re-do Reaccept.
}
}
}
void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
{
BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
{
if (!tx.IsCoinBase())
{
uint256 hash = tx.GetHash();
if (!txdb.ContainsTx(hash))
RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
}
}
if (!IsCoinBase())
{
uint256 hash = GetHash();
if (!txdb.ContainsTx(hash))
{
printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
}
}
}
void CWalletTx::RelayWalletTransaction()
{
CTxDB txdb("r");
RelayWalletTransaction(txdb);
}
void CWallet::ResendWalletTransactions()
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
- static int64 nNextTime;
+ static int64_t nNextTime;
if (GetTime() < nNextTime)
return;
bool fFirst = (nNextTime == 0);
nNextTime = GetTime() + GetRand(30 * 60);
if (fFirst)
return;
// Only do it if there's been a new block since last time
- static int64 nLastTime;
+ static int64_t nLastTime;
if (nTimeBestReceived < nLastTime)
return;
nLastTime = GetTime();
// Rebroadcast any of our txes that aren't in a block yet
printf("ResendWalletTransactions()\n");
CTxDB txdb("r");
CRITICAL_BLOCK(cs_wallet)
{
// Sort them in chronological order
multimap<unsigned int, CWalletTx*> mapSorted;
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
CWalletTx& wtx = item.second;
// Don't rebroadcast until it's had plenty of time that
// it should have gotten in already by now.
- if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
+ if (nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60)
mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
}
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
CWalletTx& wtx = *item.second;
wtx.RelayWalletTransaction(txdb);
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Actions
//
-int64 CWallet::GetBalance() const
+int64_t CWallet::GetBalance() const
{
- int64 nTotal = 0;
+ int64_t 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;
}
-int64 CWallet::GetUnconfirmedBalance() const
+int64_t CWallet::GetUnconfirmedBalance() const
{
- int64 nTotal = 0;
+ int64_t 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
+bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const
{
setCoinsRet.clear();
nValueRet = 0;
// List of values less than target
- pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
- coinLowestLarger.first = std::numeric_limits<int64>::max();
+ pair<int64_t, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
+ coinLowestLarger.first = std::numeric_limits<int64_t>::max();
coinLowestLarger.second.first = NULL;
- vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
- int64 nTotalLower = 0;
+ vector<pair<int64_t, pair<const CWalletTx*,unsigned int> > > vValue;
+ int64_t nTotalLower = 0;
CRITICAL_BLOCK(cs_wallet)
{
vector<const CWalletTx*> vCoins;
vCoins.reserve(mapWallet.size());
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
vCoins.push_back(&(*it).second);
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
{
if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
int nDepth = pcoin->GetDepthInMainChain();
if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
continue;
for (int i = 0; i < pcoin->vout.size(); i++)
{
if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
continue;
- int64 n = pcoin->vout[i].nValue;
+ int64_t n = pcoin->vout[i].nValue;
if (n <= 0)
continue;
- pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
+ pair<int64_t,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
if (n == nTargetValue)
{
setCoinsRet.insert(coin.second);
nValueRet += coin.first;
return true;
}
else if (n < nTargetValue + CENT)
{
vValue.push_back(coin);
nTotalLower += n;
}
else if (n < coinLowestLarger.first)
{
coinLowestLarger = coin;
}
}
}
}
if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
{
for (int i = 0; i < vValue.size(); ++i)
{
setCoinsRet.insert(vValue[i].second);
nValueRet += vValue[i].first;
}
return true;
}
if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
{
if (coinLowestLarger.second.first == NULL)
return false;
setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first;
return true;
}
if (nTotalLower >= nTargetValue + CENT)
nTargetValue += CENT;
// Solve subset sum by stochastic approximation
sort(vValue.rbegin(), vValue.rend());
vector<char> vfIncluded;
vector<char> vfBest(vValue.size(), true);
- int64 nBest = nTotalLower;
+ int64_t nBest = nTotalLower;
for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
{
vfIncluded.assign(vValue.size(), false);
- int64 nTotal = 0;
+ int64_t nTotal = 0;
bool fReachedTarget = false;
for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
{
for (int i = 0; i < vValue.size(); i++)
{
if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
{
nTotal += vValue[i].first;
vfIncluded[i] = true;
if (nTotal >= nTargetValue)
{
fReachedTarget = true;
if (nTotal < nBest)
{
nBest = nTotal;
vfBest = vfIncluded;
}
nTotal -= vValue[i].first;
vfIncluded[i] = false;
}
}
}
}
}
// If the next larger is still closer, return it
if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
{
setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first;
}
else {
for (int i = 0; i < vValue.size(); i++)
if (vfBest[i])
{
setCoinsRet.insert(vValue[i].second);
nValueRet += vValue[i].first;
}
//// debug print
printf("SelectCoins() best subset: ");
for (int i = 0; i < vValue.size(); i++)
if (vfBest[i])
printf("%s ", FormatMoney(vValue[i].first).c_str());
printf("total %s\n", FormatMoney(nBest).c_str());
}
return true;
}
-bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
+bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const
{
return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
}
-bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet)
{
- int64 nValue = 0;
- BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
+ int64_t nValue = 0;
+ BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
{
if (nValue < 0)
return false;
nValue += s.second;
}
if (vecSend.empty() || nValue < 0)
return false;
wtxNew.BindWallet(this);
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
{
// txdb must be opened before the mapWallet lock
CTxDB txdb("r");
{
nFeeRet = nTransactionFee;
loop
{
wtxNew.vin.clear();
wtxNew.vout.clear();
wtxNew.fFromMe = true;
- int64 nTotalValue = nValue + nFeeRet;
+ int64_t nTotalValue = nValue + nFeeRet;
double dPriority = 0;
// vouts to the payees
- BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
+ BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
wtxNew.vout.push_back(CTxOut(s.second, s.first));
// Choose coins to use
set<pair<const CWalletTx*,unsigned int> > setCoins;
- int64 nValueIn = 0;
+ int64_t nValueIn = 0;
if (!SelectCoins(nTotalValue, setCoins, nValueIn))
return false;
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
- int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
+ int64_t nCredit = pcoin.first->vout[pcoin.second].nValue;
dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
}
- int64 nChange = nValueIn - nValue - nFeeRet;
+ int64_t nChange = nValueIn - nValue - nFeeRet;
// if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
// or until nChange becomes zero
// NOTE: this depends on the exact behaviour of GetMinFee
if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
{
- int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
+ int64_t nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
nChange -= nMoveToFee;
nFeeRet += nMoveToFee;
}
if (nChange > 0)
{
// Note: We use a new key here to keep it from being obvious which side is the change.
// The drawback is that by not reusing a previous key, the change may be lost if a
// backup is restored, if the backup doesn't have the new private key for the change.
// If we reused the old key, it would be possible to add code to look for and
// rediscover unknown transactions that were written with keys of ours to recover
// post-backup change.
// Reserve a new key pair from key pool
vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
// assert(mapKeys.count(vchPubKey));
// Fill a vout to ourself
// TODO: pass in scriptChange instead of reservekey so
// change transaction isn't always pay-to-bitcoin-address
CScript scriptChange;
scriptChange.SetBitcoinAddress(vchPubKey);
// Insert change txn at random position:
vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
}
else
reservekey.ReturnKey();
// Fill vin
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
// Sign
int nIn = 0;
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
return false;
// Limit size
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
return false;
dPriority /= nBytes;
// Check that enough fee is included
- int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
+ int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);
bool fAllowFree = CTransaction::AllowFree(dPriority);
- int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
+ int64_t nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
if (nFeeRet < max(nPayFee, nMinFee))
{
nFeeRet = max(nPayFee, nMinFee);
continue;
}
// Fill vtxPrev by copying from previous transactions vtxPrev
wtxNew.AddSupportingTransactions(txdb);
wtxNew.fTimeReceivedIsTxTime = true;
break;
}
}
}
return true;
}
-bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+bool CWallet::CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet)
{
- vector< pair<CScript, int64> > vecSend;
+ vector< pair<CScript, int64_t> > vecSend;
vecSend.push_back(make_pair(scriptPubKey, nValue));
return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
}
// Call after CreateTransaction unless you want to abort
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
{
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
{
printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
{
// This is only to keep the database open to defeat the auto-flush for the
// duration of this scope. This is the only place where this optimization
// maybe makes sense; please don't do it anywhere else.
CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
// Take key pair from key pool so it won't be used again
reservekey.KeepKey();
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
AddToWallet(wtxNew);
// Mark old coins as spent
set<CWalletTx*> setCoins;
BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
coin.BindWallet(this);
coin.MarkSpent(txin.prevout.n);
coin.WriteToDisk();
vWalletUpdated.push_back(coin.GetHash());
}
if (fFileBacked)
delete pwalletdb;
}
// Track how many getdata requests our transaction gets
mapRequestCount[wtxNew.GetHash()] = 0;
// Broadcast
if (!wtxNew.AcceptToMemoryPool())
{
// This must not fail. The transaction has already been signed and recorded.
printf("CommitTransaction() : Error: Transaction not valid");
return false;
}
wtxNew.RelayWalletTransaction();
}
MainFrameRepaint();
return true;
}
-string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
+string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee)
{
CReserveKey reservekey(this);
- int64 nFeeRequired;
+ int64_t nFeeRequired;
if (IsLocked())
{
string strError = _("Error: Wallet locked, unable to create transaction ");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
{
string strError;
if (nValue + nFeeRequired > GetBalance())
strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str());
else
strError = _("Error: Transaction creation failed ");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
return "ABORTED";
if (!CommitTransaction(wtxNew, reservekey))
return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
MainFrameRepaint();
return "";
}
-string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
+string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64_t nValue, CWalletTx& wtxNew, bool fAskFee)
{
// Check amount
if (nValue <= 0)
return _("Invalid amount");
if (nValue + nTransactionFee > GetBalance())
return _("Insufficient funds");
// Parse bitcoin address
CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(address);
return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
}
int CWallet::LoadWallet(bool& fFirstRunRet)
{
if (!fFileBacked)
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();
if (!HaveKey(Hash160(vchDefaultKey)))
{
// Create new keyUser and set as default key
RandAddSeedPerfmon();
std::vector<unsigned char> newDefaultKey;
if (!GetKeyFromPool(newDefaultKey, false))
return DB_LOAD_FAIL;
SetDefaultKey(newDefaultKey);
if (!SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""))
return DB_LOAD_FAIL;
}
CreateThread(ThreadFlushWalletDB, &strWalletFile);
return DB_LOAD_OK;
}
bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
{
mapAddressBook[address] = strName;
if (!fFileBacked)
return false;
return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
}
bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
{
mapAddressBook.erase(address);
if (!fFileBacked)
return false;
return CWalletDB(strWalletFile).EraseName(address.ToString());
}
void CWallet::PrintWallet(const CBlock& block)
{
CRITICAL_BLOCK(cs_wallet)
{
if (mapWallet.count(block.vtx[0].GetHash()))
{
CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
}
}
printf("\n");
}
bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
{
CRITICAL_BLOCK(cs_wallet)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
if (mi != mapWallet.end())
{
wtx = (*mi).second;
return true;
}
}
return false;
}
bool CWallet::SetDefaultKey(const std::vector<unsigned char> &vchPubKey)
{
if (fFileBacked)
{
if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
return false;
}
vchDefaultKey = vchPubKey;
return true;
}
bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
{
if (!pwallet->fFileBacked)
return false;
strWalletFileOut = pwallet->strWalletFile;
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)
+ BOOST_FOREACH(int64_t nIndex, setKeyPool)
walletdb.ErasePool(nIndex);
setKeyPool.clear();
if (IsLocked())
return false;
- int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
+ int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0);
for (int i = 0; i < nKeys; i++)
{
- int64 nIndex = i+1;
+ int64_t 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)
{
if (IsLocked())
return false;
CWalletDB walletdb(strWalletFile);
// Top up key pool
- int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
+ int64_t nTargetSize = max(GetArg("-keypool", 100), (int64_t)0);
while (setKeyPool.size() < nTargetSize+1)
{
- int64 nEnd = 1;
+ int64_t nEnd = 1;
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
throw runtime_error("TopUpKeyPool() : writing generated key failed");
setKeyPool.insert(nEnd);
printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
}
}
return true;
}
-void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
+void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey.clear();
CRITICAL_BLOCK(cs_wallet)
{
if (!IsLocked())
TopUpKeyPool();
// Get the oldest key
if(setKeyPool.empty())
return;
CWalletDB walletdb(strWalletFile);
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
throw runtime_error("ReserveKeyFromKeyPool() : read failed");
if (!HaveKey(Hash160(keypool.vchPubKey)))
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
assert(!keypool.vchPubKey.empty());
printf("keypool reserve %"PRI64d"\n", nIndex);
}
}
-int64 CWallet::AddReserveKey(const CKeyPool& keypool)
+int64_t CWallet::AddReserveKey(const CKeyPool& keypool)
{
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
{
CWalletDB walletdb(strWalletFile);
- int64 nIndex = 1 + *(--setKeyPool.end());
+ int64_t nIndex = 1 + *(--setKeyPool.end());
if (!walletdb.WritePool(nIndex, keypool))
throw runtime_error("AddReserveKey() : writing added key failed");
setKeyPool.insert(nIndex);
return nIndex;
}
return -1;
}
-void CWallet::KeepKey(int64 nIndex)
+void CWallet::KeepKey(int64_t nIndex)
{
// Remove from key pool
if (fFileBacked)
{
CWalletDB walletdb(strWalletFile);
walletdb.ErasePool(nIndex);
}
printf("keypool keep %"PRI64d"\n", nIndex);
}
-void CWallet::ReturnKey(int64 nIndex)
+void CWallet::ReturnKey(int64_t nIndex)
{
// Return to key pool
CRITICAL_BLOCK(cs_wallet)
setKeyPool.insert(nIndex);
printf("keypool return %"PRI64d"\n", nIndex);
}
bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse)
{
- int64 nIndex = 0;
+ int64_t nIndex = 0;
CKeyPool keypool;
CRITICAL_BLOCK(cs_wallet)
{
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
{
if (fAllowReuse && !vchDefaultKey.empty())
{
result = vchDefaultKey;
return true;
}
if (IsLocked()) return false;
result = GenerateNewKey();
return true;
}
KeepKey(nIndex);
result = keypool.vchPubKey;
}
return true;
}
-int64 CWallet::GetOldestKeyPoolTime()
+int64_t CWallet::GetOldestKeyPoolTime()
{
- int64 nIndex = 0;
+ int64_t nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
return GetTime();
ReturnKey(nIndex);
return keypool.nTime;
}
vector<unsigned char> CReserveKey::GetReservedKey()
{
if (nIndex == -1)
{
CKeyPool keypool;
pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex != -1)
vchPubKey = keypool.vchPubKey;
else
{
printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool.");
vchPubKey = pwallet->vchDefaultKey;
}
}
assert(!vchPubKey.empty());
return vchPubKey;
}
void CReserveKey::KeepKey()
{
if (nIndex != -1)
pwallet->KeepKey(nIndex);
nIndex = -1;
vchPubKey.clear();
}
void CReserveKey::ReturnKey()
{
if (nIndex != -1)
pwallet->ReturnKey(nIndex);
nIndex = -1;
vchPubKey.clear();
}
void CWallet::GetAllReserveAddresses(set<CBitcoinAddress>& setAddress)
{
setAddress.clear();
CWalletDB walletdb(strWalletFile);
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
- BOOST_FOREACH(const int64& id, setKeyPool)
+ BOOST_FOREACH(const int64_t& id, setKeyPool)
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))
throw runtime_error("GetAllReserveKeyHashes() : read failed");
CBitcoinAddress address(keypool.vchPubKey);
assert(!keypool.vchPubKey.empty());
if (!HaveKey(address))
throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool");
setAddress.insert(address);
}
}
diff --git a/src/wallet.h b/src/wallet.h
index a7d07c993f..7ab1c708f7 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -1,652 +1,654 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
#ifndef BITCOIN_WALLET_H
#define BITCOIN_WALLET_H
+#include <stdint.h>
+
#include "bignum.h"
#include "key.h"
#include "keystore.h"
#include "script.h"
class CWalletTx;
class CReserveKey;
class CWalletDB;
// A CWallet is an extension of a keystore, which also maintains a set of
// transactions and balances, and provides the ability to create new
// transactions
class CWallet : public CCryptoKeyStore
{
private:
- bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
- bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
+ bool SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const;
+ bool SelectCoins(int64_t nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const;
CWalletDB *pwalletdbEncryption;
public:
mutable CCriticalSection cs_wallet;
bool fFileBacked;
std::string strWalletFile;
- std::set<int64> setKeyPool;
+ std::set<int64_t> setKeyPool;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID;
CWallet()
{
fFileBacked = false;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
}
CWallet(std::string strWalletFileIn)
{
strWalletFile = strWalletFileIn;
fFileBacked = true;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
}
std::map<uint256, CWalletTx> mapWallet;
std::vector<uint256> vWalletUpdated;
std::map<uint256, int> mapRequestCount;
std::map<CBitcoinAddress, std::string> mapAddressBook;
std::vector<unsigned char> vchDefaultKey;
// keystore implementation
// Adds a key to the store, and saves it to disk.
bool AddKey(const CKey& key);
// Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
// Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
// Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
bool AddCScript(const uint160& hash, const CScript& redeemScript);
bool LoadCScript(const uint160& hash, const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(hash, redeemScript); }
bool Unlock(const SecureString& strWalletPassphrase);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false);
bool EraseFromWallet(uint256 hash);
void WalletUpdateSpent(const CTransaction& prevout);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
int ScanForWalletTransaction(const uint256& hashTx);
void ReacceptWalletTransactions();
void ResendWalletTransactions();
- int64 GetBalance() const;
- int64 GetUnconfirmedBalance() const;
- bool CreateTransaction(const std::vector<std::pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
- bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
+ int64_t GetBalance() const;
+ int64_t GetUnconfirmedBalance() const;
+ bool CreateTransaction(const std::vector<std::pair<CScript, int64_t> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet);
+ bool CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
bool BroadcastTransaction(CWalletTx& wtxNew);
- std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
- std::string SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
+ std::string SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee=false);
+ std::string SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64_t nValue, CWalletTx& wtxNew, bool fAskFee=false);
bool NewKeyPool();
bool TopUpKeyPool();
- int64 AddReserveKey(const CKeyPool& keypool);
- void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
- void KeepKey(int64 nIndex);
- void ReturnKey(int64 nIndex);
+ int64_t AddReserveKey(const CKeyPool& keypool);
+ void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool);
+ void KeepKey(int64_t nIndex);
+ void ReturnKey(int64_t nIndex);
bool GetKeyFromPool(std::vector<unsigned char> &key, bool fAllowReuse=true);
- int64 GetOldestKeyPoolTime();
+ int64_t GetOldestKeyPoolTime();
void GetAllReserveAddresses(std::set<CBitcoinAddress>& setAddress);
bool IsMine(const CTxIn& txin) const;
- int64 GetDebit(const CTxIn& txin) const;
+ int64_t GetDebit(const CTxIn& txin) const;
bool IsMine(const CTxOut& txout) const
{
return ::IsMine(*this, txout.scriptPubKey);
}
- int64 GetCredit(const CTxOut& txout) const
+ int64_t GetCredit(const CTxOut& txout) const
{
if (!MoneyRange(txout.nValue))
throw std::runtime_error("CWallet::GetCredit() : value out of range");
return (IsMine(txout) ? txout.nValue : 0);
}
bool IsChange(const CTxOut& txout) const;
- int64 GetChange(const CTxOut& txout) const
+ int64_t GetChange(const CTxOut& txout) const
{
if (!MoneyRange(txout.nValue))
throw std::runtime_error("CWallet::GetChange() : value out of range");
return (IsChange(txout) ? txout.nValue : 0);
}
bool IsMine(const CTransaction& tx) const
{
BOOST_FOREACH(const CTxOut& txout, tx.vout)
if (IsMine(txout))
return true;
return false;
}
bool IsFromMe(const CTransaction& tx) const
{
return (GetDebit(tx) > 0);
}
- int64 GetDebit(const CTransaction& tx) const
+ int64_t GetDebit(const CTransaction& tx) const
{
- int64 nDebit = 0;
+ int64_t nDebit = 0;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
nDebit += GetDebit(txin);
if (!MoneyRange(nDebit))
throw std::runtime_error("CWallet::GetDebit() : value out of range");
}
return nDebit;
}
- int64 GetCredit(const CTransaction& tx) const
+ int64_t GetCredit(const CTransaction& tx) const
{
- int64 nCredit = 0;
+ int64_t nCredit = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
nCredit += GetCredit(txout);
if (!MoneyRange(nCredit))
throw std::runtime_error("CWallet::GetCredit() : value out of range");
}
return nCredit;
}
- int64 GetChange(const CTransaction& tx) const
+ int64_t GetChange(const CTransaction& tx) const
{
- int64 nChange = 0;
+ int64_t nChange = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
nChange += GetChange(txout);
if (!MoneyRange(nChange))
throw std::runtime_error("CWallet::GetChange() : value out of range");
}
return nChange;
}
void SetBestChain(const CBlockLocator& loc)
{
CWalletDB walletdb(strWalletFile);
walletdb.WriteBestBlock(loc);
}
int LoadWallet(bool& fFirstRunRet);
// bool BackupWallet(const std::string& strDest);
bool SetAddressBookName(const CBitcoinAddress& address, const std::string& strName);
bool DelAddressBookName(const CBitcoinAddress& address);
void UpdatedTransaction(const uint256 &hashTx)
{
CRITICAL_BLOCK(cs_wallet)
vWalletUpdated.push_back(hashTx);
}
void PrintWallet(const CBlock& block);
void Inventory(const uint256 &hash)
{
CRITICAL_BLOCK(cs_wallet)
{
std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
}
int GetKeyPoolSize()
{
return setKeyPool.size();
}
bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);
};
class CReserveKey
{
protected:
CWallet* pwallet;
- int64 nIndex;
+ int64_t nIndex;
std::vector<unsigned char> vchPubKey;
public:
CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn;
}
~CReserveKey()
{
if (!fShutdown)
ReturnKey();
}
void ReturnKey();
std::vector<unsigned char> GetReservedKey();
void KeepKey();
};
//
// A transaction with a bunch of additional info that only the owner cares
// about. It includes any unrecorded transactions needed to link it back
// to the block chain.
//
class CWalletTx : public CMerkleTx
{
private:
const CWallet* pwallet;
public:
std::vector<CMerkleTx> vtxPrev;
std::map<std::string, std::string> mapValue;
std::vector<std::pair<std::string, std::string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime;
unsigned int nTimeReceived; // time received by this node
char fFromMe;
std::string strFromAccount;
std::vector<char> vfSpent; // which outputs are already spent
// memory only
mutable char fDebitCached;
mutable char fCreditCached;
mutable char fAvailableCreditCached;
mutable char fChangeCached;
- mutable int64 nDebitCached;
- mutable int64 nCreditCached;
- mutable int64 nAvailableCreditCached;
- mutable int64 nChangeCached;
+ mutable int64_t nDebitCached;
+ mutable int64_t nCreditCached;
+ mutable int64_t nAvailableCreditCached;
+ mutable int64_t nChangeCached;
// memory only UI hints
mutable unsigned int nTimeDisplayed;
mutable int nLinesDisplayed;
mutable char fConfirmedDisplayed;
CWalletTx()
{
Init(NULL);
}
CWalletTx(const CWallet* pwalletIn)
{
Init(pwalletIn);
}
CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
{
Init(pwalletIn);
}
CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
{
Init(pwalletIn);
}
void Init(const CWallet* pwalletIn)
{
pwallet = pwalletIn;
vtxPrev.clear();
mapValue.clear();
vOrderForm.clear();
fTimeReceivedIsTxTime = false;
nTimeReceived = 0;
fFromMe = false;
strFromAccount.clear();
vfSpent.clear();
fDebitCached = false;
fCreditCached = false;
fAvailableCreditCached = false;
fChangeCached = false;
nDebitCached = 0;
nCreditCached = 0;
nAvailableCreditCached = 0;
nChangeCached = 0;
nTimeDisplayed = 0;
nLinesDisplayed = 0;
fConfirmedDisplayed = false;
}
IMPLEMENT_SERIALIZE
(
CWalletTx* pthis = const_cast<CWalletTx*>(this);
if (fRead)
pthis->Init(NULL);
char fSpent = false;
if (!fRead)
{
pthis->mapValue["fromaccount"] = pthis->strFromAccount;
std::string str;
BOOST_FOREACH(char f, vfSpent)
{
str += (f ? '1' : '0');
if (f)
fSpent = true;
}
pthis->mapValue["spent"] = str;
}
nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action);
READWRITE(vtxPrev);
READWRITE(mapValue);
READWRITE(vOrderForm);
READWRITE(fTimeReceivedIsTxTime);
READWRITE(nTimeReceived);
READWRITE(fFromMe);
READWRITE(fSpent);
if (fRead)
{
pthis->strFromAccount = pthis->mapValue["fromaccount"];
if (mapValue.count("spent"))
BOOST_FOREACH(char c, pthis->mapValue["spent"])
pthis->vfSpent.push_back(c != '0');
else
pthis->vfSpent.assign(vout.size(), fSpent);
}
pthis->mapValue.erase("fromaccount");
pthis->mapValue.erase("version");
pthis->mapValue.erase("spent");
)
// marks certain txout's as spent
// returns true if any update took place
bool UpdateSpent(const std::vector<char>& vfNewSpent)
{
bool fReturn = false;
for (int i=0; i < vfNewSpent.size(); i++)
{
if (i == vfSpent.size())
break;
if (vfNewSpent[i] && !vfSpent[i])
{
vfSpent[i] = true;
fReturn = true;
fAvailableCreditCached = false;
}
}
return fReturn;
}
// make sure balances are recalculated
void MarkDirty()
{
fCreditCached = false;
fAvailableCreditCached = false;
fDebitCached = false;
fChangeCached = false;
}
void BindWallet(CWallet *pwalletIn)
{
pwallet = pwalletIn;
MarkDirty();
}
void MarkSpent(unsigned int nOut)
{
if (nOut >= vout.size())
throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range");
vfSpent.resize(vout.size());
if (!vfSpent[nOut])
{
vfSpent[nOut] = true;
fAvailableCreditCached = false;
}
}
bool IsSpent(unsigned int nOut) const
{
if (nOut >= vout.size())
throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range");
if (nOut >= vfSpent.size())
return false;
return (!!vfSpent[nOut]);
}
- int64 GetDebit() const
+ int64_t GetDebit() const
{
if (vin.empty())
return 0;
if (fDebitCached)
return nDebitCached;
nDebitCached = pwallet->GetDebit(*this);
fDebitCached = true;
return nDebitCached;
}
- int64 GetCredit(bool fUseCache=true) const
+ int64_t GetCredit(bool fUseCache=true) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
// GetBalance can assume transactions in mapWallet won't change
if (fUseCache && fCreditCached)
return nCreditCached;
nCreditCached = pwallet->GetCredit(*this);
fCreditCached = true;
return nCreditCached;
}
- int64 GetAvailableCredit(bool fUseCache=true) const
+ int64_t GetAvailableCredit(bool fUseCache=true) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
if (fUseCache && fAvailableCreditCached)
return nAvailableCreditCached;
- int64 nCredit = 0;
+ int64_t nCredit = 0;
for (int i = 0; i < vout.size(); i++)
{
if (!IsSpent(i))
{
const CTxOut &txout = vout[i];
nCredit += pwallet->GetCredit(txout);
if (!MoneyRange(nCredit))
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
}
}
nAvailableCreditCached = nCredit;
fAvailableCreditCached = true;
return nCredit;
}
- int64 GetChange() const
+ int64_t GetChange() const
{
if (fChangeCached)
return nChangeCached;
nChangeCached = pwallet->GetChange(*this);
fChangeCached = true;
return nChangeCached;
}
- void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list<std::pair<CBitcoinAddress, int64> >& listReceived,
- std::list<std::pair<CBitcoinAddress, int64> >& listSent, int64& nFee, std::string& strSentAccount) const;
+ void GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, std::list<std::pair<CBitcoinAddress, int64_t> >& listReceived,
+ std::list<std::pair<CBitcoinAddress, int64_t> >& listSent, int64_t& nFee, std::string& strSentAccount) const;
- void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived,
- int64& nSent, int64& nFee) const;
+ void GetAccountAmounts(const std::string& strAccount, int64_t& nGenerated, int64_t& nReceived,
+ int64_t& nSent, int64_t& nFee) const;
bool IsFromMe() const
{
return (GetDebit() > 0);
}
bool IsConfirmed() const
{
// Quick answer in most cases
if (!IsFinal())
return false;
if (GetDepthInMainChain() >= 1)
return true;
if (!IsFromMe()) // using wtx's cached debit
return false;
// If no confirmations but it's from us, we can still
// consider it confirmed if all dependencies are confirmed
std::map<uint256, const CMerkleTx*> mapPrev;
std::vector<const CMerkleTx*> vWorkQueue;
vWorkQueue.reserve(vtxPrev.size()+1);
vWorkQueue.push_back(this);
for (int i = 0; i < vWorkQueue.size(); i++)
{
const CMerkleTx* ptx = vWorkQueue[i];
if (!ptx->IsFinal())
return false;
if (ptx->GetDepthInMainChain() >= 1)
continue;
if (!pwallet->IsFromMe(*ptx))
return false;
if (mapPrev.empty())
BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
mapPrev[tx.GetHash()] = &tx;
BOOST_FOREACH(const CTxIn& txin, ptx->vin)
{
if (!mapPrev.count(txin.prevout.hash))
return false;
vWorkQueue.push_back(mapPrev[txin.prevout.hash]);
}
}
return true;
}
bool WriteToDisk();
- int64 GetTxTime() const;
+ int64_t GetTxTime() const;
int GetRequestCount() const;
void AddSupportingTransactions(CTxDB& txdb);
bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true);
bool AcceptWalletTransaction();
void RelayWalletTransaction(CTxDB& txdb);
void RelayWalletTransaction();
};
//
// Private key that includes an expiration date in case it never gets used.
//
class CWalletKey
{
public:
CPrivKey vchPrivKey;
- int64 nTimeCreated;
- int64 nTimeExpires;
+ int64_t nTimeCreated;
+ int64_t nTimeExpires;
std::string strComment;
//// todo: add something to note what created it (user, getnewaddress, change)
//// maybe should have a map<string, string> property map
- CWalletKey(int64 nExpires=0)
+ CWalletKey(int64_t nExpires=0)
{
nTimeCreated = (nExpires ? GetTime() : 0);
nTimeExpires = nExpires;
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vchPrivKey);
READWRITE(nTimeCreated);
READWRITE(nTimeExpires);
READWRITE(strComment);
)
};
//
// Account information.
// Stored in wallet with key "acc"+string account name
//
class CAccount
{
public:
std::vector<unsigned char> vchPubKey;
CAccount()
{
SetNull();
}
void SetNull()
{
vchPubKey.clear();
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vchPubKey);
)
};
//
// Internal transfers.
// Database key is acentry<account><counter>
//
class CAccountingEntry
{
public:
std::string strAccount;
- int64 nCreditDebit;
- int64 nTime;
+ int64_t nCreditDebit;
+ int64_t nTime;
std::string strOtherAccount;
std::string strComment;
CAccountingEntry()
{
SetNull();
}
void SetNull()
{
nCreditDebit = 0;
nTime = 0;
strAccount.clear();
strOtherAccount.clear();
strComment.clear();
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
// Note: strAccount is serialized as part of the key, not here.
READWRITE(nCreditDebit);
READWRITE(nTime);
READWRITE(strOtherAccount);
READWRITE(strComment);
)
};
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
#endif

File Metadata

Mime Type
text/x-diff
Expires
Sun, Mar 2, 11:24 (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187588
Default Alt Text
(873 KB)

Event Timeline