-
-
Save anonymous/b4d5d1ab333c5d6e238fdc2242a428b5 to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"%file: ./base58.h" | |
// Copyright (c) 2009 Satoshi Nakamoto | |
// 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. | |
// | |
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | |
inline 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 | |
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 string | |
string str; | |
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 string to big endian | |
reverse(str.begin(), str.end()); | |
return str; | |
} | |
inline string EncodeBase58(const vector<unsigned char>& vch) | |
{ | |
return EncodeBase58(&vch[0], &vch[0] + vch.size()); | |
} | |
inline bool DecodeBase58(const char* psz, 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 | |
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; | |
} | |
inline bool DecodeBase58(const string& str, vector<unsigned char>& vchRet) | |
{ | |
return DecodeBase58(str.c_str(), vchRet); | |
} | |
inline string EncodeBase58Check(const vector<unsigned char>& vchIn) | |
{ | |
// add 4-byte hash check to the end | |
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); | |
} | |
inline bool DecodeBase58Check(const char* psz, 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; | |
} | |
inline bool DecodeBase58Check(const string& str, vector<unsigned char>& vchRet) | |
{ | |
return DecodeBase58Check(str.c_str(), vchRet); | |
} | |
static const unsigned char ADDRESSVERSION = 0; | |
inline string Hash160ToAddress(uint160 hash160) | |
{ | |
// add 1-byte version number to the front | |
vector<unsigned char> vch(1, ADDRESSVERSION); | |
vch.insert(vch.end(), UBEGIN(hash160), UEND(hash160)); | |
return EncodeBase58Check(vch); | |
} | |
inline bool AddressToHash160(const char* psz, uint160& hash160Ret) | |
{ | |
vector<unsigned char> vch; | |
if (!DecodeBase58Check(psz, vch)) | |
return false; | |
if (vch.empty()) | |
return false; | |
unsigned char nVersion = vch[0]; | |
if (vch.size() != sizeof(hash160Ret) + 1) | |
return false; | |
memcpy(&hash160Ret, &vch[1], sizeof(hash160Ret)); | |
return (nVersion <= ADDRESSVERSION); | |
} | |
inline bool AddressToHash160(const string& str, uint160& hash160Ret) | |
{ | |
return AddressToHash160(str.c_str(), hash160Ret); | |
} | |
inline bool IsValidBitcoinAddress(const char* psz) | |
{ | |
uint160 hash160; | |
return AddressToHash160(psz, hash160); | |
} | |
inline bool IsValidBitcoinAddress(const string& str) | |
{ | |
return IsValidBitcoinAddress(str.c_str()); | |
} | |
inline string PubKeyToAddress(const vector<unsigned char>& vchPubKey) | |
{ | |
return Hash160ToAddress(Hash160(vchPubKey)); | |
} | |
"%file: ./bignum.h" | |
// Copyright (c) 2009-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. | |
#include <stdexcept> | |
#include <vector> | |
#include <openssl/bn.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(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); } | |
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 > INT_MAX ? INT_MAX : n); | |
else | |
return (n > INT_MAX ? INT_MIN : -(int)n); | |
} | |
void setint64(int64 n) | |
{ | |
unsigned char pch[sizeof(n) + 6]; | |
unsigned char* p = pch + 4; | |
bool fNegative = false; | |
if (n < (int64)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) | |
{ | |
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(); | |
vch2[0] = (nSize >> 24) & 0xff; | |
vch2[1] = (nSize >> 16) & 0xff; | |
vch2[2] = (nSize >> 8) & 0xff; | |
vch2[3] = (nSize >> 0) & 0xff; | |
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; | |
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=VERSION) const | |
{ | |
return ::GetSerializeSize(getvch(), nType, nVersion); | |
} | |
template<typename Stream> | |
void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const | |
{ | |
::Serialize(s, getvch(), nType, nVersion); | |
} | |
template<typename Stream> | |
void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) | |
{ | |
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 ubuntu 9.10 if 2^shift is greater than the number | |
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; | |
// Note: BN_rshift segfaults on 64-bit ubuntu 9.10 if 2^shift is greater than the number | |
if (!BN_rshift(&r, &a, shift)) | |
throw bignum_error("CBigNum:operator>> : BN_rshift failed"); | |
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); } | |
"%file: ./bugs.txt" | |
Known bugs: | |
- Window flickers when blocks are added (problem with repainting?) | |
"%file: ./build-msw.txt" | |
Bitcoin v0.2.0 BETA | |
Copyright (c) 2009-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. | |
This product includes software developed by the OpenSSL Project for use in | |
the OpenSSL Toolkit (http://www.openssl.org/). This product includes | |
cryptographic software written by Eric Young (eay@cryptsoft.com). | |
WINDOWS BUILD NOTES | |
=================== | |
Compilers Supported | |
------------------- | |
MinGW GCC (recommended) | |
MSVC 6.0 SP6: You'll need Boost version 1.34 because they dropped support | |
for MSVC 6.0 after that. However, they didn't add Asio until 1.35. | |
You should still be able to build with MSVC 6.0 by adding Asio to 1.34 by | |
unpacking boost_asio_*.zip into the boost directory: | |
http://sourceforge.net/projects/asio/files/asio | |
MSVC 8.0 (2005) SP1 has been tested. Note: MSVC 7.0 and up have a habit of | |
linking to runtime DLLs that are not installed on XP by default. | |
Dependencies | |
------------ | |
Libraries you need to download separately and build: | |
default path download | |
wxWidgets-2.9 \wxwidgets http://www.wxwidgets.org/downloads/ | |
OpenSSL \openssl http://www.openssl.org/source/ | |
Berkeley DB \db http://www.oracle.com/technology/software/products/berkeley-db/index.html | |
Boost \boost http://www.boost.org/users/download/ | |
Their licenses: | |
wxWidgets LGPL 2.1 with very liberal exceptions | |
OpenSSL Old BSD license with the problematic advertising requirement | |
Berkeley DB New BSD license with additional requirement that linked software must be free open source | |
Boost MIT-like license | |
Versions used in this release: | |
MinGW GCC 3.4.5 | |
wxWidgets 2.9.0 | |
OpenSSL 0.9.8k | |
Berkeley DB 4.7.25.NC | |
Boost 1.42.1 | |
Notes | |
----- | |
The UI layout is edited with wxFormBuilder. The project file is | |
uiproject.fbp. It generates uibase.cpp and uibase.h, which define base | |
classes that do the rote work of constructing all the UI elements. | |
The release is built with GCC and then "strip bitcoin.exe" to strip the debug | |
symbols, which reduces the executable size by about 90%. | |
wxWidgets | |
--------- | |
cd \wxwidgets\build\msw | |
make -f makefile.gcc | |
or | |
nmake -f makefile.vc | |
OpenSSL | |
------- | |
Bitcoin does not use any encryption. If you want to do a no-everything | |
build of OpenSSL to exclude encryption routines, a few patches are required. | |
(instructions for OpenSSL v0.9.8k) | |
Edit engines\e_gmp.c and engines\e_capi.c and add this #ifndef around | |
the openssl/rsa.h include: | |
#ifndef OPENSSL_NO_RSA | |
#include <openssl/rsa.h> | |
#endif | |
Edit ms\mingw32.bat and replace the Configure line's parameters with this | |
no-everything list. You have to put this in the batch file because batch | |
files can't take more than nine command line parameters. | |
perl Configure mingw threads no-rc2 no-rc4 no-rc5 no-idea no-des no-bf no-cast no-aes no-camellia no-seed no-rsa no-dh | |
Also REM out the following line in ms\mingw32.bat after the mingw32-make | |
line. The build fails after it's already finished building libeay32, which | |
is all we care about, but the failure aborts the script before it runs | |
dllwrap to generate libeay32.dll. | |
REM if errorlevel 1 goto end | |
Build | |
cd \openssl | |
ms\mingw32.bat | |
If you want to use it with MSVC, generate the .lib file | |
lib /machine:i386 /def:ms\libeay32.def /out:out\libeay32.lib | |
Berkeley DB | |
----------- | |
Using MinGW and MSYS: | |
cd \db\build_unix | |
sh ../dist/configure --enable-mingw --enable-cxx | |
make | |
Boost | |
----- | |
download bjam.exe from | |
http://sourceforge.net/project/showfiles.php?group_id=7586&package_id=72941 | |
cd \boost | |
bjam toolset=gcc --build-type=complete stage | |
or | |
bjam toolset=msvc --build-type=complete stage | |
"%file: ./build-osx.txt" | |
Mac OS X build instructions | |
Laszlo Hanyecz (solar@heliacal.net) | |
Tested on 10.5 and 10.6 intel. PPC is not supported because it's big-endian. | |
All of the commands should be executed in Terminal.app.. it's in | |
/Applications/Utilities | |
You need to install XCode with all the options checked so that the compiler | |
and everything is available in /usr not just /Developer | |
I think it comes on the DVD but you can get the current version from | |
http://developer.apple.com | |
1. Pick a directory to work inside.. something like ~/bitcoin works. The | |
structure I use looks like this: | |
(~ is your home directory) | |
~/bitcoin | |
~/bitcoin/trunk # source code | |
~/bitcoin/deps # dependencies.. like libraries and headers needed to compile | |
~/bitcoin/Bitcoin.app # the application bundle where you can run the app | |
Just execute: mkdir ~/bitcoin | |
This will create the top dir for you.. | |
WARNING: do not use the ~ notation with the configure scripts.. use the full | |
name of the directory, for example /Users/james/bitcoin/deps for a user named | |
'james'. In my examples I am using 'macosuser' so make sure you change that. | |
2. Check out the trunk version of the bitcoin code from subversion: | |
cd ~/bitcoin | |
svn checkout https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk | |
This will make ~/bitcoin/trunk for you with all the files from subversion. | |
3. Get and build the dependencies | |
Boost | |
----- | |
Download from http://www.boost.org/users/download/ | |
I'm assuming it ended up in ~/Downloads.. | |
mkdir ~/bitcoin/deps | |
cd ~/bitcoin/deps | |
tar xvjf ~/Downloads/boost_1_42_0.tar.bz2 | |
cd boost_1_42_0 | |
./bootstrap.sh | |
./bjam architecture=combined address-model=32_64 macosx-version=10.6 macosx-version-min=10.5 link=static runtime-link=static --toolset=darwin --prefix=/Users/macosuser/bitcoin/deps install | |
This part takes a while.. use your judgement and fix it if something doesn't | |
build for some reason. | |
Change the prefix to whatever your directory is (my username in this example | |
is macosuser). I'm also running on 10.6 so i have macosx-version=10.6 change | |
to 10.5 if you're using leopard. | |
This is what my output looked like at the end: | |
...failed updating 2 targets... | |
...skipped 144 targets... | |
...updated 8074 targets... | |
OpenSSL | |
------- | |
Download from http://www.openssl.org/source/ | |
We would like to build this as a 32 bit/64 bit library so we actually build it | |
2 times and join it together here.. If you downloaded with safari it already | |
uncompressed it so it will just be a tar not a tar.gz | |
cd ~/bitcoin/deps | |
tar xvf ~/Downloads/openssl-1.0.0.tar | |
mv openssl-1.0.0 openssl-1.0.0-i386 | |
tar xvf ~/Downloads/openssl-1.0.0.tar | |
mv openssl-1.0.0 openssl-1.0.0-x86_64 | |
# build i386 (32 bit intel) binary | |
cd openssl-1.0.0-i386 | |
./Configure --prefix=/Users/macosuser/bitcoin/deps --openssldir=/Users/macosuser/deps/openssl darwin-i386-cc && make | |
make install # only do this on one of the architectures, to install the headers | |
cd .. | |
# build x86_64 (64 bit intel) binary | |
cd openssl-1.0.0-x86_64 | |
./Configure --prefix=/Users/macosuser/bitcoin/deps --openssldir=/Users/macosuser/deps/openssl darwin64-x86_64-cc && make | |
cd .. | |
# combine the libs | |
cd ~/bitcoin/deps | |
lipo -arch i386 openssl-1.0.0-i386/libcrypto.a -arch x86_64 openssl-1.0.0-x86_64/libcrypto.a -o lib/libcrypto.a -create | |
lipo -arch i386 openssl-1.0.0-i386/libssl.a -arch x86_64 openssl-1.0.0-x86_64/libssl.a -o lib/libssl.a -create | |
Verify your binaries | |
file lib/libcrypto.a | |
output should look like this: | |
ib/libcrypto.a: Mach-O universal binary with 2 architectures | |
lib/libcrypto.a (for architecture i386): current ar archive random library | |
lib/libcrypto.a (for architecture x86_64): current ar archive random library | |
Berkeley DB | |
----------- | |
Download from http://freshmeat.net/projects/berkeleydb/ | |
cd ~/bitcoin/deps | |
tar xvf ~/Downloads/db-4.8.26.tar | |
cd db-4.8.26/build_unix | |
../dist/configure --prefix=/Users/macosuser/bitcoin/deps --enable-cxx && make && make install | |
wxWidgets | |
--------- | |
This is the big one.. | |
Check it out from svn | |
cd ~/bitcoin/deps | |
svn checkout http://svn.wxwidgets.org/svn/wx/wxWidgets/trunk wxWidgets-trunk | |
This will make a wxWidgets-trunk directory in deps. | |
Use this script snippet, change your prefix to whatever your dir is: | |
PREFIX=~/bitcoin/deps | |
SRCDIR="$PREFIX/wxWidgets-trunk" | |
BUILDDIR="$SRCDIR/macbuild" | |
cd "$PREFIX" && | |
#svn checkout http://svn.wxwidgets.org/svn/wx/wxWidgets/trunk wxWidgets-trunk && | |
cd "$SRCDIR" && | |
[ -f include/wx/hashmap.h.orig ] || cp include/wx/hashmap.h include/wx/hashmap.h.orig && | |
sed 's/if wxUSE_STL/if 0 \&\& wxUSE_STL/g' < include/wx/hashmap.h.orig > include/wx/hashmap.h && | |
[ -f include/wx/hashset.h.orig ] || cp include/wx/hashset.h include/wx/hashset.h.orig && | |
sed 's/if wxUSE_STL/if 0 \&\& wxUSE_STL/g' < include/wx/hashset.h.orig > include/wx/hashset.h && | |
rm -vrf "$BUILDDIR" && | |
mkdir "$BUILDDIR" && | |
cd "$BUILDDIR" && | |
../configure --prefix="$PREFIX" \ | |
--with-osx_cocoa \ | |
--disable-shared \ | |
--disable-debug_flag \ | |
--with-macosx-version-min=10.5 \ | |
--enable-stl \ | |
--enable-utf8 \ | |
--enable-universal_binary \ | |
--with-libjpeg=builtin \ | |
--with-libpng=builtin \ | |
--with-regex=builtin \ | |
--with-libtiff=builtin \ | |
--with-zlib=builtin \ | |
--with-expat=builtin \ | |
--with-macosx-sdk=/Developer/SDKs/MacOSX10.5.sdk && | |
find . -name Makefile | | |
while read i; do | |
echo $i; | |
sed 's/-arch i386/-arch i386 -arch x86_64/g' < "$i" > "$i".new && | |
mv "$i" "$i".old && | |
mv "$i".new "$i"; | |
done | |
make && | |
make install | |
Now you should be able to build bitcoin | |
cd ~/bitcoin/trunk | |
make -f makefile.osx bitcoin | |
Before you can run it, you need to create an application bundle for Mac OS. | |
Create the directories in terminal using mkdir and copy the files into place. | |
They are available at http://heliacal.net/~solar/bitcoin/mac-build/ | |
You need the Info.plist and the .ins file. The Contents/MacOS/bitcoin file is | |
the output of the build. | |
Your directory structure should look like this: | |
Bitcoin.app | |
Bitcoin.app/Contents | |
Bitcoin.app/Contents/Info.plist | |
Bitcoin.app/Contents/MacOS | |
Bitcoin.app/Contents/MacOS/bitcoin | |
Bitcoin.app/Contents/Resources | |
Bitcoin.app/Contents/Resources/BitcoinAppIcon.icns | |
To run it you can just click the Bitcoin.app in Finder, or just do open | |
~/bitcoin/Bitcoin.app | |
If you want to run it with arguments you can just run it without backgrounding | |
by specifying the full name in terminal: | |
~/bitcoin/Bitcoin.app/Contents/MacOS/bitcoin -addnode=192.75.207.66 | |
"%file: ./build-unix.txt" | |
Bitcoin v0.2.0 BETA | |
Copyright (c) 2009-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. | |
This product includes software developed by the OpenSSL Project for use in | |
the OpenSSL Toolkit (http://www.openssl.org/). This product includes | |
cryptographic software written by Eric Young (eay@cryptsoft.com). | |
UNIX BUILD NOTES | |
================ | |
Dependencies | |
------------ | |
sudo apt-get install build-essential | |
sudo apt-get install libgtk2.0-dev | |
sudo apt-get install libssl-dev | |
sudo apt-get install libdb4.7-dev | |
sudo apt-get install libdb4.7++-dev | |
sudo apt-get install libboost-dev | |
We're now using wxWidgets 2.9, which uses UTF-8. | |
There isn't currently a debian package of wxWidgets we can use. The 2.8 | |
packages for Karmic are UTF-16 unicode and won't work for us, and we've had | |
trouble building 2.8 on 64-bit. | |
You need to download wxWidgets from http://www.wxwidgets.org/downloads/ | |
and build it yourself. See the build instructions and configure parameters | |
below. | |
Licenses of statically linked libraries: | |
wxWidgets LGPL 2.1 with very liberal exceptions | |
Berkeley DB New BSD license with additional requirement that linked software must be free open source | |
Boost MIT-like license | |
Versions used in this release: | |
GCC 4.3.3 | |
OpenSSL 0.9.8k | |
wxWidgets 2.9.0 | |
Berkeley DB 4.7.25.NC | |
Boost 1.38.0 | |
Notes | |
----- | |
The UI layout is edited with wxFormBuilder. The project file is | |
uiproject.fbp. It generates uibase.cpp and uibase.h, which define base | |
classes that do the rote work of constructing all the UI elements. | |
The release is built with GCC and then "strip bitcoin" to strip the debug | |
symbols, which reduces the executable size by about 90%. | |
wxWidgets | |
--------- | |
cd /usr/local | |
tar -xzvf wxWidgets-2.9.0.tar.gz | |
cd /usr/local/wxWidgets-2.9.0 | |
mkdir buildgtk | |
cd buildgtk | |
../configure --with-gtk --enable-debug --disable-shared --enable-monolithic | |
make | |
sudo su | |
make install | |
ldconfig | |
Boost | |
----- | |
If you want to build Boost yourself, | |
cd /usr/local/boost_1_38_0 | |
su | |
./bootstrap.sh | |
./bjam install | |
"%file: ./changelog.txt" | |
Changes after 0.1.5: | |
-------------------- | |
+ Options dialog layout changed - added the UI options panel | |
+ Minimize to tray feature | |
+ Startup on system boot feature | |
+ Ask before closing | |
+ NSIS installer | |
"%file: ./db.h" | |
// Copyright (c) 2009-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. | |
class CTransaction; | |
class CTxIndex; | |
class CDiskBlockIndex; | |
class CDiskTxPos; | |
class COutPoint; | |
class CUser; | |
class CReview; | |
class CAddress; | |
class CWalletTx; | |
extern map<string, string> mapAddressBook; | |
extern CCriticalSection cs_mapAddressBook; | |
extern vector<unsigned char> vchDefaultKey; | |
extern bool fClient; | |
extern unsigned int nWalletDBUpdated; | |
extern DbEnv dbenv; | |
extern void DBFlush(bool fShutdown); | |
class CDB | |
{ | |
protected: | |
Db* pdb; | |
string strFile; | |
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", false)); | |
// 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", false)); | |
// 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, 0); | |
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(string("version"), nVersion); | |
} | |
bool WriteVersion(int nVersion) | |
{ | |
return Write(string("version"), nVersion); | |
} | |
}; | |
class CTxDB : public CDB | |
{ | |
public: | |
CTxDB(const char* pszMode="r+") : CDB(!fClient ? "blkindex.dat" : NULL, 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, 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 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 LoadAddresses(); | |
}; | |
bool LoadAddresses(); | |
class CWalletDB : public CDB | |
{ | |
public: | |
CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode) { } | |
private: | |
CWalletDB(const CWalletDB&); | |
void operator=(const CWalletDB&); | |
public: | |
bool ReadName(const string& strAddress, string& strName) | |
{ | |
strName = ""; | |
return Read(make_pair(string("name"), strAddress), strName); | |
} | |
bool WriteName(const string& strAddress, const string& strName) | |
{ | |
CRITICAL_BLOCK(cs_mapAddressBook) | |
mapAddressBook[strAddress] = strName; | |
nWalletDBUpdated++; | |
return Write(make_pair(string("name"), strAddress), strName); | |
} | |
bool 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. | |
CRITICAL_BLOCK(cs_mapAddressBook) | |
mapAddressBook.erase(strAddress); | |
nWalletDBUpdated++; | |
return Erase(make_pair(string("name"), strAddress)); | |
} | |
bool ReadTx(uint256 hash, CWalletTx& wtx) | |
{ | |
return Read(make_pair(string("tx"), hash), wtx); | |
} | |
bool WriteTx(uint256 hash, const CWalletTx& wtx) | |
{ | |
nWalletDBUpdated++; | |
return Write(make_pair(string("tx"), hash), wtx); | |
} | |
bool EraseTx(uint256 hash) | |
{ | |
nWalletDBUpdated++; | |
return Erase(make_pair(string("tx"), hash)); | |
} | |
bool ReadKey(const vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey) | |
{ | |
vchPrivKey.clear(); | |
return Read(make_pair(string("key"), vchPubKey), vchPrivKey); | |
} | |
bool WriteKey(const vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey) | |
{ | |
nWalletDBUpdated++; | |
return Write(make_pair(string("key"), vchPubKey), vchPrivKey, false); | |
} | |
bool ReadDefaultKey(vector<unsigned char>& vchPubKey) | |
{ | |
vchPubKey.clear(); | |
return Read(string("defaultkey"), vchPubKey); | |
} | |
bool WriteDefaultKey(const vector<unsigned char>& vchPubKey) | |
{ | |
vchDefaultKey = vchPubKey; | |
nWalletDBUpdated++; | |
return Write(string("defaultkey"), vchPubKey); | |
} | |
template<typename T> | |
bool ReadSetting(const string& strKey, T& value) | |
{ | |
return Read(make_pair(string("setting"), strKey), value); | |
} | |
template<typename T> | |
bool WriteSetting(const string& strKey, const T& value) | |
{ | |
nWalletDBUpdated++; | |
return Write(make_pair(string("setting"), strKey), value); | |
} | |
bool LoadWallet(); | |
}; | |
bool LoadWallet(bool& fFirstRunRet); | |
inline bool SetAddressBookName(const string& strAddress, const string& strName) | |
{ | |
return CWalletDB().WriteName(strAddress, strName); | |
} | |
"%file: ./db.cpp" | |
// Copyright (c) 2009-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. | |
#include "headers.h" | |
void ThreadFlushWalletDB(void* parg); | |
unsigned int nWalletDBUpdated; | |
// | |
// CDB | |
// | |
static CCriticalSection cs_db; | |
static bool fDbEnvInit = false; | |
DbEnv dbenv(0); | |
static map<string, int> mapFileUseCount; | |
static map<string, Db*> mapDb; | |
class CDBInit | |
{ | |
public: | |
CDBInit() | |
{ | |
} | |
~CDBInit() | |
{ | |
if (fDbEnvInit) | |
{ | |
dbenv.close(0); | |
fDbEnvInit = false; | |
} | |
} | |
} | |
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"; | |
_mkdir(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_PRIVATE | | |
DB_RECOVER, | |
S_IRUSR | S_IWUSR); | |
if (ret > 0) | |
throw runtime_error(strprintf("CDB() : error %d opening database environment\n", 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\n", pszFile, ret)); | |
} | |
if (fCreate && !Exists(string("version"))) | |
{ | |
bool fTmp = fReadOnly; | |
fReadOnly = false; | |
WriteVersion(VERSION); | |
fReadOnly = fTmp; | |
} | |
mapDb[strFile] = pdb; | |
} | |
} | |
} | |
void CDB::Close() | |
{ | |
if (!pdb) | |
return; | |
if (!vTxn.empty()) | |
vTxn.front()->abort(); | |
vTxn.clear(); | |
pdb = NULL; | |
dbenv.txn_checkpoint(0, 0, 0); | |
CRITICAL_BLOCK(cs_db) | |
--mapFileUseCount[strFile]; | |
} | |
void 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; | |
} | |
} | |
} | |
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); | |
dbenv.close(0); | |
fDbEnvInit = false; | |
} | |
} | |
} | |
// | |
// 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); | |
} | |
CBlockIndex* 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 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 << 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 and best block | |
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) | |
pindexGenesisBlock = pindexNew; | |
} | |
else | |
{ | |
break; | |
} | |
} | |
pcursor->close(); | |
if (!ReadHashBestChain(hashBestChain)) | |
{ | |
if (pindexGenesisBlock == NULL) | |
return true; | |
return error("CTxDB::LoadBlockIndex() : hashBestChain not found"); | |
} | |
if (!mapBlockIndex.count(hashBestChain)) | |
return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found"); | |
pindexBest = mapBlockIndex[hashBestChain]; | |
nBestHeight = pindexBest->nHeight; | |
printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight); | |
return true; | |
} | |
// | |
// CAddrDB | |
// | |
bool CAddrDB::WriteAddress(const CAddress& addr) | |
{ | |
return Write(make_pair(string("addr"), addr.GetKey()), addr); | |
} | |
bool CAddrDB::LoadAddresses() | |
{ | |
CRITICAL_BLOCK(cs_mapAddresses) | |
{ | |
// Load user provided addresses | |
CAutoFile filein = fopen((GetDataDir() + "/addr.txt").c_str(), "rt"); | |
if (filein) | |
{ | |
try | |
{ | |
char psz[1000]; | |
while (fgets(psz, sizeof(psz), filein)) | |
{ | |
CAddress addr(psz, NODE_NETWORK); | |
addr.nTime = 0; // so it won't relay unless successfully connected | |
if (addr.IsValid()) | |
AddAddress(addr); | |
} | |
} | |
catch (...) { } | |
} | |
// 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()); | |
// Fix for possible bug that manifests in mapAddresses.count in irc.cpp, | |
// just need to call count here and it doesn't happen there. The bug was the | |
// pack pragma in irc.cpp and has been fixed, but I'm not in a hurry to delete this. | |
mapAddresses.count(vector<unsigned char>(18)); | |
} | |
return true; | |
} | |
bool LoadAddresses() | |
{ | |
return CAddrDB("cr+").LoadAddresses(); | |
} | |
// | |
// CWalletDB | |
// | |
bool CWalletDB::LoadWallet() | |
{ | |
vchDefaultKey.clear(); | |
int nFileVersion = 0; | |
// Modify defaults | |
#ifndef __WXMSW__ | |
// 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(cs_mapKeys) | |
CRITICAL_BLOCK(cs_mapWallet) | |
{ | |
// 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 | |
// 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 >> mapAddressBook[strAddress]; | |
} | |
else if (strType == "tx") | |
{ | |
uint256 hash; | |
ssKey >> hash; | |
CWalletTx& wtx = mapWallet[hash]; | |
ssValue >> wtx; | |
if (wtx.GetHash() != hash) | |
printf("Error in wallet.dat, hash mismatch\n"); | |
//// 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.nTime).c_str(), | |
// wtx.hashBlock.ToString().substr(0,16).c_str(), | |
// wtx.mapValue["message"].c_str()); | |
} | |
else if (strType == "key" || strType == "wkey") | |
{ | |
vector<unsigned char> vchPubKey; | |
ssKey >> vchPubKey; | |
CWalletKey wkey; | |
if (strType == "key") | |
ssValue >> wkey.vchPrivKey; | |
else | |
ssValue >> wkey; | |
mapKeys[vchPubKey] = wkey.vchPrivKey; | |
mapPubKeys[Hash160(vchPubKey)] = vchPubKey; | |
} | |
else if (strType == "defaultkey") | |
{ | |
ssValue >> vchDefaultKey; | |
} | |
else if (strType == "version") | |
{ | |
ssValue >> nFileVersion; | |
} | |
else if (strType == "setting") | |
{ | |
string strKey; | |
ssKey >> strKey; | |
// Menu state | |
if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins; | |
// Options | |
if (strKey == "nTransactionFee") ssValue >> nTransactionFee; | |
if (strKey == "addrIncoming") ssValue >> addrIncoming; | |
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; | |
} | |
} | |
pcursor->close(); | |
} | |
printf("nFileVersion = %d\n", nFileVersion); | |
printf("fGenerateBitcoins = %d\n", fGenerateBitcoins); | |
printf("nTransactionFee = %"PRI64d"\n", nTransactionFee); | |
printf("addrIncoming = %s\n", addrIncoming.ToString().c_str()); | |
printf("fMinimizeToTray = %d\n", fMinimizeToTray); | |
printf("fMinimizeOnClose = %d\n", fMinimizeOnClose); | |
printf("fUseProxy = %d\n", fUseProxy); | |
printf("addrProxy = %s\n", addrProxy.ToString().c_str()); | |
// The transaction fee setting won't be needed for many years to come. | |
// Setting it to zero here in case they set it to something in an earlier version. | |
if (nTransactionFee != 0) | |
{ | |
nTransactionFee = 0; | |
WriteSetting("nTransactionFee", nTransactionFee); | |
} | |
// Upgrade | |
if (nFileVersion < VERSION) | |
{ | |
// Get rid of old debug.log file in current directory | |
if (nFileVersion <= 105 && !pszSetDataDir[0]) | |
unlink("debug.log"); | |
WriteVersion(VERSION); | |
} | |
return true; | |
} | |
bool LoadWallet(bool& fFirstRunRet) | |
{ | |
fFirstRunRet = false; | |
if (!CWalletDB("cr+").LoadWallet()) | |
return false; | |
fFirstRunRet = vchDefaultKey.empty(); | |
if (mapKeys.count(vchDefaultKey)) | |
{ | |
// Set keyUser | |
keyUser.SetPubKey(vchDefaultKey); | |
keyUser.SetPrivKey(mapKeys[vchDefaultKey]); | |
} | |
else | |
{ | |
// Create new keyUser and set as default key | |
RandAddSeedPerfmon(); | |
keyUser.MakeNewKey(); | |
if (!AddKey(keyUser)) | |
return false; | |
if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), "Your Address")) | |
return false; | |
CWalletDB().WriteDefaultKey(keyUser.GetPubKey()); | |
} | |
CreateThread(ThreadFlushWalletDB, NULL); | |
return true; | |
} | |
void ThreadFlushWalletDB(void* parg) | |
{ | |
static bool fOneThread; | |
if (fOneThread) | |
return; | |
fOneThread = true; | |
if (mapArgs.count("-noflushwallet")) | |
return; | |
unsigned int nLastSeen = nWalletDBUpdated; | |
unsigned int nLastFlushed = nWalletDBUpdated; | |
int64 nLastWalletUpdate = GetTime(); | |
while (!fShutdown) | |
{ | |
Sleep(500); | |
if (nLastSeen != nWalletDBUpdated) | |
{ | |
nLastSeen = nWalletDBUpdated; | |
nLastWalletUpdate = GetTime(); | |
} | |
if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2) | |
{ | |
TRY_CRITICAL_BLOCK(cs_db) | |
{ | |
// Don't do this if any databases are in use | |
int nRefCount = 0; | |
map<string, int>::iterator mi = mapFileUseCount.begin(); | |
while (mi != mapFileUseCount.end()) | |
{ | |
nRefCount += (*mi).second; | |
mi++; | |
} | |
if (nRefCount == 0 && !fShutdown) | |
{ | |
string strFile = "wallet.dat"; | |
map<string, int>::iterator mi = mapFileUseCount.find(strFile); | |
if (mi != mapFileUseCount.end()) | |
{ | |
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); | |
printf("Flushing wallet.dat\n"); | |
nLastFlushed = nWalletDBUpdated; | |
int64 nStart = GetTimeMillis(); | |
// Flush wallet.dat so it's self contained | |
CloseDb(strFile); | |
dbenv.txn_checkpoint(0, 0, 0); | |
dbenv.lsn_reset(strFile.c_str(), 0); | |
mapFileUseCount.erase(mi++); | |
printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart); | |
} | |
} | |
} | |
} | |
} | |
} | |
"%file: ./headers.h" | |
// Copyright (c) 2009-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. | |
#ifdef _MSC_VER | |
#pragma warning(disable:4786) | |
#pragma warning(disable:4804) | |
#pragma warning(disable:4805) | |
#pragma warning(disable:4717) | |
#endif | |
#ifdef _WIN32_WINNT | |
#undef _WIN32_WINNT | |
#endif | |
#define _WIN32_WINNT 0x0400 | |
#ifdef _WIN32_IE | |
#undef _WIN32_IE | |
#endif | |
#define _WIN32_IE 0x0400 | |
#define WIN32_LEAN_AND_MEAN 1 | |
#define __STDC_LIMIT_MACROS // to enable UINT64_MAX from stdint.h | |
#include <wx/wx.h> | |
#include <wx/stdpaths.h> | |
#include <wx/snglinst.h> | |
#if wxUSE_GUI | |
#include <wx/utils.h> | |
#include <wx/clipbrd.h> | |
#include <wx/taskbar.h> | |
#endif | |
#include <openssl/ecdsa.h> | |
#include <openssl/evp.h> | |
#include <openssl/rand.h> | |
#include <openssl/sha.h> | |
#include <openssl/ripemd.h> | |
#include <db_cxx.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
#include <limits.h> | |
#include <float.h> | |
#include <assert.h> | |
#include <memory> | |
#include <iostream> | |
#include <sstream> | |
#include <string> | |
#include <vector> | |
#include <list> | |
#include <deque> | |
#include <map> | |
#include <set> | |
#include <algorithm> | |
#include <numeric> | |
#include <boost/foreach.hpp> | |
#include <boost/lexical_cast.hpp> | |
#include <boost/tuple/tuple.hpp> | |
#include <boost/tuple/tuple_comparison.hpp> | |
#include <boost/tuple/tuple_io.hpp> | |
#include <boost/array.hpp> | |
#include <boost/bind.hpp> | |
#include <boost/function.hpp> | |
#include <boost/filesystem.hpp> | |
#include <boost/algorithm/string.hpp> | |
#ifdef __WXMSW__ | |
#include <windows.h> | |
#include <winsock2.h> | |
#include <mswsock.h> | |
#include <shlobj.h> | |
#include <shlwapi.h> | |
#include <io.h> | |
#include <process.h> | |
#include <malloc.h> | |
#else | |
#include <sys/time.h> | |
#include <sys/resource.h> | |
#include <sys/socket.h> | |
#include <arpa/inet.h> | |
#include <netdb.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <net/if.h> | |
#include <ifaddrs.h> | |
#endif | |
#ifdef __BSD__ | |
#include <netinet/in.h> | |
#endif | |
#pragma hdrstop | |
using namespace std; | |
using namespace boost; | |
#include "strlcpy.h" | |
#include "serialize.h" | |
#include "uint256.h" | |
#include "util.h" | |
#include "key.h" | |
#include "bignum.h" | |
#include "base58.h" | |
#include "script.h" | |
#include "db.h" | |
#include "net.h" | |
#include "irc.h" | |
#include "main.h" | |
#include "rpc.h" | |
#if wxUSE_GUI | |
#include "uibase.h" | |
#endif | |
#include "ui.h" | |
#include "init.h" | |
#include "xpm/addressbook16.xpm" | |
#include "xpm/addressbook20.xpm" | |
#include "xpm/bitcoin16.xpm" | |
#include "xpm/bitcoin20.xpm" | |
#include "xpm/bitcoin32.xpm" | |
#include "xpm/bitcoin48.xpm" | |
#include "xpm/check.xpm" | |
#include "xpm/send16.xpm" | |
#include "xpm/send16noshadow.xpm" | |
#include "xpm/send20.xpm" | |
#include "xpm/about.xpm" | |
"%file: ./init.h" | |
// Copyright (c) 2009-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. | |
void Shutdown(void* parg); | |
bool GetStartOnSystemStartup(); | |
void SetStartOnSystemStartup(bool fAutoStart); | |
"%file: ./init.cpp" | |
// Copyright (c) 2009-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. | |
#include "headers.h" | |
void ExitTimeout(void* parg) | |
{ | |
#ifdef __WXMSW__ | |
Sleep(5000); | |
ExitProcess(0); | |
#endif | |
} | |
void Shutdown(void* parg) | |
{ | |
static CCriticalSection cs_Shutdown; | |
static bool fTaken; | |
bool fFirstThread; | |
CRITICAL_BLOCK(cs_Shutdown) | |
{ | |
fFirstThread = !fTaken; | |
fTaken = true; | |
} | |
static bool fExit; | |
if (fFirstThread) | |
{ | |
fShutdown = true; | |
nTransactionsUpdated++; | |
DBFlush(false); | |
StopNode(); | |
DBFlush(true); | |
CreateThread(ExitTimeout, NULL); | |
Sleep(50); | |
printf("Bitcoin exiting\n\n"); | |
fExit = true; | |
exit(0); | |
} | |
else | |
{ | |
while (!fExit) | |
Sleep(500); | |
Sleep(100); | |
ExitThread(0); | |
} | |
} | |
////////////////////////////////////////////////////////////////////////////// | |
// | |
// Startup folder | |
// | |
#ifdef __WXMSW__ | |
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 is not usually available on NT 4.0 | |
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; | |
} | |
string StartupShortcutPath() | |
{ | |
return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk"; | |
} | |
bool GetStartOnSystemStartup() | |
{ | |
return wxFileExists(StartupShortcutPath()); | |
} | |
void 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)); | |
// Set the path to the shortcut target | |
psl->SetPath(pszExePath); | |
PathRemoveFileSpec(pszExePath); | |
psl->SetWorkingDirectory(pszExePath); | |
psl->SetShowCmd(SW_SHOWMINNOACTIVE); | |
// 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(); | |
} | |
} | |
#else | |
bool GetStartOnSystemStartup() { return false; } | |
void SetStartOnSystemStartup(bool fAutoStart) { } | |
#endif | |
////////////////////////////////////////////////////////////////////////////// | |
// | |
// CMyApp | |
// | |
// Define a new application | |
class CMyApp: public wxApp | |
{ | |
public: | |
wxLocale m_locale; | |
CMyApp(){}; | |
~CMyApp(){}; | |
bool OnInit(); | |
bool OnInit2(); | |
int OnExit(); | |
// Hook Initialize so we can start without GUI | |
virtual bool Initialize(int& argc, wxChar** argv); | |
// 2nd-level exception handling: we get all the exceptions occurring in any | |
// event handler here | |
virtual bool OnExceptionInMainLoop(); | |
// 3rd, and final, level exception handling: whenever an unhandled | |
// exception is caught, this function is called | |
virtual void OnUnhandledException(); | |
// and now for something different: this function is called in case of a | |
// crash (e.g. dereferencing null pointer, division by 0, ...) | |
virtual void OnFatalException(); | |
}; | |
IMPLEMENT_APP(CMyApp) | |
bool CMyApp::Initialize(int& argc, wxChar** argv) | |
{ | |
if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') && | |
wxString(argv[1]) != "start") | |
{ | |
fCommandLine = true; | |
} | |
else if (!fGUI) | |
{ | |
fDaemon = true; | |
} | |
else | |
{ | |
// wxApp::Initialize will remove environment-specific parameters, | |
// so it's too early to call ParseParameters yet | |
for (int i = 1; i < argc; i++) | |
{ | |
wxString str = argv[i]; | |
#ifdef __WXMSW__ | |
if (str.size() >= 1 && str[0] == '/') | |
str[0] = '-'; | |
str = str.MakeLower(); | |
#endif | |
// haven't decided which argument to use for this yet | |
if (str == "-daemon" || str == "-d" || str == "start") | |
fDaemon = true; | |
} | |
} | |
#ifdef __WXGTK__ | |
if (fDaemon || fCommandLine) | |
{ | |
// Call the original Initialize while suppressing error messages | |
// and ignoring failure. If unable to initialize GTK, it fails | |
// near the end so hopefully the last few things don't matter. | |
{ | |
wxLogNull logNo; | |
wxApp::Initialize(argc, argv); | |
} | |
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) | |
pthread_exit((void*)0); | |
} | |
return true; | |
} | |
#endif | |
return wxApp::Initialize(argc, argv); | |
} | |
bool CMyApp::OnInit() | |
{ | |
bool fRet = false; | |
try | |
{ | |
fRet = OnInit2(); | |
} | |
catch (std::exception& e) { | |
PrintException(&e, "OnInit()"); | |
} catch (...) { | |
PrintException(NULL, "OnInit()"); | |
} | |
if (!fRet) | |
Shutdown(NULL); | |
return fRet; | |
} | |
extern int g_isPainting; | |
bool CMyApp::OnInit2() | |
{ | |
#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 | |
#if defined(__WXMSW__) && defined(__WXDEBUG__) && wxUSE_GUI | |
// Disable malfunctioning wxWidgets debug assertion | |
g_isPainting = 10000; | |
#endif | |
#if wxUSE_GUI | |
wxImage::AddHandler(new wxPNGHandler); | |
#endif | |
#if defined(__WXMSW__ ) || defined(__WXMAC__) | |
SetAppName("Bitcoin"); | |
#else | |
SetAppName("bitcoin"); | |
#endif | |
#ifndef __WXMSW__ | |
umask(077); | |
#endif | |
#ifdef __WXMSW__ | |
#if wxUSE_UNICODE | |
// Hack to set wxConvLibc codepage to UTF-8 on Windows, | |
// may break if wxMBConv_win32 implementation in strconv.cpp changes. | |
class wxMBConv_win32 : public wxMBConv | |
{ | |
public: | |
long m_CodePage; | |
size_t m_minMBCharWidth; | |
}; | |
if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP) | |
((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8; | |
#endif | |
#endif | |
// Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file | |
m_locale.Init(wxLANGUAGE_DEFAULT, 0); | |
m_locale.AddCatalogLookupPathPrefix("locale"); | |
if (!fWindows) | |
{ | |
m_locale.AddCatalogLookupPathPrefix("/usr/share/locale"); | |
m_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale"); | |
} | |
m_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any | |
m_locale.AddCatalog("bitcoin"); | |
// | |
// Parameters | |
// | |
if (fCommandLine) | |
{ | |
int ret = CommandLineRPC(argc, argv); | |
exit(ret); | |
} | |
ParseParameters(argc, argv); | |
if (mapArgs.count("-?") || mapArgs.count("--help")) | |
{ | |
wxString strUsage = string() + | |
_("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" + | |
" bitcoin [options] \t" + "\n" + | |
" bitcoin [command] \t" + _("Send command to bitcoin running with -server or -daemon\n") + | |
" bitcoin [command] -? \t" + _("Get help for a command\n") + | |
" bitcoin help \t" + _("List commands\n") + | |
_("Options:\n") + | |
" -gen \t " + _("Generate coins\n") + | |
" -gen=0 \t " + _("Don't generate coins\n") + | |
" -min \t " + _("Start minimized\n") + | |
" -datadir=<dir> \t " + _("Specify data directory\n") + | |
" -proxy=<ip:port>\t " + _("Connect through socks4 proxy\n") + | |
" -addnode=<ip> \t " + _("Add a node to connect to\n") + | |
" -connect=<ip> \t " + _("Connect only to the specified node\n") + | |
" -server \t " + _("Accept command line and JSON-RPC commands\n") + | |
" -daemon \t " + _("Run in the background as a daemon and accept commands\n") + | |
" -? \t " + _("This help message\n"); | |
if (fWindows && fGUI) | |
{ | |
// Tabs make the columns line up in the message box | |
wxMessageBox(strUsage, "Bitcoin", wxOK); | |
} | |
else | |
{ | |
// Remove tabs | |
strUsage.Replace("\t", ""); | |
fprintf(stderr, "%s", ((string)strUsage).c_str()); | |
} | |
return false; | |
} | |
if (mapArgs.count("-datadir")) | |
strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir)); | |
if (mapArgs.count("-debug")) | |
fDebug = true; | |
if (mapArgs.count("-printtodebugger")) | |
fPrintToDebugger = true; | |
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 0.%d.%d%s beta, OS version %s\n", VERSION/100, VERSION%100, pszSubVer, ((string)wxGetOsDescription()).c_str()); | |
printf("System default language is %d %s\n", m_locale.GetSystemLanguage(), ((string)m_locale.GetSysName()).c_str()); | |
printf("Language file %s (%s)\n", (string("locale/") + (string)m_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)m_locale.GetLocale()).c_str()); | |
if (mapArgs.count("-loadblockindextest")) | |
{ | |
CTxDB txdb("r"); | |
txdb.LoadBlockIndex(); | |
PrintBlockTree(); | |
return false; | |
} | |
// | |
// Limit to single instance per user | |
// Required to protect the database files if we're going to keep deleting log.* | |
// | |
#ifdef __WXMSW__ | |
// todo: wxSingleInstanceChecker wasn't working on Linux, never deleted its lock file | |
// maybe should go by whether successfully bind port 8333 instead | |
wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH"); | |
for (int i = 0; i < strMutexName.size(); i++) | |
if (!isalnum(strMutexName[i])) | |
strMutexName[i] = '.'; | |
wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName); | |
if (psingleinstancechecker->IsAnotherRunning()) | |
{ | |
printf("Existing instance found\n"); | |
unsigned int nStart = GetTime(); | |
loop | |
{ | |
// TODO: find out how to do this in Linux, or replace with wxWidgets commands | |
// Show the previous instance and exit | |
HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin"); | |
if (hwndPrev) | |
{ | |
if (IsIconic(hwndPrev)) | |
ShowWindow(hwndPrev, SW_RESTORE); | |
SetForegroundWindow(hwndPrev); | |
return false; | |
} | |
if (GetTime() > nStart + 60) | |
return false; | |
// Resume this instance if the other exits | |
delete psingleinstancechecker; | |
Sleep(1000); | |
psingleinstancechecker = new wxSingleInstanceChecker(strMutexName); | |
if (!psingleinstancechecker->IsAnotherRunning()) | |
break; | |
} | |
} | |
#endif | |
// Bind to the port early so we can tell if another instance is already running. | |
// This is a backup to wxSingleInstanceChecker, which doesn't work on Linux. | |
string strErrors; | |
if (!BindListenPort(strErrors)) | |
{ | |
wxMessageBox(strErrors, "Bitcoin"); | |
return false; | |
} | |
// | |
// Load data files | |
// | |
if (fDaemon) | |
fprintf(stdout, "bitcoin server starting\n"); | |
strErrors = ""; | |
int64 nStart; | |
printf("Loading addresses...\n"); | |
nStart = GetTimeMillis(); | |
if (!LoadAddresses()) | |
strErrors += _("Error loading addr.dat \n"); | |
printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart); | |
printf("Loading block index...\n"); | |
nStart = GetTimeMillis(); | |
if (!LoadBlockIndex()) | |
strErrors += _("Error loading blkindex.dat \n"); | |
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); | |
printf("Loading wallet...\n"); | |
nStart = GetTimeMillis(); | |
bool fFirstRun; | |
if (!LoadWallet(fFirstRun)) | |
strErrors += _("Error loading wallet.dat \n"); | |
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); | |
printf("Done loading\n"); | |
//// debug print | |
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); | |
printf("nBestHeight = %d\n", nBestHeight); | |
printf("mapKeys.size() = %d\n", mapKeys.size()); | |
printf("mapPubKeys.size() = %d\n", mapPubKeys.size()); | |
printf("mapWallet.size() = %d\n", mapWallet.size()); | |
printf("mapAddressBook.size() = %d\n", mapAddressBook.size()); | |
if (!strErrors.empty()) | |
{ | |
wxMessageBox(strErrors, "Bitcoin"); | |
return false; | |
} | |
// Add wallet transactions that aren't already in a block to mapTransactions | |
ReacceptWalletTransactions(); | |
// | |
// Parameters | |
// | |
if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree")) | |
{ | |
PrintBlockTree(); | |
return false; | |
} | |
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; | |
} | |
if (mapArgs.count("-gen")) | |
{ | |
if (mapArgs["-gen"].empty()) | |
fGenerateBitcoins = true; | |
else | |
fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0); | |
} | |
if (mapArgs.count("-proxy")) | |
{ | |
fUseProxy = true; | |
addrProxy = CAddress(mapArgs["-proxy"]); | |
if (!addrProxy.IsValid()) | |
{ | |
wxMessageBox(_("Invalid -proxy address"), "Bitcoin"); | |
return false; | |
} | |
} | |
if (mapArgs.count("-addnode")) | |
{ | |
foreach(string strAddr, mapMultiArgs["-addnode"]) | |
{ | |
CAddress addr(strAddr, NODE_NETWORK); | |
addr.nTime = 0; // so it won't relay unless successfully connected | |
if (addr.IsValid()) | |
AddAddress(addr); | |
} | |
} | |
// | |
// Create the main window and start the node | |
// | |
if (!fDaemon) | |
CreateMainWindow(); | |
if (!CheckDiskSpace()) | |
return false; | |
RandAddSeedPerfmon(); | |
if (!CreateThread(StartNode, NULL)) | |
wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin"); | |
if (mapArgs.count("-server") || fDaemon) | |
CreateThread(ThreadRPCServer, NULL); | |
if (fFirstRun) | |
SetStartOnSystemStartup(true); | |
return true; | |
} | |
int CMyApp::OnExit() | |
{ | |
Shutdown(NULL); | |
return wxApp::OnExit(); | |
} | |
bool CMyApp::OnExceptionInMainLoop() | |
{ | |
try | |
{ | |
throw; | |
} | |
catch (std::exception& e) | |
{ | |
PrintException(&e, "CMyApp::OnExceptionInMainLoop()"); | |
wxLogWarning("Exception %s %s", typeid(e).name(), e.what()); | |
Sleep(1000); | |
throw; | |
} | |
catch (...) | |
{ | |
PrintException(NULL, "CMyApp::OnExceptionInMainLoop()"); | |
wxLogWarning("Unknown exception"); | |
Sleep(1000); | |
throw; | |
} | |
return true; | |
} | |
void CMyApp::OnUnhandledException() | |
{ | |
// this shows how we may let some exception propagate uncaught | |
try | |
{ | |
throw; | |
} | |
catch (std::exception& e) | |
{ | |
PrintException(&e, "CMyApp::OnUnhandledException()"); | |
wxLogWarning("Exception %s %s", typeid(e).name(), e.what()); | |
Sleep(1000); | |
throw; | |
} | |
catch (...) | |
{ | |
PrintException(NULL, "CMyApp::OnUnhandledException()"); | |
wxLogWarning("Unknown exception"); | |
Sleep(1000); | |
throw; | |
} | |
} | |
void CMyApp::OnFatalException() | |
{ | |
wxMessageBox(_("Program has crashed and will terminate. "), "Bitcoin", wxOK | wxICON_ERROR); | |
} | |
"%file: ./irc.h" | |
// Copyright (c) 2009-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. | |
bool RecvLine(SOCKET hSocket, string& strLine); | |
void ThreadIRCSeed(void* parg); | |
extern int nGotIRCAddresses; | |
"%file: ./irc.cpp" | |
// Copyright (c) 2009-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. | |
#include "headers.h" | |
int nGotIRCAddresses = 0; | |
#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, 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 (!strLine.empty()) | |
return true; | |
// socket closed | |
printf("IRC socket closed\n"); | |
return false; | |
} | |
else | |
{ | |
// socket error | |
int nErr = WSAGetLastError(); | |
if (nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) | |
{ | |
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) | |
{ | |
loop | |
{ | |
string strLine; | |
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; | |
} | |
} | |
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; | |
} | |
void ThreadIRCSeed(void* parg) | |
{ | |
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"); | |
if (!fTOR) | |
{ | |
struct hostent* phostent = gethostbyname("chat.freenode.net"); | |
if (phostent && phostent->h_addr_list && phostent->h_addr_list[0]) | |
addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(6667)); | |
} | |
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")) | |
{ | |
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); | |
Send(hSocket, "JOIN #bitcoin\r"); | |
Send(hSocket, "WHO #bitcoin\r"); | |
int64 nStart = GetTime(); | |
string strLine; | |
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() - 51 * 60; | |
if (AddAddress(addr)) | |
printf("IRC got new address\n"); | |
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 | |
"%file: ./json/json_spirit.h" | |
#ifndef JSON_SPIRIT | |
#define JSON_SPIRIT | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include "json_spirit_value.h" | |
#include "json_spirit_reader.h" | |
#include "json_spirit_writer.h" | |
#include "json_spirit_utils.h" | |
#endif | |
"%file: ./json/json_spirit_error_position.h" | |
#ifndef JSON_SPIRIT_ERROR_POSITION | |
#define JSON_SPIRIT_ERROR_POSITION | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include <string> | |
namespace json_spirit | |
{ | |
// An Error_position exception is thrown by the "read_or_throw" functions below on finding an error. | |
// Note the "read_or_throw" functions are around 3 times slower than the standard functions "read" | |
// functions that return a bool. | |
// | |
struct Error_position | |
{ | |
Error_position(); | |
Error_position( unsigned int line, unsigned int column, const std::string& reason ); | |
bool operator==( const Error_position& lhs ) const; | |
unsigned int line_; | |
unsigned int column_; | |
std::string reason_; | |
}; | |
inline Error_position::Error_position() | |
: line_( 0 ) | |
, column_( 0 ) | |
{ | |
} | |
inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason ) | |
: line_( line ) | |
, column_( column ) | |
, reason_( reason ) | |
{ | |
} | |
inline bool Error_position::operator==( const Error_position& lhs ) const | |
{ | |
if( this == &lhs ) return true; | |
return ( reason_ == lhs.reason_ ) && | |
( line_ == lhs.line_ ) && | |
( column_ == lhs.column_ ); | |
} | |
} | |
#endif | |
"%file: ./json/json_spirit_reader.h" | |
#ifndef JSON_SPIRIT_READER | |
#define JSON_SPIRIT_READER | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include "json_spirit_value.h" | |
#include "json_spirit_error_position.h" | |
#include <iostream> | |
namespace json_spirit | |
{ | |
// functions to reads a JSON values | |
bool read( const std::string& s, Value& value ); | |
bool read( std::istream& is, Value& value ); | |
bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); | |
void read_or_throw( const std::string& s, Value& value ); | |
void read_or_throw( std::istream& is, Value& value ); | |
void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); | |
#ifndef BOOST_NO_STD_WSTRING | |
bool read( const std::wstring& s, wValue& value ); | |
bool read( std::wistream& is, wValue& value ); | |
bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); | |
void read_or_throw( const std::wstring& s, wValue& value ); | |
void read_or_throw( std::wistream& is, wValue& value ); | |
void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); | |
#endif | |
bool read( const std::string& s, mValue& value ); | |
bool read( std::istream& is, mValue& value ); | |
bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); | |
void read_or_throw( const std::string& s, mValue& value ); | |
void read_or_throw( std::istream& is, mValue& value ); | |
void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); | |
#ifndef BOOST_NO_STD_WSTRING | |
bool read( const std::wstring& s, wmValue& value ); | |
bool read( std::wistream& is, wmValue& value ); | |
bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); | |
void read_or_throw( const std::wstring& s, wmValue& value ); | |
void read_or_throw( std::wistream& is, wmValue& value ); | |
void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); | |
#endif | |
} | |
#endif | |
"%file: ./json/json_spirit_reader.cpp" | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#include "json_spirit_reader.h" | |
#include "json_spirit_reader_template.h" | |
using namespace json_spirit; | |
bool json_spirit::read( const std::string& s, Value& value ) | |
{ | |
return read_string( s, value ); | |
} | |
void json_spirit::read_or_throw( const std::string& s, Value& value ) | |
{ | |
read_string_or_throw( s, value ); | |
} | |
bool json_spirit::read( std::istream& is, Value& value ) | |
{ | |
return read_stream( is, value ); | |
} | |
void json_spirit::read_or_throw( std::istream& is, Value& value ) | |
{ | |
read_stream_or_throw( is, value ); | |
} | |
bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) | |
{ | |
return read_range( begin, end, value ); | |
} | |
void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) | |
{ | |
begin = read_range_or_throw( begin, end, value ); | |
} | |
#ifndef BOOST_NO_STD_WSTRING | |
bool json_spirit::read( const std::wstring& s, wValue& value ) | |
{ | |
return read_string( s, value ); | |
} | |
void json_spirit::read_or_throw( const std::wstring& s, wValue& value ) | |
{ | |
read_string_or_throw( s, value ); | |
} | |
bool json_spirit::read( std::wistream& is, wValue& value ) | |
{ | |
return read_stream( is, value ); | |
} | |
void json_spirit::read_or_throw( std::wistream& is, wValue& value ) | |
{ | |
read_stream_or_throw( is, value ); | |
} | |
bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) | |
{ | |
return read_range( begin, end, value ); | |
} | |
void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) | |
{ | |
begin = read_range_or_throw( begin, end, value ); | |
} | |
#endif | |
bool json_spirit::read( const std::string& s, mValue& value ) | |
{ | |
return read_string( s, value ); | |
} | |
void json_spirit::read_or_throw( const std::string& s, mValue& value ) | |
{ | |
read_string_or_throw( s, value ); | |
} | |
bool json_spirit::read( std::istream& is, mValue& value ) | |
{ | |
return read_stream( is, value ); | |
} | |
void json_spirit::read_or_throw( std::istream& is, mValue& value ) | |
{ | |
read_stream_or_throw( is, value ); | |
} | |
bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) | |
{ | |
return read_range( begin, end, value ); | |
} | |
void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) | |
{ | |
begin = read_range_or_throw( begin, end, value ); | |
} | |
#ifndef BOOST_NO_STD_WSTRING | |
bool json_spirit::read( const std::wstring& s, wmValue& value ) | |
{ | |
return read_string( s, value ); | |
} | |
void json_spirit::read_or_throw( const std::wstring& s, wmValue& value ) | |
{ | |
read_string_or_throw( s, value ); | |
} | |
bool json_spirit::read( std::wistream& is, wmValue& value ) | |
{ | |
return read_stream( is, value ); | |
} | |
void json_spirit::read_or_throw( std::wistream& is, wmValue& value ) | |
{ | |
read_stream_or_throw( is, value ); | |
} | |
bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) | |
{ | |
return read_range( begin, end, value ); | |
} | |
void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) | |
{ | |
begin = read_range_or_throw( begin, end, value ); | |
} | |
#endif | |
"%file: ./json/json_spirit_reader_template.h" | |
#ifndef JSON_SPIRIT_READER_TEMPLATE | |
#define JSON_SPIRIT_READER_TEMPLATE | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#include "json_spirit_value.h" | |
#include "json_spirit_error_position.h" | |
//#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread | |
#include <boost/bind.hpp> | |
#include <boost/function.hpp> | |
#include <boost/version.hpp> | |
#if BOOST_VERSION >= 103800 | |
#include <boost/spirit/include/classic_core.hpp> | |
#include <boost/spirit/include/classic_confix.hpp> | |
#include <boost/spirit/include/classic_escape_char.hpp> | |
#include <boost/spirit/include/classic_multi_pass.hpp> | |
#include <boost/spirit/include/classic_position_iterator.hpp> | |
#define spirit_namespace boost::spirit::classic | |
#else | |
#include <boost/spirit/core.hpp> | |
#include <boost/spirit/utility/confix.hpp> | |
#include <boost/spirit/utility/escape_char.hpp> | |
#include <boost/spirit/iterator/multi_pass.hpp> | |
#include <boost/spirit/iterator/position_iterator.hpp> | |
#define spirit_namespace boost::spirit | |
#endif | |
namespace json_spirit | |
{ | |
const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >(); | |
const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >(); | |
template< class Iter_type > | |
bool is_eq( Iter_type first, Iter_type last, const char* c_str ) | |
{ | |
for( Iter_type i = first; i != last; ++i, ++c_str ) | |
{ | |
if( *c_str == 0 ) return false; | |
if( *i != *c_str ) return false; | |
} | |
return true; | |
} | |
template< class Char_type > | |
Char_type hex_to_num( const Char_type c ) | |
{ | |
if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0'; | |
if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10; | |
if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10; | |
return 0; | |
} | |
template< class Char_type, class Iter_type > | |
Char_type hex_str_to_char( Iter_type& begin ) | |
{ | |
const Char_type c1( *( ++begin ) ); | |
const Char_type c2( *( ++begin ) ); | |
return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 ); | |
} | |
template< class Char_type, class Iter_type > | |
Char_type unicode_str_to_char( Iter_type& begin ) | |
{ | |
const Char_type c1( *( ++begin ) ); | |
const Char_type c2( *( ++begin ) ); | |
const Char_type c3( *( ++begin ) ); | |
const Char_type c4( *( ++begin ) ); | |
return ( hex_to_num( c1 ) << 12 ) + | |
( hex_to_num( c2 ) << 8 ) + | |
( hex_to_num( c3 ) << 4 ) + | |
hex_to_num( c4 ); | |
} | |
template< class String_type > | |
void append_esc_char_and_incr_iter( String_type& s, | |
typename String_type::const_iterator& begin, | |
typename String_type::const_iterator end ) | |
{ | |
typedef typename String_type::value_type Char_type; | |
const Char_type c2( *begin ); | |
switch( c2 ) | |
{ | |
case 't': s += '\t'; break; | |
case 'b': s += '\b'; break; | |
case 'f': s += '\f'; break; | |
case 'n': s += '\n'; break; | |
case 'r': s += '\r'; break; | |
case '\\': s += '\\'; break; | |
case '/': s += '/'; break; | |
case '"': s += '"'; break; | |
case 'x': | |
{ | |
if( end - begin >= 3 ) // expecting "xHH..." | |
{ | |
s += hex_str_to_char< Char_type >( begin ); | |
} | |
break; | |
} | |
case 'u': | |
{ | |
if( end - begin >= 5 ) // expecting "uHHHH..." | |
{ | |
s += unicode_str_to_char< Char_type >( begin ); | |
} | |
break; | |
} | |
} | |
} | |
template< class String_type > | |
String_type substitute_esc_chars( typename String_type::const_iterator begin, | |
typename String_type::const_iterator end ) | |
{ | |
typedef typename String_type::const_iterator Iter_type; | |
if( end - begin < 2 ) return String_type( begin, end ); | |
String_type result; | |
result.reserve( end - begin ); | |
const Iter_type end_minus_1( end - 1 ); | |
Iter_type substr_start = begin; | |
Iter_type i = begin; | |
for( ; i < end_minus_1; ++i ) | |
{ | |
if( *i == '\\' ) | |
{ | |
result.append( substr_start, i ); | |
++i; // skip the '\' | |
append_esc_char_and_incr_iter( result, i, end ); | |
substr_start = i + 1; | |
} | |
} | |
result.append( substr_start, end ); | |
return result; | |
} | |
template< class String_type > | |
String_type get_str_( typename String_type::const_iterator begin, | |
typename String_type::const_iterator end ) | |
{ | |
assert( end - begin >= 2 ); | |
typedef typename String_type::const_iterator Iter_type; | |
Iter_type str_without_quotes( ++begin ); | |
Iter_type end_without_quotes( --end ); | |
return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes ); | |
} | |
inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end ) | |
{ | |
return get_str_< std::string >( begin, end ); | |
} | |
inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end ) | |
{ | |
return get_str_< std::wstring >( begin, end ); | |
} | |
template< class String_type, class Iter_type > | |
String_type get_str( Iter_type begin, Iter_type end ) | |
{ | |
const String_type tmp( begin, end ); // convert multipass iterators to string iterators | |
return get_str( tmp.begin(), tmp.end() ); | |
} | |
// this class's methods get called by the spirit parse resulting | |
// in the creation of a JSON object or array | |
// | |
// NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator | |
// | |
template< class Value_type, class Iter_type > | |
class Semantic_actions | |
{ | |
public: | |
typedef typename Value_type::Config_type Config_type; | |
typedef typename Config_type::String_type String_type; | |
typedef typename Config_type::Object_type Object_type; | |
typedef typename Config_type::Array_type Array_type; | |
typedef typename String_type::value_type Char_type; | |
Semantic_actions( Value_type& value ) | |
: value_( value ) | |
, current_p_( 0 ) | |
{ | |
} | |
void begin_obj( Char_type c ) | |
{ | |
assert( c == '{' ); | |
begin_compound< Object_type >(); | |
} | |
void end_obj( Char_type c ) | |
{ | |
assert( c == '}' ); | |
end_compound(); | |
} | |
void begin_array( Char_type c ) | |
{ | |
assert( c == '[' ); | |
begin_compound< Array_type >(); | |
} | |
void end_array( Char_type c ) | |
{ | |
assert( c == ']' ); | |
end_compound(); | |
} | |
void new_name( Iter_type begin, Iter_type end ) | |
{ | |
assert( current_p_->type() == obj_type ); | |
name_ = get_str< String_type >( begin, end ); | |
} | |
void new_str( Iter_type begin, Iter_type end ) | |
{ | |
add_to_current( get_str< String_type >( begin, end ) ); | |
} | |
void new_true( Iter_type begin, Iter_type end ) | |
{ | |
assert( is_eq( begin, end, "true" ) ); | |
add_to_current( true ); | |
} | |
void new_false( Iter_type begin, Iter_type end ) | |
{ | |
assert( is_eq( begin, end, "false" ) ); | |
add_to_current( false ); | |
} | |
void new_null( Iter_type begin, Iter_type end ) | |
{ | |
assert( is_eq( begin, end, "null" ) ); | |
add_to_current( Value_type() ); | |
} | |
void new_int( boost::int64_t i ) | |
{ | |
add_to_current( i ); | |
} | |
void new_uint64( boost::uint64_t ui ) | |
{ | |
add_to_current( ui ); | |
} | |
void new_real( double d ) | |
{ | |
add_to_current( d ); | |
} | |
private: | |
Semantic_actions& operator=( const Semantic_actions& ); | |
// to prevent "assignment operator could not be generated" warning | |
Value_type* add_first( const Value_type& value ) | |
{ | |
assert( current_p_ == 0 ); | |
value_ = value; | |
current_p_ = &value_; | |
return current_p_; | |
} | |
template< class Array_or_obj > | |
void begin_compound() | |
{ | |
if( current_p_ == 0 ) | |
{ | |
add_first( Array_or_obj() ); | |
} | |
else | |
{ | |
stack_.push_back( current_p_ ); | |
Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place | |
current_p_ = add_to_current( new_array_or_obj ); | |
} | |
} | |
void end_compound() | |
{ | |
if( current_p_ != &value_ ) | |
{ | |
current_p_ = stack_.back(); | |
stack_.pop_back(); | |
} | |
} | |
Value_type* add_to_current( const Value_type& value ) | |
{ | |
if( current_p_ == 0 ) | |
{ | |
return add_first( value ); | |
} | |
else if( current_p_->type() == array_type ) | |
{ | |
current_p_->get_array().push_back( value ); | |
return ¤t_p_->get_array().back(); | |
} | |
assert( current_p_->type() == obj_type ); | |
return &Config_type::add( current_p_->get_obj(), name_, value ); | |
} | |
Value_type& value_; // this is the object or array that is being created | |
Value_type* current_p_; // the child object or array that is currently being constructed | |
std::vector< Value_type* > stack_; // previous child objects and arrays | |
String_type name_; // of current name/value pair | |
}; | |
template< typename Iter_type > | |
void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason ) | |
{ | |
throw Error_position( i.get_position().line, i.get_position().column, reason ); | |
} | |
template< typename Iter_type > | |
void throw_error( Iter_type i, const std::string& reason ) | |
{ | |
throw reason; | |
} | |
// the spirit grammer | |
// | |
template< class Value_type, class Iter_type > | |
class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > > | |
{ | |
public: | |
typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t; | |
Json_grammer( Semantic_actions_t& semantic_actions ) | |
: actions_( semantic_actions ) | |
{ | |
} | |
static void throw_not_value( Iter_type begin, Iter_type end ) | |
{ | |
throw_error( begin, "not a value" ); | |
} | |
static void throw_not_array( Iter_type begin, Iter_type end ) | |
{ | |
throw_error( begin, "not an array" ); | |
} | |
static void throw_not_object( Iter_type begin, Iter_type end ) | |
{ | |
throw_error( begin, "not an object" ); | |
} | |
static void throw_not_pair( Iter_type begin, Iter_type end ) | |
{ | |
throw_error( begin, "not a pair" ); | |
} | |
static void throw_not_colon( Iter_type begin, Iter_type end ) | |
{ | |
throw_error( begin, "no colon in pair" ); | |
} | |
static void throw_not_string( Iter_type begin, Iter_type end ) | |
{ | |
throw_error( begin, "not a string" ); | |
} | |
template< typename ScannerT > | |
class definition | |
{ | |
public: | |
definition( const Json_grammer& self ) | |
{ | |
using namespace spirit_namespace; | |
typedef typename Value_type::String_type::value_type Char_type; | |
// first we convert the semantic action class methods to functors with the | |
// parameter signature expected by spirit | |
typedef boost::function< void( Char_type ) > Char_action; | |
typedef boost::function< void( Iter_type, Iter_type ) > Str_action; | |
typedef boost::function< void( double ) > Real_action; | |
typedef boost::function< void( boost::int64_t ) > Int_action; | |
typedef boost::function< void( boost::uint64_t ) > Uint64_action; | |
Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) ); | |
Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) ); | |
Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) ); | |
Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) ); | |
Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) ); | |
Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) ); | |
Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) ); | |
Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) ); | |
Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) ); | |
Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) ); | |
Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) ); | |
Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) ); | |
// actual grammer | |
json_ | |
= value_ | eps_p[ &throw_not_value ] | |
; | |
value_ | |
= string_[ new_str ] | |
| number_ | |
| object_ | |
| array_ | |
| str_p( "true" ) [ new_true ] | |
| str_p( "false" )[ new_false ] | |
| str_p( "null" ) [ new_null ] | |
; | |
object_ | |
= ch_p('{')[ begin_obj ] | |
>> !members_ | |
>> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] ) | |
; | |
members_ | |
= pair_ >> *( ',' >> pair_ ) | |
; | |
pair_ | |
= string_[ new_name ] | |
>> ( ':' | eps_p[ &throw_not_colon ] ) | |
>> ( value_ | eps_p[ &throw_not_value ] ) | |
; | |
array_ | |
= ch_p('[')[ begin_array ] | |
>> !elements_ | |
>> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] ) | |
; | |
elements_ | |
= value_ >> *( ',' >> value_ ) | |
; | |
string_ | |
= lexeme_d // this causes white space inside a string to be retained | |
[ | |
confix_p | |
( | |
'"', | |
*lex_escape_ch_p, | |
'"' | |
) | |
] | |
; | |
number_ | |
= strict_real_p[ new_real ] | |
| int64_p [ new_int ] | |
| uint64_p [ new_uint64 ] | |
; | |
} | |
spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_; | |
const spirit_namespace::rule< ScannerT >& start() const { return json_; } | |
}; | |
private: | |
Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning | |
Semantic_actions_t& actions_; | |
}; | |
template< class Iter_type, class Value_type > | |
Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) | |
{ | |
Semantic_actions< Value_type, Iter_type > semantic_actions( value ); | |
const spirit_namespace::parse_info< Iter_type > info = | |
spirit_namespace::parse( begin, end, | |
Json_grammer< Value_type, Iter_type >( semantic_actions ), | |
spirit_namespace::space_p ); | |
if( !info.hit ) | |
{ | |
assert( false ); // in theory exception should already have been thrown | |
throw_error( info.stop, "error" ); | |
} | |
return info.stop; | |
} | |
template< class Iter_type, class Value_type > | |
void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) | |
{ | |
typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; | |
const Posn_iter_t posn_begin( begin, end ); | |
const Posn_iter_t posn_end( end, end ); | |
read_range_or_throw( posn_begin, posn_end, value ); | |
} | |
template< class Iter_type, class Value_type > | |
bool read_range( Iter_type& begin, Iter_type end, Value_type& value ) | |
{ | |
try | |
{ | |
begin = read_range_or_throw( begin, end, value ); | |
return true; | |
} | |
catch( ... ) | |
{ | |
return false; | |
} | |
} | |
template< class String_type, class Value_type > | |
void read_string_or_throw( const String_type& s, Value_type& value ) | |
{ | |
add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); | |
} | |
template< class String_type, class Value_type > | |
bool read_string( const String_type& s, Value_type& value ) | |
{ | |
typename String_type::const_iterator begin = s.begin(); | |
return read_range( begin, s.end(), value ); | |
} | |
template< class Istream_type > | |
struct Multi_pass_iters | |
{ | |
typedef typename Istream_type::char_type Char_type; | |
typedef std::istream_iterator< Char_type, Char_type > istream_iter; | |
typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; | |
Multi_pass_iters( Istream_type& is ) | |
{ | |
is.unsetf( std::ios::skipws ); | |
begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); | |
end_ = spirit_namespace::make_multi_pass( istream_iter() ); | |
} | |
Mp_iter begin_; | |
Mp_iter end_; | |
}; | |
template< class Istream_type, class Value_type > | |
bool read_stream( Istream_type& is, Value_type& value ) | |
{ | |
Multi_pass_iters< Istream_type > mp_iters( is ); | |
return read_range( mp_iters.begin_, mp_iters.end_, value ); | |
} | |
template< class Istream_type, class Value_type > | |
void read_stream_or_throw( Istream_type& is, Value_type& value ) | |
{ | |
const Multi_pass_iters< Istream_type > mp_iters( is ); | |
add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value ); | |
} | |
} | |
#endif | |
"%file: ./json/json_spirit_stream_reader.h" | |
#ifndef JSON_SPIRIT_READ_STREAM | |
#define JSON_SPIRIT_READ_STREAM | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include "json_spirit_reader_template.h" | |
namespace json_spirit | |
{ | |
// these classes allows you to read multiple top level contiguous values from a stream, | |
// the normal stream read functions have a bug that prevent multiple top level values | |
// from being read unless they are separated by spaces | |
template< class Istream_type, class Value_type > | |
class Stream_reader | |
{ | |
public: | |
Stream_reader( Istream_type& is ) | |
: iters_( is ) | |
{ | |
} | |
bool read_next( Value_type& value ) | |
{ | |
return read_range( iters_.begin_, iters_.end_, value ); | |
} | |
private: | |
typedef Multi_pass_iters< Istream_type > Mp_iters; | |
Mp_iters iters_; | |
}; | |
template< class Istream_type, class Value_type > | |
class Stream_reader_thrower | |
{ | |
public: | |
Stream_reader_thrower( Istream_type& is ) | |
: iters_( is ) | |
, posn_begin_( iters_.begin_, iters_.end_ ) | |
, posn_end_( iters_.end_, iters_.end_ ) | |
{ | |
} | |
void read_next( Value_type& value ) | |
{ | |
posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value ); | |
} | |
private: | |
typedef Multi_pass_iters< Istream_type > Mp_iters; | |
typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t; | |
Mp_iters iters_; | |
Posn_iter_t posn_begin_, posn_end_; | |
}; | |
} | |
#endif | |
"%file: ./json/json_spirit_utils.h" | |
#ifndef JSON_SPIRIT_UTILS | |
#define JSON_SPIRIT_UTILS | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include "json_spirit_value.h" | |
#include <map> | |
namespace json_spirit | |
{ | |
template< class Obj_t, class Map_t > | |
void obj_to_map( const Obj_t& obj, Map_t& mp_obj ) | |
{ | |
mp_obj.clear(); | |
for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) | |
{ | |
mp_obj[ i->name_ ] = i->value_; | |
} | |
} | |
template< class Obj_t, class Map_t > | |
void map_to_obj( const Map_t& mp_obj, Obj_t& obj ) | |
{ | |
obj.clear(); | |
for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i ) | |
{ | |
obj.push_back( typename Obj_t::value_type( i->first, i->second ) ); | |
} | |
} | |
typedef std::map< std::string, Value > Mapped_obj; | |
#ifndef BOOST_NO_STD_WSTRING | |
typedef std::map< std::wstring, wValue > wMapped_obj; | |
#endif | |
template< class Object_type, class String_type > | |
const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name ) | |
{ | |
for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i ) | |
{ | |
if( i->name_ == name ) | |
{ | |
return i->value_; | |
} | |
} | |
return Object_type::value_type::Value_type::null; | |
} | |
} | |
#endif | |
"%file: ./json/json_spirit_value.h" | |
#ifndef JSON_SPIRIT_VALUE | |
#define JSON_SPIRIT_VALUE | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include <vector> | |
#include <map> | |
#include <string> | |
#include <cassert> | |
#include <sstream> | |
#include <stdexcept> | |
#include <boost/config.hpp> | |
#include <boost/cstdint.hpp> | |
#include <boost/shared_ptr.hpp> | |
#include <boost/variant.hpp> | |
namespace json_spirit | |
{ | |
enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; | |
static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"}; | |
template< class Config > // Config determines whether the value uses std::string or std::wstring and | |
// whether JSON Objects are represented as vectors or maps | |
class Value_impl | |
{ | |
public: | |
typedef Config Config_type; | |
typedef typename Config::String_type String_type; | |
typedef typename Config::Object_type Object; | |
typedef typename Config::Array_type Array; | |
typedef typename String_type::const_pointer Const_str_ptr; // eg const char* | |
Value_impl(); // creates null value | |
Value_impl( Const_str_ptr value ); | |
Value_impl( const String_type& value ); | |
Value_impl( const Object& value ); | |
Value_impl( const Array& value ); | |
Value_impl( bool value ); | |
Value_impl( int value ); | |
Value_impl( boost::int64_t value ); | |
Value_impl( boost::uint64_t value ); | |
Value_impl( double value ); | |
Value_impl( const Value_impl& other ); | |
bool operator==( const Value_impl& lhs ) const; | |
Value_impl& operator=( const Value_impl& lhs ); | |
Value_type type() const; | |
bool is_uint64() const; | |
bool is_null() const; | |
const String_type& get_str() const; | |
const Object& get_obj() const; | |
const Array& get_array() const; | |
bool get_bool() const; | |
int get_int() const; | |
boost::int64_t get_int64() const; | |
boost::uint64_t get_uint64() const; | |
double get_real() const; | |
Object& get_obj(); | |
Array& get_array(); | |
template< typename T > T get_value() const; // example usage: int i = value.get_value< int >(); | |
// or double d = value.get_value< double >(); | |
static const Value_impl null; | |
private: | |
void check_type( const Value_type vtype ) const; | |
typedef boost::variant< String_type, | |
boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, | |
bool, boost::int64_t, double > Variant; | |
Value_type type_; | |
Variant v_; | |
bool is_uint64_; | |
}; | |
// vector objects | |
template< class Config > | |
struct Pair_impl | |
{ | |
typedef typename Config::String_type String_type; | |
typedef typename Config::Value_type Value_type; | |
Pair_impl( const String_type& name, const Value_type& value ); | |
bool operator==( const Pair_impl& lhs ) const; | |
String_type name_; | |
Value_type value_; | |
}; | |
template< class String > | |
struct Config_vector | |
{ | |
typedef String String_type; | |
typedef Value_impl< Config_vector > Value_type; | |
typedef Pair_impl < Config_vector > Pair_type; | |
typedef std::vector< Value_type > Array_type; | |
typedef std::vector< Pair_type > Object_type; | |
static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) | |
{ | |
obj.push_back( Pair_type( name , value ) ); | |
return obj.back().value_; | |
} | |
static String_type get_name( const Pair_type& pair ) | |
{ | |
return pair.name_; | |
} | |
static Value_type get_value( const Pair_type& pair ) | |
{ | |
return pair.value_; | |
} | |
}; | |
// typedefs for ASCII | |
typedef Config_vector< std::string > Config; | |
typedef Config::Value_type Value; | |
typedef Config::Pair_type Pair; | |
typedef Config::Object_type Object; | |
typedef Config::Array_type Array; | |
// typedefs for Unicode | |
#ifndef BOOST_NO_STD_WSTRING | |
typedef Config_vector< std::wstring > wConfig; | |
typedef wConfig::Value_type wValue; | |
typedef wConfig::Pair_type wPair; | |
typedef wConfig::Object_type wObject; | |
typedef wConfig::Array_type wArray; | |
#endif | |
// map objects | |
template< class String > | |
struct Config_map | |
{ | |
typedef String String_type; | |
typedef Value_impl< Config_map > Value_type; | |
typedef std::vector< Value_type > Array_type; | |
typedef std::map< String_type, Value_type > Object_type; | |
typedef typename Object_type::value_type Pair_type; | |
static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) | |
{ | |
return obj[ name ] = value; | |
} | |
static String_type get_name( const Pair_type& pair ) | |
{ | |
return pair.first; | |
} | |
static Value_type get_value( const Pair_type& pair ) | |
{ | |
return pair.second; | |
} | |
}; | |
// typedefs for ASCII | |
typedef Config_map< std::string > mConfig; | |
typedef mConfig::Value_type mValue; | |
typedef mConfig::Object_type mObject; | |
typedef mConfig::Array_type mArray; | |
// typedefs for Unicode | |
#ifndef BOOST_NO_STD_WSTRING | |
typedef Config_map< std::wstring > wmConfig; | |
typedef wmConfig::Value_type wmValue; | |
typedef wmConfig::Object_type wmObject; | |
typedef wmConfig::Array_type wmArray; | |
#endif | |
/////////////////////////////////////////////////////////////////////////////////////////////// | |
// | |
// implementation | |
template< class Config > | |
const Value_impl< Config > Value_impl< Config >::null; | |
template< class Config > | |
Value_impl< Config >::Value_impl() | |
: type_( null_type ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( const Const_str_ptr value ) | |
: type_( str_type ) | |
, v_( String_type( value ) ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( const String_type& value ) | |
: type_( str_type ) | |
, v_( value ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( const Object& value ) | |
: type_( obj_type ) | |
, v_( value ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( const Array& value ) | |
: type_( array_type ) | |
, v_( value ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( bool value ) | |
: type_( bool_type ) | |
, v_( value ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( int value ) | |
: type_( int_type ) | |
, v_( static_cast< boost::int64_t >( value ) ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( boost::int64_t value ) | |
: type_( int_type ) | |
, v_( value ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( boost::uint64_t value ) | |
: type_( int_type ) | |
, v_( static_cast< boost::int64_t >( value ) ) | |
, is_uint64_( true ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( double value ) | |
: type_( real_type ) | |
, v_( value ) | |
, is_uint64_( false ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) | |
: type_( other.type() ) | |
, v_( other.v_ ) | |
, is_uint64_( other.is_uint64_ ) | |
{ | |
} | |
template< class Config > | |
Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs ) | |
{ | |
Value_impl tmp( lhs ); | |
std::swap( type_, tmp.type_ ); | |
std::swap( v_, tmp.v_ ); | |
std::swap( is_uint64_, tmp.is_uint64_ ); | |
return *this; | |
} | |
template< class Config > | |
bool Value_impl< Config >::operator==( const Value_impl& lhs ) const | |
{ | |
if( this == &lhs ) return true; | |
if( type() != lhs.type() ) return false; | |
return v_ == lhs.v_; | |
} | |
template< class Config > | |
Value_type Value_impl< Config >::type() const | |
{ | |
return type_; | |
} | |
template< class Config > | |
bool Value_impl< Config >::is_uint64() const | |
{ | |
return is_uint64_; | |
} | |
template< class Config > | |
bool Value_impl< Config >::is_null() const | |
{ | |
return type() == null_type; | |
} | |
template< class Config > | |
void Value_impl< Config >::check_type( const Value_type vtype ) const | |
{ | |
if( type() != vtype ) | |
{ | |
std::ostringstream os; | |
/// satoshi: tell the types by name instead of by number | |
os << "value is type " << Value_type_name[type()] << ", expected " << Value_type_name[vtype]; | |
throw std::runtime_error( os.str() ); | |
} | |
} | |
template< class Config > | |
const typename Config::String_type& Value_impl< Config >::get_str() const | |
{ | |
check_type( str_type ); | |
return *boost::get< String_type >( &v_ ); | |
} | |
template< class Config > | |
const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const | |
{ | |
check_type( obj_type ); | |
return *boost::get< Object >( &v_ ); | |
} | |
template< class Config > | |
const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const | |
{ | |
check_type( array_type ); | |
return *boost::get< Array >( &v_ ); | |
} | |
template< class Config > | |
bool Value_impl< Config >::get_bool() const | |
{ | |
check_type( bool_type ); | |
return boost::get< bool >( v_ ); | |
} | |
template< class Config > | |
int Value_impl< Config >::get_int() const | |
{ | |
check_type( int_type ); | |
return static_cast< int >( get_int64() ); | |
} | |
template< class Config > | |
boost::int64_t Value_impl< Config >::get_int64() const | |
{ | |
check_type( int_type ); | |
return boost::get< boost::int64_t >( v_ ); | |
} | |
template< class Config > | |
boost::uint64_t Value_impl< Config >::get_uint64() const | |
{ | |
check_type( int_type ); | |
return static_cast< boost::uint64_t >( get_int64() ); | |
} | |
template< class Config > | |
double Value_impl< Config >::get_real() const | |
{ | |
if( type() == int_type ) | |
{ | |
return is_uint64() ? static_cast< double >( get_uint64() ) | |
: static_cast< double >( get_int64() ); | |
} | |
check_type( real_type ); | |
return boost::get< double >( v_ ); | |
} | |
template< class Config > | |
typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() | |
{ | |
check_type( obj_type ); | |
return *boost::get< Object >( &v_ ); | |
} | |
template< class Config > | |
typename Value_impl< Config >::Array& Value_impl< Config >::get_array() | |
{ | |
check_type( array_type ); | |
return *boost::get< Array >( &v_ ); | |
} | |
template< class Config > | |
Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value ) | |
: name_( name ) | |
, value_( value ) | |
{ | |
} | |
template< class Config > | |
bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const | |
{ | |
if( this == &lhs ) return true; | |
return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ ); | |
} | |
// converts a C string, ie. 8 bit char array, to a string object | |
// | |
template < class String_type > | |
String_type to_str( const char* c_str ) | |
{ | |
String_type result; | |
for( const char* p = c_str; *p != 0; ++p ) | |
{ | |
result += *p; | |
} | |
return result; | |
} | |
// | |
namespace internal_ | |
{ | |
template< typename T > | |
struct Type_to_type | |
{ | |
}; | |
template< class Value > | |
int get_value( const Value& value, Type_to_type< int > ) | |
{ | |
return value.get_int(); | |
} | |
template< class Value > | |
boost::int64_t get_value( const Value& value, Type_to_type< boost::int64_t > ) | |
{ | |
return value.get_int64(); | |
} | |
template< class Value > | |
boost::uint64_t get_value( const Value& value, Type_to_type< boost::uint64_t > ) | |
{ | |
return value.get_uint64(); | |
} | |
template< class Value > | |
double get_value( const Value& value, Type_to_type< double > ) | |
{ | |
return value.get_real(); | |
} | |
template< class Value > | |
typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > ) | |
{ | |
return value.get_str(); | |
} | |
template< class Value > | |
typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > ) | |
{ | |
return value.get_array(); | |
} | |
template< class Value > | |
typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > ) | |
{ | |
return value.get_obj(); | |
} | |
template< class Value > | |
bool get_value( const Value& value, Type_to_type< bool > ) | |
{ | |
return value.get_bool(); | |
} | |
} | |
template< class Config > | |
template< typename T > | |
T Value_impl< Config >::get_value() const | |
{ | |
return internal_::get_value( *this, internal_::Type_to_type< T >() ); | |
} | |
} | |
#endif | |
"%file: ./json/json_spirit_value.cpp" | |
/* Copyright (c) 2007 John W Wilkinson | |
This source code can be used for any purpose as long as | |
this comment is retained. */ | |
// json spirit version 2.00 | |
#include "json_spirit_value.h" | |
"%file: ./json/json_spirit_writer.h" | |
#ifndef JSON_SPIRIT_WRITER | |
#define JSON_SPIRIT_WRITER | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include "json_spirit_value.h" | |
#include <iostream> | |
namespace json_spirit | |
{ | |
// functions to convert JSON Values to text, | |
// the "formatted" versions add whitespace to format the output nicely | |
void write ( const Value& value, std::ostream& os ); | |
void write_formatted( const Value& value, std::ostream& os ); | |
std::string write ( const Value& value ); | |
std::string write_formatted( const Value& value ); | |
#ifndef BOOST_NO_STD_WSTRING | |
void write ( const wValue& value, std::wostream& os ); | |
void write_formatted( const wValue& value, std::wostream& os ); | |
std::wstring write ( const wValue& value ); | |
std::wstring write_formatted( const wValue& value ); | |
#endif | |
void write ( const mValue& value, std::ostream& os ); | |
void write_formatted( const mValue& value, std::ostream& os ); | |
std::string write ( const mValue& value ); | |
std::string write_formatted( const mValue& value ); | |
#ifndef BOOST_NO_STD_WSTRING | |
void write ( const wmValue& value, std::wostream& os ); | |
void write_formatted( const wmValue& value, std::wostream& os ); | |
std::wstring write ( const wmValue& value ); | |
std::wstring write_formatted( const wmValue& value ); | |
#endif | |
} | |
#endif | |
"%file: ./json/json_spirit_writer.cpp" | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#include "json_spirit_writer.h" | |
#include "json_spirit_writer_template.h" | |
void json_spirit::write( const Value& value, std::ostream& os ) | |
{ | |
write_stream( value, os, false ); | |
} | |
void json_spirit::write_formatted( const Value& value, std::ostream& os ) | |
{ | |
write_stream( value, os, true ); | |
} | |
std::string json_spirit::write( const Value& value ) | |
{ | |
return write_string( value, false ); | |
} | |
std::string json_spirit::write_formatted( const Value& value ) | |
{ | |
return write_string( value, true ); | |
} | |
#ifndef BOOST_NO_STD_WSTRING | |
void json_spirit::write( const wValue& value, std::wostream& os ) | |
{ | |
write_stream( value, os, false ); | |
} | |
void json_spirit::write_formatted( const wValue& value, std::wostream& os ) | |
{ | |
write_stream( value, os, true ); | |
} | |
std::wstring json_spirit::write( const wValue& value ) | |
{ | |
return write_string( value, false ); | |
} | |
std::wstring json_spirit::write_formatted( const wValue& value ) | |
{ | |
return write_string( value, true ); | |
} | |
#endif | |
void json_spirit::write( const mValue& value, std::ostream& os ) | |
{ | |
write_stream( value, os, false ); | |
} | |
void json_spirit::write_formatted( const mValue& value, std::ostream& os ) | |
{ | |
write_stream( value, os, true ); | |
} | |
std::string json_spirit::write( const mValue& value ) | |
{ | |
return write_string( value, false ); | |
} | |
std::string json_spirit::write_formatted( const mValue& value ) | |
{ | |
return write_string( value, true ); | |
} | |
#ifndef BOOST_NO_STD_WSTRING | |
void json_spirit::write( const wmValue& value, std::wostream& os ) | |
{ | |
write_stream( value, os, false ); | |
} | |
void json_spirit::write_formatted( const wmValue& value, std::wostream& os ) | |
{ | |
write_stream( value, os, true ); | |
} | |
std::wstring json_spirit::write( const wmValue& value ) | |
{ | |
return write_string( value, false ); | |
} | |
std::wstring json_spirit::write_formatted( const wmValue& value ) | |
{ | |
return write_string( value, true ); | |
} | |
#endif | |
"%file: ./json/json_spirit_writer_template.h" | |
#ifndef JSON_SPIRIT_WRITER_TEMPLATE | |
#define JSON_SPIRIT_WRITER_TEMPLATE | |
// Copyright John W. Wilkinson 2007 - 2009. | |
// Distributed under the MIT License, see accompanying file LICENSE.txt | |
// json spirit version 4.03 | |
#include "json_spirit_value.h" | |
#include <cassert> | |
#include <sstream> | |
#include <iomanip> | |
namespace json_spirit | |
{ | |
inline char to_hex_char( unsigned int c ) | |
{ | |
assert( c <= 0xF ); | |
const char ch = static_cast< char >( c ); | |
if( ch < 10 ) return '0' + ch; | |
return 'A' - 10 + ch; | |
} | |
template< class String_type > | |
String_type non_printable_to_string( unsigned int c ) | |
{ | |
typedef typename String_type::value_type Char_type; | |
String_type result( 6, '\\' ); | |
result[1] = 'u'; | |
result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4; | |
result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4; | |
result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4; | |
result[ 2 ] = to_hex_char( c & 0x000F ); | |
return result; | |
} | |
template< typename Char_type, class String_type > | |
bool add_esc_char( Char_type c, String_type& s ) | |
{ | |
switch( c ) | |
{ | |
case '"': s += to_str< String_type >( "\\\"" ); return true; | |
case '\\': s += to_str< String_type >( "\\\\" ); return true; | |
case '\b': s += to_str< String_type >( "\\b" ); return true; | |
case '\f': s += to_str< String_type >( "\\f" ); return true; | |
case '\n': s += to_str< String_type >( "\\n" ); return true; | |
case '\r': s += to_str< String_type >( "\\r" ); return true; | |
case '\t': s += to_str< String_type >( "\\t" ); return true; | |
} | |
return false; | |
} | |
template< class String_type > | |
String_type add_esc_chars( const String_type& s ) | |
{ | |
typedef typename String_type::const_iterator Iter_type; | |
typedef typename String_type::value_type Char_type; | |
String_type result; | |
const Iter_type end( s.end() ); | |
for( Iter_type i = s.begin(); i != end; ++i ) | |
{ | |
const Char_type c( *i ); | |
if( add_esc_char( c, result ) ) continue; | |
const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); | |
if( iswprint( unsigned_c ) ) | |
{ | |
result += c; | |
} | |
else | |
{ | |
result += non_printable_to_string< String_type >( unsigned_c ); | |
} | |
} | |
return result; | |
} | |
// this class generates the JSON text, | |
// it keeps track of the indentation level etc. | |
// | |
template< class Value_type, class Ostream_type > | |
class Generator | |
{ | |
typedef typename Value_type::Config_type Config_type; | |
typedef typename Config_type::String_type String_type; | |
typedef typename Config_type::Object_type Object_type; | |
typedef typename Config_type::Array_type Array_type; | |
typedef typename String_type::value_type Char_type; | |
typedef typename Object_type::value_type Obj_member_type; | |
public: | |
Generator( const Value_type& value, Ostream_type& os, bool pretty ) | |
: os_( os ) | |
, indentation_level_( 0 ) | |
, pretty_( pretty ) | |
{ | |
output( value ); | |
} | |
private: | |
void output( const Value_type& value ) | |
{ | |
switch( value.type() ) | |
{ | |
case obj_type: output( value.get_obj() ); break; | |
case array_type: output( value.get_array() ); break; | |
case str_type: output( value.get_str() ); break; | |
case bool_type: output( value.get_bool() ); break; | |
case int_type: output_int( value ); break; | |
case real_type: os_ << std::showpoint << std::setprecision( 16 ) | |
<< value.get_real(); break; | |
case null_type: os_ << "null"; break; | |
default: assert( false ); | |
} | |
} | |
void output( const Object_type& obj ) | |
{ | |
output_array_or_obj( obj, '{', '}' ); | |
} | |
void output( const Array_type& arr ) | |
{ | |
output_array_or_obj( arr, '[', ']' ); | |
} | |
void output( const Obj_member_type& member ) | |
{ | |
output( Config_type::get_name( member ) ); space(); | |
os_ << ':'; space(); | |
output( Config_type::get_value( member ) ); | |
} | |
void output_int( const Value_type& value ) | |
{ | |
if( value.is_uint64() ) | |
{ | |
os_ << value.get_uint64(); | |
} | |
else | |
{ | |
os_ << value.get_int64(); | |
} | |
} | |
void output( const String_type& s ) | |
{ | |
os_ << '"' << add_esc_chars( s ) << '"'; | |
} | |
void output( bool b ) | |
{ | |
os_ << to_str< String_type >( b ? "true" : "false" ); | |
} | |
template< class T > | |
void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char ) | |
{ | |
os_ << start_char; new_line(); | |
++indentation_level_; | |
for( typename T::const_iterator i = t.begin(); i != t.end(); ++i ) | |
{ | |
indent(); output( *i ); | |
typename T::const_iterator next = i; | |
if( ++next != t.end()) | |
{ | |
os_ << ','; | |
} | |
new_line(); | |
} | |
--indentation_level_; | |
indent(); os_ << end_char; | |
} | |
void indent() | |
{ | |
if( !pretty_ ) return; | |
for( int i = 0; i < indentation_level_; ++i ) | |
{ | |
os_ << " "; | |
} | |
} | |
void space() | |
{ | |
if( pretty_ ) os_ << ' '; | |
} | |
void new_line() | |
{ | |
if( pretty_ ) os_ << '\n'; | |
} | |
Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning | |
Ostream_type& os_; | |
int indentation_level_; | |
bool pretty_; | |
}; | |
template< class Value_type, class Ostream_type > | |
void write_stream( const Value_type& value, Ostream_type& os, bool pretty ) | |
{ | |
Generator< Value_type, Ostream_type >( value, os, pretty ); | |
} | |
template< class Value_type > | |
typename Value_type::String_type write_string( const Value_type& value, bool pretty ) | |
{ | |
typedef typename Value_type::String_type::value_type Char_type; | |
std::basic_ostringstream< Char_type > os; | |
write_stream( value, os, pretty ); | |
return os.str(); | |
} | |
} | |
#endif | |
"%file: ./json/LICENSE.txt" | |
The MIT License | |
Copyright (c) 2007 - 2009 John W. Wilkinson | |
Permission is hereby granted, free of charge, to any person | |
obtaining a copy of this software and associated documentation | |
files (the "Software"), to deal in the Software without | |
restriction, including without limitation the rights to use, | |
copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following | |
conditions: | |
The above copyright notice and this permission notice shall be | |
included in all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
OTHER DEALINGS IN THE SOFTWARE. | |
"%file: ./key.h" | |
// Copyright (c) 2009 Satoshi Nakamoto | |
// Distributed under the MIT/X11 software license, see the accompanying | |
// file license.txt or http://www.opensource.org/licenses/mit-license.php. | |
// secp160k1 | |
// const unsigned int PRIVATE_KEY_SIZE = 192; | |
// const unsigned int PUBLIC_KEY_SIZE = 41; | |
// const unsigned int SIGNATURE_SIZE = 48; | |
// | |
// secp192k1 | |
// const unsigned int PRIVATE_KEY_SIZE = 222; | |
// const unsigned int PUBLIC_KEY_SIZE = 49; | |
// const unsigned int SIGNATURE_SIZE = 57; | |
// | |
// secp224k1 | |
// const unsigned int PRIVATE_KEY_SIZE = 250; | |
// const unsigned int PUBLIC_KEY_SIZE = 57; | |
// const unsigned int SIGNATURE_SIZE = 66; | |
// | |
// secp256k1: | |
// const unsigned int PRIVATE_KEY_SIZE = 279; | |
// const unsigned int PUBLIC_KEY_SIZE = 65; | |
// const unsigned int SIGNATURE_SIZE = 72; | |
// | |
// see www.keylength.com | |
// script supports up to 75 for single byte push | |
class key_error : public std::runtime_error | |
{ | |
public: | |
explicit key_error(const std::string& str) : std::runtime_error(str) {} | |
}; | |
// secure_allocator is defined in serialize.h | |
typedef vector<unsigned char, secure_allocator<unsigned char> > CPrivKey; | |
class CKey | |
{ | |
protected: | |
EC_KEY* pkey; | |
bool fSet; | |
public: | |
CKey() | |
{ | |
pkey = EC_KEY_new_by_curve_name(NID_secp256k1); | |
if (pkey == NULL) | |
throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); | |
fSet = false; | |
} | |
CKey(const CKey& b) | |
{ | |
pkey = EC_KEY_dup(b.pkey); | |
if (pkey == NULL) | |
throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); | |
fSet = b.fSet; | |
} | |
CKey& operator=(const CKey& b) | |
{ | |
if (!EC_KEY_copy(pkey, b.pkey)) | |
throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); | |
fSet = b.fSet; | |
return (*this); | |
} | |
~CKey() | |
{ | |
EC_KEY_free(pkey); | |
} | |
bool IsNull() const | |
{ | |
return !fSet; | |
} | |
void MakeNewKey() | |
{ | |
if (!EC_KEY_generate_key(pkey)) | |
throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); | |
fSet = true; | |
} | |
bool SetPrivKey(const CPrivKey& vchPrivKey) | |
{ | |
const unsigned char* pbegin = &vchPrivKey[0]; | |
if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) | |
return false; | |
fSet = true; | |
return true; | |
} | |
CPrivKey GetPrivKey() const | |
{ | |
unsigned int nSize = i2d_ECPrivateKey(pkey, NULL); | |
if (!nSize) | |
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); | |
CPrivKey vchPrivKey(nSize, 0); | |
unsigned char* pbegin = &vchPrivKey[0]; | |
if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) | |
throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); | |
return vchPrivKey; | |
} | |
bool SetPubKey(const vector<unsigned char>& vchPubKey) | |
{ | |
const unsigned char* pbegin = &vchPubKey[0]; | |
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) | |
return false; | |
fSet = true; | |
return true; | |
} | |
vector<unsigned char> GetPubKey() const | |
{ | |
unsigned int nSize = i2o_ECPublicKey(pkey, NULL); | |
if (!nSize) | |
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); | |
vector<unsigned char> vchPubKey(nSize, 0); | |
unsigned char* pbegin = &vchPubKey[0]; | |
if (i2o_ECPublicKey(pkey, &pbegin) != nSize) | |
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); | |
return vchPubKey; | |
} | |
bool Sign(uint256 hash, vector<unsigned char>& vchSig) | |
{ | |
vchSig.clear(); | |
unsigned char pchSig[10000]; | |
unsigned int nSize = 0; | |
if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey)) | |
return false; | |
vchSig.resize(nSize); | |
memcpy(&vchSig[0], pchSig, nSize); | |
return true; | |
} | |
bool Verify(uint256 hash, const vector<unsigned char>& vchSig) | |
{ | |
// -1 = error, 0 = bad sig, 1 = good | |
if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) | |
return false; | |
return true; | |
} | |
static bool Sign(const CPrivKey& vchPrivKey, uint256 hash, vector<unsigned char>& vchSig) | |
{ | |
CKey key; | |
if (!key.SetPrivKey(vchPrivKey)) | |
return false; | |
return key.Sign(hash, vchSig); | |
} | |
static bool Verify(const vector<unsigned char>& vchPubKey, uint256 hash, const vector<unsigned char>& vchSig) | |
{ | |
CKey key; | |
if (!key.SetPubKey(vchPubKey)) | |
return false; | |
return key.Verify(hash, vchSig); | |
} | |
}; | |
"%file: ./license.txt" | |
Copyright (c) 2009-2010 Satoshi Nakamoto | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
THE SOFTWARE. | |
"%file: ./locale/de/LC_MESSAGES/bitcoin.mo" | |
Þ é ì | |