Skip to content

Instantly share code, notes, and snippets.

/bitcoin.c Secret

Created August 30, 2017 19:59
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/b4d5d1ab333c5d6e238fdc2242a428b5 to your computer and use it in GitHub Desktop.
Save anonymous/b4d5d1ab333c5d6e238fdc2242a428b5 to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
"%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 &current_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"
Þ•­„éì
‘5¡×æû (9K P ]g mw– §³ ÂÌÕÜü*0 JT,g” ¢®µ » Åæ"1A])z¤´ÂÑßó ,E S_y ŽŸ½ÆÎ×ñ 9 Z a#k­Ð»Œ¤«° ¶ÂØ Þëaþ`r!²Ò×ÚO²$'.M ](gf©Xi|“¥´ÌJæ1&7^}‚‹ ¦²µÈNÖ% -7@Ra6u)¬
Öáê  
$/7H
[fky‘¢
©©´Ð^È/ÓøÌ Fß e&!Ō!R"$W"|""¤"À"Ñ"æ"##+#G#d#ƒ#™#
°#»#Ã#Ë#˜à#y%9‡% Á%!Î%ð% && &&8&I&O& _& i& v&€&“& ¥&±& Å&Ï& Ø&â& '
'' '&'8'?' Y'e'6'¸' É'
Ö' á'î'$ý'"(%=(c(v(!ˆ(!ª(*Ì(÷( )) ,)9)N)h) x)„)¢)°);Ä)*
**%'* M*Y*a*j*†*˜*
¨*O³* +
+,+E+ ]+ýi+g- €-- “- Ÿ-¬-Ä-Í-#à-n.s.%†.)¬.'Ö.þ.D/OL03œ0Ð0!Ö0ø0
1-1@1~[1·Ú1’3«3Å3Ú3í34[$4 €454.Ã4ò4
ø455 5,5/5 E5iR5¼5
Å5Ð5á5õ5 6>&60e6
–6¡6%ª6Ð6&Ù6 7
77+7A7 O7[7p7Œ7Ÿ7¦7ϵ7<…8åÂ9ð¨:™;Eª;|ð;"m<=K•=á=ö=)>9>O>#i>>¢>Á>Û>$û> ?6?L? f?p?x?'‚b/¨ˆ–SCF.7[¬5PGŒ žŽOš}~¥¡x‡N|By!X"“¤ª¢QM ˜$1(%i—&)›>{ ;­=E*™‰”r’:€4ToqŸd\D_+…8Yk<^U‹32v‘§nfŠ`¦
Vt„?,J#•Rw]g0lƒAI©zWZchp L«-eK£6j@u†as9œHm
Connecting... %d connections %d blocks %d transactions Generating &Copy to Clipboard &New Address... &New... &Port: (yours) (yours, label: Address &Book... All In Progress Received Sent Standard transaction fee is included %d confirmations%d/offline?%d/unconfirmed&About...&Amount:&Apply&Connect through socks4 proxy: &Delete&Edit...&File&From:&Generate Coins&Help&Limit coin generation to&Message:&Minimize on close&Minimize to the tray instead of the taskbar&Open Bitcoin&Options...&Paste&Send&Settings&Start Bitcoin on system startup&Your Receiving Addresses...(%s matures in %d more blocks)(not accepted)(not connected), broadcast through %d node, broadcast through %d nodes, has not been successfully broadcast yet<b>Credit:</b> <b>Date:</b> <b>Debit:</b> <b>From:</b> <b>Net amount:</b> <b>Source:</b> Generated<br><b>Status:</b> <b>To:</b> <b>Transaction fee:</b> About BitcoinAdd AddressAdd a node to connect to
AddressAddress BookAll TransactionsAmount exceeds your balance Balance:BitcoinBitcoin Bitcoin - (not connected)Bitcoin - GeneratingBitcoin AddressCANCELLEDCan't include a message when sending to a Bitcoin addressCancelCancelledConnect only to the specified node
Connect through socks4 proxy
Connecting...Copyright (c) 2009-2010 Satoshi Nakamoto.
This is experimental software. Do not rely on it for actual financial transactions.
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/) and cryptographic software written by
Eric Young (eay@cryptsoft.com).Creating transaction...CreditDateDebitDescriptionDon't generate coins
E&xitEdit AddressEdit Address LabelEnter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)Error in amount Error loading addr.dat
Error loading blkindex.dat
Error loading wallet.dat
Error: Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.Error: This is an oversized transaction that requires a transaction fee of %s Error: Transaction creation failed From: From: unknown, Received with: Generate coins
GeneratedGenerated (%s matures in %d more blocks)Generated (not accepted)Generated - Warning: This block was not received by any other nodes and will probably not be accepted!Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.Insufficient fundsInvalid -proxy addressInvalid address Invalid amountInvalid bitcoin addressInvalid response receivedIt's good policy to use a new address for each payment you receive.
LabelLabelLost connection, transaction cancelledM&inimize to the tray on closeMainMessage:NameNew Receiving AddressO&ptions...OKOpen for %d blocksOpen until %sOptional transaction fee you give to the nodes that process your transactions.OptionsOptions:
Pay &To:Payment completedPayment sent Payment to yourselfPayment was sent, but an invalid response was receivedProgram has crashed and will terminate. Proxy &IP:ReceivedReceived public key...ReceivingRequesting public key...Send CoinsSendingSending %s to %sSending payment...Sending...SentSent/ReceivedSpecify data directory
Start minimized
StatusT&ransfer:The payment was sent, but the recipient was unable to verify it.
The transaction is recorded and will credit to the recipient,
but the comment information will be blank.The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.These are your Bitcoin addresses for receiving payments. You can give a different one to each sender to keep track of who is paying you. The highlighted address will be displayed in the main window.These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window.This help message
This is an oversized transaction that requires a transaction fee of %sThis is one of your own addresses for receiving payments and cannot be entered in the address book. This transaction is over the size limit. You can still send it for a fee of %s, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?To: Total exceeds your balance when the Transaction DetailsTransaction abortedTransaction creation failedTransaction fee:Transfer cancelled Transfer was not acceptedUnable to connectUsage: bitcoin [options]Waiting for confirmation...Warning: Disk space is low Will appear as "From: Unknown"Your Bitcoin Address:Your Bitcoin Addressesprocessorsunknownversionversion 0.%d.%d betaPOT-Creation-Date: 2010-05-26 22:02-0000
PO-Revision-Date: 2010-06-16 17:31-0000
Last-Translator: Satoshi Nakamoto
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Poedit-KeywordsList: _;gettext;gettext_noop
X-Poedit-Basepath: .
X-Generator: Lokalize 1.0
Plural-Forms: nplurals=2; plural=n != 1;
Project-Id-Version:
Language-Team:
X-Poedit-SearchPath-0: ../../..
Verbinde... %d Verbindungen %d Blöcke %d Überweisungen Erzeugen In die Zwischenablage &kopieren &Neue Adresse... &Neu... &Port: (Eigene) (Eigene, Beschreibung: Address&buch... Alle In Bearbeitung Erhalten Überwiesen Standard berücksichtigt %d Bestätigungen%d/Offline?%d/nicht bestätigtÜ&ber...&Betrag:&Anwenden&Verbinden per Socks4-Proxy: &Löschen&Bearbeiten...&Datei&Von:Münzen Er&zeugen&HilfeErzeugung von Münzen auf&Nachricht:Beim schließen &MinimierenIn den Infobereich statt in die Taskleiste &minimierenBitcoin Ö&ffnen&Optionen...&EinfügenÜ&berweisen&EinstellungenBitcoin beim &Systemstart ausführen&Ihre Empfangs-Adressen...(%s reifen nach %d weiteren Blöcken)(nicht akzeptiert)(nicht verbunden), durch %d Teilnehmer übertragen, durch %d Teilnehmer übertragen, wurde noch nicht erfolgreich übertragen<b>Gutschrift:</b> <b>Datum</b> <b>Belastung:</b> <b>Von:</b> <b>Nettobetrag:</b> <b>Quelle:</b>Erzeugt<br><b>Status:</b> <b>An:</b> <b>Überweisungsgebühr:</b> Über BitcoinAdresse hinzufügenEinen Teilnehmer hinzufügen, zu dem verbunden werden soll
AdresseAdressbuchAlle ÜberweisungenDer Betrag übersteigt Ihr Guthaben Kontostand:BitcoinBitcoin Bitcoin - (nicht verbunden)Bitcoin - ErzeugeBitcoin-AdresseANNULLIERTBeim überweisen an eine Bitcoin-Adresse kann keine Nachricht angegeben werden.AbbrechenAnnulliertNur zu dem angegebenen Teilnehmer verbinden
Socks4 Proxy verwenden
Verbinde...Copyright (c) 2009-2010 Satoshi Nakamoto.
Dies ist experimentelle Software. Verlassen Sie sich für tatsächliche
finanzielle Transaktionen nicht auf sie.
Lizensiert unter der MIT/X11 Software-Lizenz. Beachten Sie die beiliegende
Datei license.txt oder http://www.opensource.org/licenses/mit-license.php.
Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Nutzung im
OpenSSL Toolkit (http://www.openssl.org/) geschrieben wurde sowie
kryptographische Software von Eric Young (eay@cryptsoft.com).Erstelle Überweisung...GutschriftenDatumBelastungenBeschreibungKeine Münzen erzeugen
B&eendenAdresse bearbeitenBeschreibung der Adresse bearbeitenGeben Sie eine Bitcoin-Adresse (z.B. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) oder IP-Adresse (z.B. 123.45.6.7) einFehler in Betrag Fehler beim Laden von addr.dat
Fehler beim Laden von blkindex.dat
Fehler beim Laden von wallet.dat
Fehler: Fehler: Die Überweisung wurde abgelehnt. Das kann passieren, wenn einige der Münzen in Ihrer Brieftasche bereits ausgegeben wurden, z.B. weil Sie eine Kopie der Brieftasche (wallet.dat) gemacht haben. Bitcoins, die mithilfe der Kopie ausgegeben wurden, sind in dieser Brieftasche noch nicht als ausgegeben markiert worden.Fehler: Die Überweisung ist sehr groß. Es wird eine Gebühr von %s erhoben. Fehler: Überweisung konnte nicht erzeugt werden. Von: Von: Unbekannt, Empfangen durch: Münzen erzeugen
ErzeugtErzeugt (%s reifen nach %d weiteren Blöcken)Erzeugt (nicht akzeptiert)Erzeugt - Warnung: Dieser Block wurde von keinem anderen Teilnehmer empfangen und wird wahrscheinlich nicht akzeptiert werden!Erzeugte Münzen müssen 120 Blöcke lang reifen. Als Sie diesen Block erzeugt haben, wurde er an alle Teilnehmer übertragen, damit er zur Block-Kette hinzugefügt werden kann. Falls der Block es nicht in die Block-Kette schafft, wird die Beschreibung zu "nicht akzeptiert" geändert, und Sie können die Münzen nicht ausgeben. Dies kann manchmal passieren, wenn Sie und ein anderer Teilnehmer annähernd zeitgleich einen Block erzeugen.Unzureichende GeldmittelUngültige -Proxy AdresseUngültige Adresse Ungültiger BetragUngültige Bitcoin-AdresseUngültige Antwort erhaltenAm besten verwenden Sie für jede Zahlung die Sie erhalten eine neue Adresse.
BeschreibungBeschreibungVerbindung verloren, Überweisungsvorgang abgebrochenBeim schließen in den Infobereich m&inimierenHauptNachricht:Name&Neue Empfangs-AdresseO&ptionen...OKOffen für %d BlöckeOffen bis %sOptionale Überweisungsgebühr, die Sie an den Teilnehmer entrichten, der Ihre Überweisungen bearbeitet.OptionenOptionen:
Überweisen &An:Zahlung ausgeführtZahlung überwiesen Überweisung an Sie selbstDie Zahlung wurde überwiesen, aber die Antwort war fehlerhaftDas Programm ist abgestürzt und wird beendet. Proxy &IP:ErhaltenÖffentlichen Schlüssel empfangen...EmpfangeFordere öffentlichen Schlüssel an...ÜberweisenÜberweiseÜberweise %s an %sÜberweise Zahlung...Überweise...ÜberwiesenÜberwiesen/ErhaltenDatenverzeichnis festlegen
Minimiert starten
StatusÜ&berweisung:Die Zahlung wurde überwiesen, aber der Empfänger konnte sie nicht bestätigen.
Die Überweisung wurde gespeichert und wird dem Empfänger gutgeschrieben,
aber die begleitende Nachricht wird nicht ankommen.Die Überweisung wurde abgelehnt. Das kann passieren, wenn einige der Münzen in Ihrer Brieftasche bereits ausgegeben wurden, z.B. weil Sie eine Kopie der Brieftasche (wallet.dat) gemacht haben. Bitcoins, die mithilfe der Kopie ausgegeben wurden, sind in dieser Brieftasche noch nicht als ausgegeben markiert worden.Dies sind Ihre Bitcoin-Adressen zum Empfang von Zahlungen. Sie können jedem Überweisenden eine andere Adresse geben um nachvollziehen zu können von wem eine Zahlung stammt. Die markierte Adresse wird im Hauptfenster angezeigt.Dies sind Ihre Bitcoin-Adressen zum Empfang von Zahlungen. Sie sollten vielleicht jedem Überweisenden eine andere Adresse geben um nachvollziehen zu können von wem eine Zahlung stammt. Die markierte Adresse wird im Hauptfenster angezeigt.Diese Anleitung
Die Überweisung ist sehr groß. Es wird eine Gebühr von %s erhoben.Dies ist eine Ihrer eigenen Adressen für den Zahlungseingang und kann deshalb nicht in das Adressbuch übernommen werden. Diese Überweisung übersteigt das Betragslimit. Sie können sie trotzdem tätigen, aber es wird eine Gebühr von %s erhoben, die an den Teilnehmer ausgeschüttet wird, der Ihre Überweisung bearbeitet und dadurch hilft das Netzwerk am laufen zu halten. Möchten Sie die Gebühr entrichten?An: Der Betrag übersteigt Ihr Guthaben, wenn man die Überweisungsgebühr von ÜberweisungsdetailsÜberweisung abgebrochenÜberweisung konnte nicht erzeugt werden.Überweisungsgebühr:Überweisung annulliert Überweisung wurde nicht akzeptiertKann nicht verbindenVerwendung: bitcoin [optionen]Warte auf Bestätigung...Warnung: Festplatte fast voll Wird als "Von: Unbekannt" erscheinenIhre Bitcoin-Adresse:Ihre Bitcoin-AdressenProzessoren &beschränkenUnbekanntVersionVersion 0.%d.%d Beta
"%file: ./locale/de/LC_MESSAGES/bitcoin.po"
# DataWraith <DataWraith@web.de>, 2010.
msgid ""
msgstr ""
"POT-Creation-Date: 2010-05-26 22:02-0000\n"
"PO-Revision-Date: 2010-06-03 13:11+0200\n"
"Last-Translator: DataWraith\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-SearchPath-0: ../../..\n"
"X-Generator: Lokalize 1.0\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#: ../../../init.cpp:342
msgid "Usage: bitcoin [options]"
msgstr "Verwendung: bitcoin [optionen]"
#: ../../../init.cpp:343
msgid "Options:\n"
msgstr "Optionen:\n"
#: ../../../init.cpp:344
msgid "Generate coins\n"
msgstr "Münzen erzeugen\n"
#: ../../../init.cpp:345
msgid "Don't generate coins\n"
msgstr "Keine Münzen erzeugen\n"
#: ../../../init.cpp:346
msgid "Start minimized\n"
msgstr "Minimiert starten\n"
#: ../../../init.cpp:347
msgid "Specify data directory\n"
msgstr "Datenverzeichnis festlegen\n"
#: ../../../init.cpp:348
msgid "Connect through socks4 proxy\n"
msgstr "Socks4 Proxy verwenden\n"
#: ../../../init.cpp:349
msgid "Add a node to connect to\n"
msgstr "Einen Teilnehmer hinzufügen, zu dem verbunden werden soll\n"
#: ../../../init.cpp:350
msgid "Connect only to the specified node\n"
msgstr "Nur zu dem angegebenen Teilnehmer verbinden\n"
#: ../../../init.cpp:351
msgid "This help message\n"
msgstr "Diese Anleitung\n"
#: ../../../init.cpp:455
msgid "Error loading addr.dat \n"
msgstr "Fehler beim Laden von addr.dat \n"
#: ../../../init.cpp:461
msgid "Error loading blkindex.dat \n"
msgstr "Fehler beim Laden von blkindex.dat \n"
#: ../../../init.cpp:468
msgid "Error loading wallet.dat \n"
msgstr "Fehler beim Laden von wallet.dat \n"
#: ../../../init.cpp:536
msgid "Invalid -proxy address"
msgstr "Ungültige -Proxy Adresse"
#: ../../../init.cpp:629
msgid "Program has crashed and will terminate. "
msgstr "Das Programm ist abgestürzt und wird beendet. "
#: ../../../main.cpp:1465
msgid "Warning: Disk space is low "
msgstr "Warnung: Festplatte fast voll "
#: ../../../main.cpp:2994
#, c-format
msgid "Error: This is an oversized transaction that requires a transaction fee of %s "
msgstr "Fehler: Die Überweisung ist sehr groß. Es wird eine Gebühr von %s erhoben. "
#: ../../../main.cpp:2996
msgid "Error: Transaction creation failed "
msgstr "Fehler: Überweisung konnte nicht erzeugt werden. "
#: ../../../main.cpp:3001
#: ../../../ui.cpp:1761
#: ../../../ui.cpp:1763
#: ../../../ui.cpp:1904
#: ../../../ui.cpp:2053
msgid "Sending..."
msgstr "Überweise..."
#: ../../../main.cpp:3005
msgid "Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."
msgstr "Fehler: Die Überweisung wurde abgelehnt. Das kann passieren, wenn einige der Münzen in Ihrer Brieftasche bereits ausgegeben wurden, z.B. weil Sie eine Kopie der Brieftasche (wallet.dat) gemacht haben. Bitcoins, die mithilfe der Kopie ausgegeben wurden, sind in dieser Brieftasche noch nicht als ausgegeben markiert worden."
#: ../../../main.cpp:3017
msgid "Invalid amount"
msgstr "Ungültiger Betrag"
#: ../../../main.cpp:3019
#: ../../../ui.cpp:1971
#: ../../../ui.cpp:2038
msgid "Insufficient funds"
msgstr "Unzureichende Geldmittel"
#: ../../../main.cpp:3024
msgid "Invalid bitcoin address"
msgstr "Ungültige Bitcoin-Adresse"
#: ../../../ui.cpp:189
#, c-format
msgid "This transaction is over the size limit. You can still send it for a fee of %s, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?"
msgstr "Diese Überweisung übersteigt das Betragslimit. Sie können sie trotzdem tätigen, aber es wird eine Gebühr von %s erhoben, die an den Teilnehmer ausgeschüttet wird, der Ihre Überweisung bearbeitet und dadurch hilft das Netzwerk am laufen zu halten. Möchten Sie die Gebühr entrichten?"
#: ../../../ui.cpp:285
msgid "Status"
msgstr "Status"
#: ../../../ui.cpp:286
msgid "Date"
msgstr "Datum"
#: ../../../ui.cpp:287
msgid "Description"
msgstr "Beschreibung"
#: ../../../ui.cpp:288
msgid "Debit"
msgstr "Belastungen"
#: ../../../ui.cpp:289
msgid "Credit"
msgstr "Gutschriften"
#: ../../../ui.cpp:489
#, c-format
msgid "Open for %d blocks"
msgstr "Offen für %d Blöcke"
#: ../../../ui.cpp:491
#, c-format
msgid "Open until %s"
msgstr "Offen bis %s"
#: ../../../ui.cpp:497
#, c-format
msgid "%d/offline?"
msgstr "%d/Offline?"
#: ../../../ui.cpp:499
#, c-format
msgid "%d/unconfirmed"
msgstr "%d/nicht bestätigt"
#: ../../../ui.cpp:501
#, c-format
msgid "%d confirmations"
msgstr "%d Bestätigungen"
#: ../../../ui.cpp:584
msgid "Generated"
msgstr "Erzeugt"
#: ../../../ui.cpp:592
#, c-format
msgid "Generated (%s matures in %d more blocks)"
msgstr "Erzeugt (%s reifen nach %d weiteren Blöcken)"
#: ../../../ui.cpp:596
msgid "Generated - Warning: This block was not received by any other nodes and will probably not be accepted!"
msgstr "Erzeugt - Warnung: Dieser Block wurde von keinem anderen Teilnehmer empfangen und wird wahrscheinlich nicht akzeptiert werden!"
#: ../../../ui.cpp:600
msgid "Generated (not accepted)"
msgstr "Erzeugt (nicht akzeptiert)"
#: ../../../ui.cpp:610
msgid "From: "
msgstr "Von: "
#: ../../../ui.cpp:634
msgid "From: unknown, Received with: "
msgstr "Von: Unbekannt, Empfangen durch: "
#: ../../../ui.cpp:676
msgid "Payment to yourself"
msgstr "Überweisung an Sie selbst"
#: ../../../ui.cpp:713
msgid "To: "
msgstr "An: "
#: ../../../ui.cpp:1009
msgid " Generating"
msgstr " Erzeugen"
#: ../../../ui.cpp:1011
msgid "(not connected)"
msgstr "(nicht verbunden)"
#: ../../../ui.cpp:1014
#, c-format
msgid " %d connections %d blocks %d transactions"
msgstr " %d Verbindungen %d Blöcke %d Überweisungen"
#: ../../../ui.cpp:1123
#: ../../../ui.cpp:2351
msgid "New Receiving Address"
msgstr "&Neue Empfangs-Adresse"
#: ../../../ui.cpp:1124
#: ../../../ui.cpp:2352
msgid ""
"It's good policy to use a new address for each payment you receive.\n"
"\n"
"Label"
msgstr ""
"Am besten verwenden Sie für jede Zahlung die Sie erhalten eine neue Adresse.\n"
"\n"
"Beschreibung"
#: ../../../ui.cpp:1193
msgid "<b>Status:</b> "
msgstr "<b>Status:</b> "
#: ../../../ui.cpp:1198
msgid ", has not been successfully broadcast yet"
msgstr ", wurde noch nicht erfolgreich übertragen"
#: ../../../ui.cpp:1200
#, c-format
msgid ", broadcast through %d node"
msgstr ", durch %d Teilnehmer übertragen"
#: ../../../ui.cpp:1202
#, c-format
msgid ", broadcast through %d nodes"
msgstr ", durch %d Teilnehmer übertragen"
#: ../../../ui.cpp:1206
msgid "<b>Date:</b> "
msgstr "<b>Datum</b> "
#: ../../../ui.cpp:1214
msgid "<b>Source:</b> Generated<br>"
msgstr "<b>Quelle:</b>Erzeugt<br>"
#: ../../../ui.cpp:1220
#: ../../../ui.cpp:1238
msgid "<b>From:</b> "
msgstr "<b>Von:</b> "
#: ../../../ui.cpp:1238
msgid "unknown"
msgstr "Unbekannt"
#: ../../../ui.cpp:1239
#: ../../../ui.cpp:1263
#: ../../../ui.cpp:1322
msgid "<b>To:</b> "
msgstr "<b>An:</b> "
#: ../../../ui.cpp:1242
msgid " (yours, label: "
msgstr " (Eigene, Beschreibung: "
#: ../../../ui.cpp:1244
msgid " (yours)"
msgstr " (Eigene)"
#: ../../../ui.cpp:1281
#: ../../../ui.cpp:1293
#: ../../../ui.cpp:1356
msgid "<b>Credit:</b> "
msgstr "<b>Gutschrift:</b> "
#: ../../../ui.cpp:1283
#, c-format
msgid "(%s matures in %d more blocks)"
msgstr "(%s reifen nach %d weiteren Blöcken)"
#: ../../../ui.cpp:1285
msgid "(not accepted)"
msgstr "(nicht akzeptiert)"
#: ../../../ui.cpp:1330
#: ../../../ui.cpp:1353
msgid "<b>Debit:</b> "
msgstr "<b>Belastung:</b> "
#: ../../../ui.cpp:1344
msgid "<b>Transaction fee:</b> "
msgstr "<b>Überweisungsgebühr:</b> "
#: ../../../ui.cpp:1360
msgid "<b>Net amount:</b> "
msgstr "<b>Nettobetrag:</b> "
#: ../../../ui.cpp:1367
msgid "Message:"
msgstr "Nachricht:"
#: ../../../ui.cpp:1370
msgid "Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours."
msgstr ""
"Erzeugte Münzen müssen 120 Blöcke lang reifen. Als Sie diesen Block erzeugt haben, wurde er an alle Teilnehmer übertragen, damit er zur Block-Kette hinzugefügt werden kann. Falls der Block es nicht in die Block-Kette schafft, wird die Beschreibung zu \"nicht akzeptiert\" geändert, und Sie können die Münzen nicht ausgeben. Dies kann manchmal "
"passieren, wenn Sie und ein anderer Teilnehmer annähernd zeitgleich einen Block erzeugen."
#: ../../../ui.cpp:1437
msgid "Main"
msgstr "Haupt"
#: ../../../ui.cpp:1442
msgid "&Minimize on close"
msgstr "Beim schließen &Minimieren"
#: ../../../ui.cpp:1595
#, c-format
msgid "version 0.%d.%d beta"
msgstr "Version 0.%d.%d Beta"
#: ../../../ui.cpp:1681
msgid "Will appear as \"From: Unknown\""
msgstr "Wird als \"Von: Unbekannt\" erscheinen"
#: ../../../ui.cpp:1682
msgid "Can't include a message when sending to a Bitcoin address"
msgstr "Beim überweisen an eine Bitcoin-Adresse kann keine Nachricht angegeben werden."
#: ../../../ui.cpp:1735
msgid "Error in amount "
msgstr "Fehler in Betrag "
#: ../../../ui.cpp:1735
#: ../../../ui.cpp:1740
#: ../../../ui.cpp:1745
#: ../../../ui.cpp:1771
#: ../../../uibase.cpp:61
msgid "Send Coins"
msgstr "Überweisen"
#: ../../../ui.cpp:1740
msgid "Amount exceeds your balance "
msgstr "Der Betrag übersteigt Ihr Guthaben "
#: ../../../ui.cpp:1745
msgid "Total exceeds your balance when the "
msgstr "Der Betrag übersteigt Ihr Guthaben, wenn man die Überweisungsgebühr von "
#: ../../../ui.cpp:1745
msgid " transaction fee is included "
msgstr " berücksichtigt "
#: ../../../ui.cpp:1761
msgid "Payment sent "
msgstr "Zahlung überwiesen "
#: ../../../ui.cpp:1771
msgid "Invalid address "
msgstr "Ungültige Adresse "
#: ../../../ui.cpp:1825
#, c-format
msgid "Sending %s to %s"
msgstr "Überweise %s an %s"
#: ../../../ui.cpp:1898
#: ../../../ui.cpp:1931
msgid "CANCELLED"
msgstr "ANNULLIERT"
#: ../../../ui.cpp:1902
msgid "Cancelled"
msgstr "Annulliert"
#: ../../../ui.cpp:1904
msgid "Transfer cancelled "
msgstr "Überweisung annulliert "
#: ../../../ui.cpp:1957
msgid "Error: "
msgstr "Fehler: "
#: ../../../ui.cpp:1976
msgid "Connecting..."
msgstr "Verbinde..."
#: ../../../ui.cpp:1981
msgid "Unable to connect"
msgstr "Kann nicht verbinden"
#: ../../../ui.cpp:1986
msgid "Requesting public key..."
msgstr "Fordere öffentlichen Schlüssel an..."
#: ../../../ui.cpp:1998
msgid "Received public key..."
msgstr "Öffentlichen Schlüssel empfangen..."
#: ../../../ui.cpp:2010
msgid "Transfer was not accepted"
msgstr "Überweisung wurde nicht akzeptiert"
#: ../../../ui.cpp:2019
msgid "Invalid response received"
msgstr "Ungültige Antwort erhalten"
#: ../../../ui.cpp:2034
msgid "Creating transaction..."
msgstr "Erstelle Überweisung..."
#: ../../../ui.cpp:2046
#, c-format
msgid "This is an oversized transaction that requires a transaction fee of %s"
msgstr "Die Überweisung ist sehr groß. Es wird eine Gebühr von %s erhoben."
#: ../../../ui.cpp:2048
msgid "Transaction creation failed"
msgstr "Überweisung konnte nicht erzeugt werden."
#: ../../../ui.cpp:2055
msgid "Transaction aborted"
msgstr "Überweisung abgebrochen"
#: ../../../ui.cpp:2063
msgid "Lost connection, transaction cancelled"
msgstr "Verbindung verloren, Überweisungsvorgang abgebrochen"
#: ../../../ui.cpp:2079
msgid "Sending payment..."
msgstr "Überweise Zahlung..."
#: ../../../ui.cpp:2085
msgid "The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."
msgstr "Die Überweisung wurde abgelehnt. Das kann passieren, wenn einige der Münzen in Ihrer Brieftasche bereits ausgegeben wurden, z.B. weil Sie eine Kopie der Brieftasche (wallet.dat) gemacht haben. Bitcoins, die mithilfe der Kopie ausgegeben wurden, sind in dieser Brieftasche noch nicht als ausgegeben markiert worden."
#: ../../../ui.cpp:2092
msgid "Waiting for confirmation..."
msgstr "Warte auf Bestätigung..."
#: ../../../ui.cpp:2110
msgid ""
"The payment was sent, but the recipient was unable to verify it.\n"
"The transaction is recorded and will credit to the recipient,\n"
"but the comment information will be blank."
msgstr ""
"Die Zahlung wurde überwiesen, aber der Empfänger konnte sie nicht bestätigen.\n"
"Die Überweisung wurde gespeichert und wird dem Empfänger gutgeschrieben,\n"
"aber die begleitende Nachricht wird nicht ankommen."
#: ../../../ui.cpp:2119
msgid "Payment was sent, but an invalid response was received"
msgstr "Die Zahlung wurde überwiesen, aber die Antwort war fehlerhaft"
#: ../../../ui.cpp:2125
msgid "Payment completed"
msgstr "Zahlung ausgeführt"
#: ../../../ui.cpp:2156
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2339
msgid "Name"
msgstr "Name"
#: ../../../ui.cpp:2157
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2339
msgid "Address"
msgstr "Adresse"
#: ../../../ui.cpp:2159
#: ../../../ui.cpp:2314
msgid "Label"
msgstr "Beschreibung"
#: ../../../ui.cpp:2160
#: ../../../uibase.cpp:908
msgid "Bitcoin Address"
msgstr "Bitcoin-Adresse"
#: ../../../ui.cpp:2284
msgid "This is one of your own addresses for receiving payments and cannot be entered in the address book. "
msgstr "Dies ist eine Ihrer eigenen Adressen für den Zahlungseingang und kann deshalb nicht in das Adressbuch übernommen werden. "
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2308
msgid "Edit Address"
msgstr "Adresse bearbeiten"
#: ../../../ui.cpp:2314
msgid "Edit Address Label"
msgstr "Beschreibung der Adresse bearbeiten"
#: ../../../ui.cpp:2339
#: ../../../ui.cpp:2345
msgid "Add Address"
msgstr "Adresse hinzufügen"
#: ../../../ui.cpp:2421
msgid "Bitcoin"
msgstr "Bitcoin"
#: ../../../ui.cpp:2423
msgid "Bitcoin - Generating"
msgstr "Bitcoin - Erzeuge"
#: ../../../ui.cpp:2425
msgid "Bitcoin - (not connected)"
msgstr "Bitcoin - (nicht verbunden)"
#: ../../../ui.cpp:2500
msgid "&Open Bitcoin"
msgstr "Bitcoin Ö&ffnen"
#: ../../../ui.cpp:2501
msgid "O&ptions..."
msgstr "O&ptionen..."
#: ../../../ui.cpp:2502
#: ../../../uibase.cpp:34
msgid "&Generate Coins"
msgstr "Münzen Er&zeugen"
#: ../../../ui.cpp:2505
#: ../../../uibase.cpp:27
msgid "E&xit"
msgstr "B&eenden"
#: ../../../uibase.cpp:30
msgid "&File"
msgstr "&Datei"
#: ../../../uibase.cpp:38
msgid "&Your Receiving Addresses..."
msgstr "&Ihre Empfangs-Adressen..."
#: ../../../uibase.cpp:42
msgid "&Options..."
msgstr "&Optionen..."
#: ../../../uibase.cpp:45
msgid "&Settings"
msgstr "&Einstellungen"
#: ../../../uibase.cpp:49
msgid "&About..."
msgstr "Ü&ber..."
#: ../../../uibase.cpp:52
msgid "&Help"
msgstr "&Hilfe"
#: ../../../uibase.cpp:62
msgid "Address Book"
msgstr "Adressbuch"
#: ../../../uibase.cpp:77
msgid "Your Bitcoin Address:"
msgstr "Ihre Bitcoin-Adresse:"
#: ../../../uibase.cpp:84
msgid " &New... "
msgstr " &Neu... "
#: ../../../uibase.cpp:87
#: ../../../uibase.cpp:851
#: ../../../uibase.cpp:954
msgid " &Copy to Clipboard "
msgstr " In die Zwischenablage &kopieren "
#: ../../../uibase.cpp:102
msgid "Balance:"
msgstr "Kontostand:"
#: ../../../uibase.cpp:121
msgid " All"
msgstr " Alle"
#: ../../../uibase.cpp:121
msgid " Sent"
msgstr " Überwiesen"
#: ../../../uibase.cpp:121
msgid " Received"
msgstr " Erhalten"
#: ../../../uibase.cpp:121
msgid " In Progress"
msgstr " In Bearbeitung"
#: ../../../uibase.cpp:142
msgid "All Transactions"
msgstr "Alle Überweisungen"
#: ../../../uibase.cpp:153
msgid "Sent/Received"
msgstr "Überwiesen/Erhalten"
#: ../../../uibase.cpp:164
msgid "Sent"
msgstr "Überwiesen"
#: ../../../uibase.cpp:175
msgid "Received"
msgstr "Erhalten"
#: ../../../uibase.cpp:318
#: ../../../uibase.cpp:479
#: ../../../uibase.cpp:580
#: ../../../uibase.cpp:793
#: ../../../uibase.cpp:854
#: ../../../uibase.cpp:963
#: ../../../uibase.cpp:1052
msgid "OK"
msgstr "OK"
#: ../../../uibase.cpp:361
msgid "Optional transaction fee you give to the nodes that process your transactions."
msgstr "Optionale Überweisungsgebühr, die Sie an den Teilnehmer entrichten, der Ihre Überweisungen bearbeitet."
#: ../../../uibase.cpp:370
msgid "Transaction fee:"
msgstr "Überweisungsgebühr:"
#: ../../../uibase.cpp:386
msgid "&Limit coin generation to"
msgstr "Erzeugung von Münzen auf"
#: ../../../uibase.cpp:393
msgid "processors"
msgstr "Prozessoren &beschränken"
#: ../../../uibase.cpp:399
msgid "&Start Bitcoin on system startup"
msgstr "Bitcoin beim &Systemstart ausführen"
#: ../../../uibase.cpp:403
msgid "&Minimize to the tray instead of the taskbar"
msgstr "In den Infobereich statt in die Taskleiste &minimieren"
#: ../../../uibase.cpp:407
msgid "M&inimize to the tray on close"
msgstr "Beim schließen in den Infobereich m&inimieren"
#: ../../../uibase.cpp:414
msgid "&Connect through socks4 proxy: "
msgstr "&Verbinden per Socks4-Proxy: "
#: ../../../uibase.cpp:426
msgid "Proxy &IP:"
msgstr "Proxy &IP:"
#: ../../../uibase.cpp:434
msgid " &Port:"
msgstr " &Port:"
#: ../../../uibase.cpp:456
msgid "// [don't translate] Test panel 2 for future expansion"
msgstr ""
#: ../../../uibase.cpp:460
msgid "// [don't translate] Let's not start multiple pages until the first page is filled up"
msgstr ""
#: ../../../uibase.cpp:482
#: ../../../uibase.cpp:735
#: ../../../uibase.cpp:798
#: ../../../uibase.cpp:857
#: ../../../uibase.cpp:966
#: ../../../uibase.cpp:1055
msgid "Cancel"
msgstr "Abbrechen"
#: ../../../uibase.cpp:485
msgid "&Apply"
msgstr "&Anwenden"
#: ../../../uibase.cpp:546
msgid "Bitcoin "
msgstr "Bitcoin "
#: ../../../uibase.cpp:552
msgid "version"
msgstr "Version"
#: ../../../uibase.cpp:563
msgid ""
"Copyright (c) 2009-2010 Satoshi Nakamoto.\n"
"\n"
"This is experimental software. Do not rely on it for actual financial transactions.\n"
"\n"
"Distributed under the MIT/X11 software license, see the accompanying file \n"
"license.txt or http://www.opensource.org/licenses/mit-license.php.\n"
"\n"
"This product includes software developed by the OpenSSL Project for use in the \n"
"OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by \n"
"Eric Young (eay@cryptsoft.com)."
msgstr ""
"Copyright (c) 2009-2010 Satoshi Nakamoto.\n"
"\n"
"Dies ist experimentelle Software. Verlassen Sie sich für tatsächliche\n"
"finanzielle Transaktionen nicht auf sie.\n"
"\n"
"Lizensiert unter der MIT/X11 Software-Lizenz. Beachten Sie die beiliegende\n"
"Datei license.txt oder http://www.opensource.org/licenses/mit-license.php.\n"
"\n"
"Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Nutzung im\n"
"OpenSSL Toolkit (http://www.openssl.org/) geschrieben wurde sowie\n"
"kryptographische Software von Eric Young (eay@cryptsoft.com)."
#: ../../../uibase.cpp:619
msgid "Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)"
msgstr "Geben Sie eine Bitcoin-Adresse (z.B. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) oder IP-Adresse (z.B. 123.45.6.7) ein"
#: ../../../uibase.cpp:633
msgid "Pay &To:"
msgstr "Überweisen &An:"
#: ../../../uibase.cpp:648
msgid "&Paste"
msgstr "&Einfügen"
#: ../../../uibase.cpp:651
msgid " Address &Book..."
msgstr " Address&buch..."
#: ../../../uibase.cpp:658
msgid "&Amount:"
msgstr "&Betrag:"
#: ../../../uibase.cpp:668
msgid "T&ransfer:"
msgstr "Ü&berweisung:"
#: ../../../uibase.cpp:674
msgid " Standard"
msgstr " Standard"
#: ../../../uibase.cpp:696
msgid "&From:"
msgstr "&Von:"
#: ../../../uibase.cpp:713
msgid "&Message:"
msgstr "&Nachricht:"
#: ../../../uibase.cpp:730
msgid "&Send"
msgstr "Ü&berweisen"
#: ../../../uibase.cpp:782
msgid ""
"\n"
"\n"
"Connecting..."
msgstr ""
"\n"
"\n"
"Verbinde..."
#: ../../../uibase.cpp:832
msgid "These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window."
msgstr "Dies sind Ihre Bitcoin-Adressen zum Empfang von Zahlungen. Sie sollten vielleicht jedem Überweisenden eine andere Adresse geben um nachvollziehen zu können von wem eine Zahlung stammt. Die markierte Adresse wird im Hauptfenster angezeigt."
#: ../../../uibase.cpp:845
#: ../../../uibase.cpp:957
msgid "&Edit..."
msgstr "&Bearbeiten..."
#: ../../../uibase.cpp:848
#: ../../../uibase.cpp:960
msgid " &New Address... "
msgstr " &Neue Adresse... "
#: ../../../uibase.cpp:920
msgid "Sending"
msgstr "Überweise"
#: ../../../uibase.cpp:928
msgid "These are your Bitcoin addresses for receiving payments. You can give a different one to each sender to keep track of who is paying you. The highlighted address will be displayed in the main window."
msgstr "Dies sind Ihre Bitcoin-Adressen zum Empfang von Zahlungen. Sie können jedem Überweisenden eine andere Adresse geben um nachvollziehen zu können von wem eine Zahlung stammt. Die markierte Adresse wird im Hauptfenster angezeigt."
#: ../../../uibase.cpp:941
msgid "Receiving"
msgstr "Empfange"
#: ../../../uibase.cpp:951
msgid "&Delete"
msgstr "&Löschen"
#: ../../../uibase.h:150
msgid "Transaction Details"
msgstr "Überweisungsdetails"
#: ../../../uibase.h:203
msgid "Options"
msgstr "Optionen"
#: ../../../uibase.h:231
msgid "About Bitcoin"
msgstr "Über Bitcoin"
#: ../../../uibase.h:341
msgid "Your Bitcoin Addresses"
msgstr "Ihre Bitcoin-Adressen"
"%file: ./locale/it/LC_MESSAGES/bitcoin.mo"
Þ•­„éì
‘5¡×æû (9K P ]g mw– §³ ÂÌÕÜü*0 JT,g” ¢®µ » Åæ"1A])z¤´ÂÑßó ,E S_y ŽŸ½ÆÎ×ñ 9 Z a#k­Ð»Œ¤«° ¶ÂØ Þëaþ`r!²Ò×ÚO²$'.M ](gf©Xi|“¥´ÌJæ1&7^}‚‹ ¦²µÈNÖ% -7@Ra6u)¬
Öáê  
$/7H
[fky‘¢
©©´Ð^È/ÓøÌ Fß e&!Ō!R"$W"|""¤"À"Ñ"æ"##+#G#d#ƒ#™#
°#»#Ã#Ë#là#M%7g%Ÿ%­%Æ% Ü%è% ñ%û%&*&1& A&K& T&$^& ƒ&&ž&°&
¹&Ä&#Í& ñ&
û&' '','3' S'_',t'¡' ¯'»'Ä'Ë'$Ù'!þ'$ (E(U(d(„(+¤(Ð(á(ï( ÿ( )*)H)
W)b) )Œ)#Ÿ) Ã)Í)ß)-ó) !*+*3*<*U*i*
{*Q†*Ø*
á*,ì*!+;+ÌS+ -;-C-H- O-[-p-v-‰-l£-.#(.'L.%t.š. £.O­/3ý/1060V0e0-n0œ0tµ0a*1Œ2Ÿ2º2Ñ2æ23W 3x3+~3#ª3
Î3
Ù3ä3é3 444(4Q94‹4 “44¦4»4Ï4Bå4-(5
V5a5j5 ‡5‘5 ®5»5Ä5Õ5 ë5÷5ÿ56/6B6H6ÃX67×8×ö8Î9Lé9{6:î²:¡;-¥;Ó;ç;þ;<3<K<g<<–<(¯< Ø<ù<=
,=
7=B=K='‚b/¨ˆ–SCF.7[¬5PGŒ žŽOš}~¥¡x‡N|By!X"“¤ª¢QM ˜$1(%i—&)›>{ ;­=E*™‰”r’:€4ToqŸd\D_+…8Yk<^U‹32v‘§nfŠ`¦
Vt„?,J#•Rw]g0lƒAI©zWZchp L«-eK£6j@u†as9œHm
Connecting... %d connections %d blocks %d transactions Generating &Copy to Clipboard &New Address... &New... &Port: (yours) (yours, label: Address &Book... All In Progress Received Sent Standard transaction fee is included %d confirmations%d/offline?%d/unconfirmed&About...&Amount:&Apply&Connect through socks4 proxy: &Delete&Edit...&File&From:&Generate Coins&Help&Limit coin generation to&Message:&Minimize on close&Minimize to the tray instead of the taskbar&Open Bitcoin&Options...&Paste&Send&Settings&Start Bitcoin on system startup&Your Receiving Addresses...(%s matures in %d more blocks)(not accepted)(not connected), broadcast through %d node, broadcast through %d nodes, has not been successfully broadcast yet<b>Credit:</b> <b>Date:</b> <b>Debit:</b> <b>From:</b> <b>Net amount:</b> <b>Source:</b> Generated<br><b>Status:</b> <b>To:</b> <b>Transaction fee:</b> About BitcoinAdd AddressAdd a node to connect to
AddressAddress BookAll TransactionsAmount exceeds your balance Balance:BitcoinBitcoin Bitcoin - (not connected)Bitcoin - GeneratingBitcoin AddressCANCELLEDCan't include a message when sending to a Bitcoin addressCancelCancelledConnect only to the specified node
Connect through socks4 proxy
Connecting...Copyright (c) 2009-2010 Satoshi Nakamoto.
This is experimental software. Do not rely on it for actual financial transactions.
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/) and cryptographic software written by
Eric Young (eay@cryptsoft.com).Creating transaction...CreditDateDebitDescriptionDon't generate coins
E&xitEdit AddressEdit Address LabelEnter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)Error in amount Error loading addr.dat
Error loading blkindex.dat
Error loading wallet.dat
Error: Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.Error: This is an oversized transaction that requires a transaction fee of %s Error: Transaction creation failed From: From: unknown, Received with: Generate coins
GeneratedGenerated (%s matures in %d more blocks)Generated (not accepted)Generated - Warning: This block was not received by any other nodes and will probably not be accepted!Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.Insufficient fundsInvalid -proxy addressInvalid address Invalid amountInvalid bitcoin addressInvalid response receivedIt's good policy to use a new address for each payment you receive.
LabelLabelLost connection, transaction cancelledM&inimize to the tray on closeMainMessage:NameNew Receiving AddressO&ptions...OKOpen for %d blocksOpen until %sOptional transaction fee you give to the nodes that process your transactions.OptionsOptions:
Pay &To:Payment completedPayment sent Payment to yourselfPayment was sent, but an invalid response was receivedProgram has crashed and will terminate. Proxy &IP:ReceivedReceived public key...ReceivingRequesting public key...Send CoinsSendingSending %s to %sSending payment...Sending...SentSent/ReceivedSpecify data directory
Start minimized
StatusT&ransfer:The payment was sent, but the recipient was unable to verify it.
The transaction is recorded and will credit to the recipient,
but the comment information will be blank.The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.These are your Bitcoin addresses for receiving payments. You can give a different one to each sender to keep track of who is paying you. The highlighted address will be displayed in the main window.These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window.This help message
This is an oversized transaction that requires a transaction fee of %sThis is one of your own addresses for receiving payments and cannot be entered in the address book. This transaction is over the size limit. You can still send it for a fee of %s, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?To: Total exceeds your balance when the Transaction DetailsTransaction abortedTransaction creation failedTransaction fee:Transfer cancelled Transfer was not acceptedUnable to connectUsage: bitcoin [options]Waiting for confirmation...Warning: Disk space is low Will appear as "From: Unknown"Your Bitcoin Address:Your Bitcoin Addressesprocessorsunknownversionversion 0.%d.%d betaProject-Id-Version:
Report-Msgid-Bugs-To:
POT-Creation-Date: 2010-05-26 22:02-0000
PO-Revision-Date: 2010-05-27 15:01-0000
Last-Translator: Satoshi Nakamoto
Language-Team:
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Poedit-KeywordsList: _;gettext;gettext_noop
X-Poedit-Basepath: .
X-Poedit-SearchPath-0: ../../..
Connessione in corso... %d connessioni %d blocchi %d trasferimenti Generando &Copia nella Clipboard &Nuovo indirizzo... &Nuovo... &Porta: (vostro) (vostro, label: &Rubrica degli indirizzi... Tutte In lavorazione Ricevuto Inviato Standard il costo trasferimento è incluso %d conferme%d/fuorilinea?%d/non confermato&Info...&Quantità&Accetta%Connesso attraverso proxy socks4: &Cancella&Cambia...&File&Proveniente da:&Genera monete&Aiuto&Limita la generazione moneta a&Messaggio:&Minimizza se chiuso&Minimizza nella tray invece che nella barra&Apri Bitcoin&Opzioni...&Incolla&InviaI&mpostazioniA&vvia Bitcoin all'avvio del sistema&Il tuo indirizzo di ricezione...(%s matureranno in %d altri blocchi)(non accettato)(non connesso), diffusione attraverso %d nodo, diffusione attraverso %d nodi, non è ancora stato diffuso correttamente<b>Credito:</b> <b>Data:</b> <b>Debito:</b> <b>Da:</b> <b>Quantità del network:</b> <b>Sorgente:</b> Generato<br><b>Stato:</b> <b>A:</b> <b>Trasferimento costo:</b> Info BitcoinAggiungi indirizzoAggiungi un nodo a cui connetterti
IndirizzoRubrica indirizziTutte le operazioniL'ammontare è andato oltre i tuoi capitali Capitali:BitcoinBitcoin Bitcoin - (non connesso)Bitcoin - GenerandoIndirizzo BitcoinCANCELLATONon si può includere un messaggio quando si invia attraverso l'indirizzo BitcoinCancellaCancellatoImpossibile connettersi al nodo specificato
Connetti attraverso proxy socks4
Connessione in corso...Copyright (c) 2009-2010 Satoshi Nakamoto.
Questo è un software sperimentale. Non affidartici per gli attuali trasferimenti finanziari.
Distribuito sotto la licenza software MIT/X11, guarda il file license.txt incluso oppure su http://www.opensource.org/licenses/mit-license.php.
Questo prodoto include software sviluppato dal progetto OpenSSL per l'uso del
(http://www.openssl.org/) e il software criptografico scritto da
Eric Young (eay@cryptsoft.com).Creazione trasferimento...CreditoDataDebitoDescrizioneNon generare monete
E&sciModifica indirizzoModifica spazio indirizzoInserisci un indirizzo Bitcoin (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) o un indirizzo IP (e.g. 123.45.6.7)Errore nell'ammontare Errore nel caricare addr.dat
Errore nel caricare blkindex.dat
Errore nel caricare wallet.dat
Errore: Errore: Il trasferimento è stato respinto. Questo può accadere se alcune delle monete nel tuo portafoglio erano già state spese, o anche se hai usato una copia di wallet.dat e le monete erano già state spese nella copia originale ma non segnate in quest'ultima.Errore: Questa è un operazione fuoriscala che richiede un sovrapprezzo di %s Errore: La creazione del trasferimento è fallito Da: Da: sconosciuto, Ricevuto con: Genera monete
GeneratoGenerate (%s matureranno in %d altri blocchi)Generato (non accettato)Generato - Attenzione: Questo blocco non è stato ricevuto da nessun altro nodo e probabilmente non sarà accettato!Le monete generate devono aspettare 120 blocchi prima di poter essere spese. Quando hai generato questo blocco, è stato diffuso sul network per essere aggiunto alla catena dei blocchi. Se fallirà l'entrata nella catena, cambierà in "non accettato" e non spendibile. Questo può capitare se un altro nodo genera un blocco pochi secondi prima del tuo.Fondi insufficentiIndirizzo proxy non validoIndirizzo non valido Quantità non validaIndirizzo bitcoin non validoRisposta non valida ricevutaE' una buona abitudine usare un nuovo indirizzo per ogni pagamento che ricevuto.
LabelLabelConnessione persa, trasferimento cancellatoM&inimizza nella tray alla chiusuraPrincipaleMessaggio:NomeNuovo indirizzo riceventeO&pzioni...OKAperto per %d blocchiAperto fino a %sCosto aggiuntivo opzionale che tu dai ai nodi che realizzano i tuoi trasferimentiOpzioniOpzioni:
Paga %a:Pagamento completatoPagamento inviato Pagamento a te stessoIl pagamento è stato inviato, ma è arrivata un risposta invalidaIl programma è crashato e sarà terminato. Proxy &IP:RicevutoRicezione chiave pubblica...RicevendoRichiesta chiave pubblica...Invia moneteInviandoInviando %s a %sInviando pagamento...Inviando...InviatoInviato/RicevutoIndica la cartella per i dati
Avvia minimizzato
StatoT&rasferimento:Il pagamento è inviato, ma il ricevente non è stato in grado di verificarlo.
Il trasferimento è registrato e costerà sarà accreditato al ricevente,
ma il commento verrà mostrato come vuoto.Il trasferimento è stato respinto. Questo può accadere se alcune delle monete nel tuo portafoglio erano già state spese, o anche se hai usato una copia di wallet.dat e le monete erano già state spese nella copia originale ma non segnate in quest'ultima.Questi sono i tuoi indirizzi Bitcoin per ricevere pagamenti. Potrai darne uno diverso ad ognuno per cosi tenere traccia di chi ti sta pagando. L'indirizzo selezionato sarà quello mostrato nella finestra principale.Questi sono i tuoi indirizzi Bitcoin per ricevere pagamenti. Potrai darne uno diverso ad ognuno per cosi tenere traccia di chi ti sta pagando. L'indirizzo selezionato sarà quello mostrato nella finestra principale.Questo messaggio di aiuto
Questo è un trasferimento fuoriscala che richiede un costo aggiuntivo di %sQuesto qui è uno dei tuoi indirizzi personali per ricevere pagamenti e non può essere inserito nella rubrica indirizzi. Questo trasferimento è oltre le dimensioni massime. Puoi comunque inviarlo per un costo aggiuntivo di %s, che andrà ai nodi che effettueranno il processo della tua operazione e che supportano il network. Vuoi pagare il costo aggiuntivo?A: Il totale va oltre i tuoi capitali quando il Dettagli operazioneTrasferimento bloccatoCreazione trasferimento fallitaCosto trasferimento:Operazione cancellata Trasferimento non accettatoImpossibile connettersiUso: bitcoin [options]In attesa di conferma...Attenzione: c'è poco spazio sul disco Apparirà come "Da: Sconosciuto"Il tuo indirizzo Bitcoin:Il tuo indirizzo Bitcoinprocessorisconoscutoversioneversione 0.%d.%d beta
"%file: ./locale/it/LC_MESSAGES/bitcoin.po"
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-05-26 22:02-0000\n"
"PO-Revision-Date: 2010-05-27 13:01+0100\n"
"Last-Translator: Franco Cimatti <hostfat@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-SearchPath-0: ../../..\n"
#: ../../../init.cpp:342
msgid "Usage: bitcoin [options]"
msgstr "Uso: bitcoin [options]"
#: ../../../init.cpp:343
msgid "Options:\n"
msgstr "Opzioni:\n"
#: ../../../init.cpp:344
msgid "Generate coins\n"
msgstr "Genera monete\n"
#: ../../../init.cpp:345
msgid "Don't generate coins\n"
msgstr "Non generare monete\n"
#: ../../../init.cpp:346
msgid "Start minimized\n"
msgstr "Avvia minimizzato\n"
#: ../../../init.cpp:347
msgid "Specify data directory\n"
msgstr "Indica la cartella per i dati\n"
#: ../../../init.cpp:348
msgid "Connect through socks4 proxy\n"
msgstr "Connetti attraverso proxy socks4\n"
#: ../../../init.cpp:349
msgid "Add a node to connect to\n"
msgstr "Aggiungi un nodo a cui connetterti\n"
#: ../../../init.cpp:350
msgid "Connect only to the specified node\n"
msgstr "Impossibile connettersi al nodo specificato\n"
#: ../../../init.cpp:351
msgid "This help message\n"
msgstr "Questo messaggio di aiuto\n"
#: ../../../init.cpp:455
msgid "Error loading addr.dat \n"
msgstr "Errore nel caricare addr.dat \n"
#: ../../../init.cpp:461
msgid "Error loading blkindex.dat \n"
msgstr "Errore nel caricare blkindex.dat \n"
#: ../../../init.cpp:468
msgid "Error loading wallet.dat \n"
msgstr "Errore nel caricare wallet.dat \n"
#: ../../../init.cpp:536
msgid "Invalid -proxy address"
msgstr "Indirizzo proxy non valido"
#: ../../../init.cpp:629
msgid "Program has crashed and will terminate. "
msgstr "Il programma è crashato e sarà terminato. "
#: ../../../main.cpp:1465
msgid "Warning: Disk space is low "
msgstr "Attenzione: c'è poco spazio sul disco "
#: ../../../main.cpp:2994
#, c-format
msgid "Error: This is an oversized transaction that requires a transaction fee of %s "
msgstr "Errore: Questa è un operazione fuoriscala che richiede un sovrapprezzo di %s "
#: ../../../main.cpp:2996
msgid "Error: Transaction creation failed "
msgstr "Errore: La creazione del trasferimento è fallito "
#: ../../../main.cpp:3001
#: ../../../ui.cpp:1761
#: ../../../ui.cpp:1763
#: ../../../ui.cpp:1904
#: ../../../ui.cpp:2053
msgid "Sending..."
msgstr "Inviando..."
#: ../../../main.cpp:3005
msgid "Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."
msgstr "Errore: Il trasferimento è stato respinto. Questo può accadere se alcune delle monete nel tuo portafoglio erano già state spese, o anche se hai usato una copia di wallet.dat e le monete erano già state spese nella copia originale ma non segnate in quest'ultima."
#: ../../../main.cpp:3017
msgid "Invalid amount"
msgstr "Quantità non valida"
#: ../../../main.cpp:3019
#: ../../../ui.cpp:1971
#: ../../../ui.cpp:2038
msgid "Insufficient funds"
msgstr "Fondi insufficenti"
#: ../../../main.cpp:3024
msgid "Invalid bitcoin address"
msgstr "Indirizzo bitcoin non valido"
#: ../../../ui.cpp:189
#, c-format
msgid "This transaction is over the size limit. You can still send it for a fee of %s, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?"
msgstr "Questo trasferimento è oltre le dimensioni massime. Puoi comunque inviarlo per un costo aggiuntivo di %s, che andrà ai nodi che effettueranno il processo della tua operazione e che supportano il network. Vuoi pagare il costo aggiuntivo?"
#: ../../../ui.cpp:285
msgid "Status"
msgstr "Stato"
#: ../../../ui.cpp:286
msgid "Date"
msgstr "Data"
#: ../../../ui.cpp:287
msgid "Description"
msgstr "Descrizione"
#: ../../../ui.cpp:288
msgid "Debit"
msgstr "Debito"
#: ../../../ui.cpp:289
msgid "Credit"
msgstr "Credito"
#: ../../../ui.cpp:489
#, c-format
msgid "Open for %d blocks"
msgstr "Aperto per %d blocchi"
#: ../../../ui.cpp:491
#, c-format
msgid "Open until %s"
msgstr "Aperto fino a %s"
#: ../../../ui.cpp:497
#, c-format
msgid "%d/offline?"
msgstr "%d/fuorilinea?"
#: ../../../ui.cpp:499
#, c-format
msgid "%d/unconfirmed"
msgstr "%d/non confermato"
#: ../../../ui.cpp:501
#, c-format
msgid "%d confirmations"
msgstr "%d conferme"
#: ../../../ui.cpp:584
msgid "Generated"
msgstr "Generato"
#: ../../../ui.cpp:592
#, c-format
msgid "Generated (%s matures in %d more blocks)"
msgstr "Generate (%s matureranno in %d altri blocchi)"
#: ../../../ui.cpp:596
msgid "Generated - Warning: This block was not received by any other nodes and will probably not be accepted!"
msgstr "Generato - Attenzione: Questo blocco non è stato ricevuto da nessun altro nodo e probabilmente non sarà accettato!"
#: ../../../ui.cpp:600
msgid "Generated (not accepted)"
msgstr "Generato (non accettato)"
#: ../../../ui.cpp:610
msgid "From: "
msgstr "Da: "
#: ../../../ui.cpp:634
msgid "From: unknown, Received with: "
msgstr "Da: sconosciuto, Ricevuto con: "
#: ../../../ui.cpp:676
msgid "Payment to yourself"
msgstr "Pagamento a te stesso"
#: ../../../ui.cpp:713
msgid "To: "
msgstr "A: "
#: ../../../ui.cpp:1009
msgid " Generating"
msgstr " Generando"
#: ../../../ui.cpp:1011
msgid "(not connected)"
msgstr "(non connesso)"
#: ../../../ui.cpp:1014
#, c-format
msgid " %d connections %d blocks %d transactions"
msgstr " %d connessioni %d blocchi %d trasferimenti"
#: ../../../ui.cpp:1123
#: ../../../ui.cpp:2351
msgid "New Receiving Address"
msgstr "Nuovo indirizzo ricevente"
#: ../../../ui.cpp:1124
#: ../../../ui.cpp:2352
msgid ""
"It's good policy to use a new address for each payment you receive.\n"
"\n"
"Label"
msgstr ""
"E' una buona abitudine usare un nuovo indirizzo per ogni pagamento che ricevuto.\n"
"\n"
"Label"
#: ../../../ui.cpp:1193
msgid "<b>Status:</b> "
msgstr "<b>Stato:</b> "
#: ../../../ui.cpp:1198
msgid ", has not been successfully broadcast yet"
msgstr ", non è ancora stato diffuso correttamente"
#: ../../../ui.cpp:1200
#, c-format
msgid ", broadcast through %d node"
msgstr ", diffusione attraverso %d nodo"
#: ../../../ui.cpp:1202
#, c-format
msgid ", broadcast through %d nodes"
msgstr ", diffusione attraverso %d nodi"
#: ../../../ui.cpp:1206
msgid "<b>Date:</b> "
msgstr "<b>Data:</b> "
#: ../../../ui.cpp:1214
msgid "<b>Source:</b> Generated<br>"
msgstr "<b>Sorgente:</b> Generato<br>"
#: ../../../ui.cpp:1220
#: ../../../ui.cpp:1238
msgid "<b>From:</b> "
msgstr "<b>Da:</b> "
#: ../../../ui.cpp:1238
msgid "unknown"
msgstr "sconoscuto"
#: ../../../ui.cpp:1239
#: ../../../ui.cpp:1263
#: ../../../ui.cpp:1322
msgid "<b>To:</b> "
msgstr "<b>A:</b> "
#: ../../../ui.cpp:1242
msgid " (yours, label: "
msgstr " (vostro, label: "
#: ../../../ui.cpp:1244
msgid " (yours)"
msgstr " (vostro)"
#: ../../../ui.cpp:1281
#: ../../../ui.cpp:1293
#: ../../../ui.cpp:1356
msgid "<b>Credit:</b> "
msgstr "<b>Credito:</b> "
#: ../../../ui.cpp:1283
#, c-format
msgid "(%s matures in %d more blocks)"
msgstr "(%s matureranno in %d altri blocchi)"
#: ../../../ui.cpp:1285
msgid "(not accepted)"
msgstr "(non accettato)"
#: ../../../ui.cpp:1330
#: ../../../ui.cpp:1353
msgid "<b>Debit:</b> "
msgstr "<b>Debito:</b> "
#: ../../../ui.cpp:1344
msgid "<b>Transaction fee:</b> "
msgstr "<b>Trasferimento costo:</b> "
#: ../../../ui.cpp:1360
msgid "<b>Net amount:</b> "
msgstr "<b>Quantità del network:</b> "
#: ../../../ui.cpp:1367
msgid "Message:"
msgstr "Messaggio:"
#: ../../../ui.cpp:1370
msgid "Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours."
msgstr "Le monete generate devono aspettare 120 blocchi prima di poter essere spese. Quando hai generato questo blocco, è stato diffuso sul network per essere aggiunto alla catena dei blocchi. Se fallirà l'entrata nella catena, cambierà in \"non accettato\" e non spendibile. Questo può capitare se un altro nodo genera un blocco pochi secondi prima del tuo."
#: ../../../ui.cpp:1437
msgid "Main"
msgstr "Principale"
#: ../../../ui.cpp:1442
msgid "&Minimize on close"
msgstr "&Minimizza se chiuso"
#: ../../../ui.cpp:1595
#, c-format
msgid "version 0.%d.%d beta"
msgstr "versione 0.%d.%d beta"
#: ../../../ui.cpp:1681
msgid "Will appear as \"From: Unknown\""
msgstr "Apparirà come \"Da: Sconosciuto\""
#: ../../../ui.cpp:1682
msgid "Can't include a message when sending to a Bitcoin address"
msgstr "Non si può includere un messaggio quando si invia attraverso l'indirizzo Bitcoin"
#: ../../../ui.cpp:1735
msgid "Error in amount "
msgstr "Errore nell'ammontare "
#: ../../../ui.cpp:1735
#: ../../../ui.cpp:1740
#: ../../../ui.cpp:1745
#: ../../../ui.cpp:1771
#: ../../../uibase.cpp:61
msgid "Send Coins"
msgstr "Invia monete"
#: ../../../ui.cpp:1740
msgid "Amount exceeds your balance "
msgstr "L'ammontare è andato oltre i tuoi capitali "
#: ../../../ui.cpp:1745
msgid "Total exceeds your balance when the "
msgstr "Il totale va oltre i tuoi capitali quando il "
#: ../../../ui.cpp:1745
msgid " transaction fee is included "
msgstr " il costo trasferimento è incluso "
#: ../../../ui.cpp:1761
msgid "Payment sent "
msgstr "Pagamento inviato "
#: ../../../ui.cpp:1771
msgid "Invalid address "
msgstr "Indirizzo non valido "
#: ../../../ui.cpp:1825
#, c-format
msgid "Sending %s to %s"
msgstr "Inviando %s a %s"
#: ../../../ui.cpp:1898
#: ../../../ui.cpp:1931
msgid "CANCELLED"
msgstr "CANCELLATO"
#: ../../../ui.cpp:1902
msgid "Cancelled"
msgstr "Cancellato"
#: ../../../ui.cpp:1904
msgid "Transfer cancelled "
msgstr "Operazione cancellata "
#: ../../../ui.cpp:1957
msgid "Error: "
msgstr "Errore: "
#: ../../../ui.cpp:1976
msgid "Connecting..."
msgstr "Connessione in corso..."
#: ../../../ui.cpp:1981
msgid "Unable to connect"
msgstr "Impossibile connettersi"
#: ../../../ui.cpp:1986
msgid "Requesting public key..."
msgstr "Richiesta chiave pubblica..."
#: ../../../ui.cpp:1998
msgid "Received public key..."
msgstr "Ricezione chiave pubblica..."
#: ../../../ui.cpp:2010
msgid "Transfer was not accepted"
msgstr "Trasferimento non accettato"
#: ../../../ui.cpp:2019
msgid "Invalid response received"
msgstr "Risposta non valida ricevuta"
#: ../../../ui.cpp:2034
msgid "Creating transaction..."
msgstr "Creazione trasferimento..."
#: ../../../ui.cpp:2046
#, c-format
msgid "This is an oversized transaction that requires a transaction fee of %s"
msgstr "Questo è un trasferimento fuoriscala che richiede un costo aggiuntivo di %s"
#: ../../../ui.cpp:2048
msgid "Transaction creation failed"
msgstr "Creazione trasferimento fallita"
#: ../../../ui.cpp:2055
msgid "Transaction aborted"
msgstr "Trasferimento bloccato"
#: ../../../ui.cpp:2063
msgid "Lost connection, transaction cancelled"
msgstr "Connessione persa, trasferimento cancellato"
#: ../../../ui.cpp:2079
msgid "Sending payment..."
msgstr "Inviando pagamento..."
#: ../../../ui.cpp:2085
msgid "The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."
msgstr "Il trasferimento è stato respinto. Questo può accadere se alcune delle monete nel tuo portafoglio erano già state spese, o anche se hai usato una copia di wallet.dat e le monete erano già state spese nella copia originale ma non segnate in quest'ultima."
#: ../../../ui.cpp:2092
msgid "Waiting for confirmation..."
msgstr "In attesa di conferma..."
#: ../../../ui.cpp:2110
msgid ""
"The payment was sent, but the recipient was unable to verify it.\n"
"The transaction is recorded and will credit to the recipient,\n"
"but the comment information will be blank."
msgstr ""
"Il pagamento è inviato, ma il ricevente non è stato in grado di verificarlo.\n"
"Il trasferimento è registrato e costerà sarà accreditato al ricevente,\n"
"ma il commento verrà mostrato come vuoto."
#: ../../../ui.cpp:2119
msgid "Payment was sent, but an invalid response was received"
msgstr "Il pagamento è stato inviato, ma è arrivata un risposta invalida"
#: ../../../ui.cpp:2125
msgid "Payment completed"
msgstr "Pagamento completato"
#: ../../../ui.cpp:2156
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2339
msgid "Name"
msgstr "Nome"
#: ../../../ui.cpp:2157
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2339
msgid "Address"
msgstr "Indirizzo"
#: ../../../ui.cpp:2159
#: ../../../ui.cpp:2314
msgid "Label"
msgstr "Label"
#: ../../../ui.cpp:2160
#: ../../../uibase.cpp:908
msgid "Bitcoin Address"
msgstr "Indirizzo Bitcoin"
#: ../../../ui.cpp:2284
msgid "This is one of your own addresses for receiving payments and cannot be entered in the address book. "
msgstr "Questo qui è uno dei tuoi indirizzi personali per ricevere pagamenti e non può essere inserito nella rubrica indirizzi. "
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2308
msgid "Edit Address"
msgstr "Modifica indirizzo"
#: ../../../ui.cpp:2314
msgid "Edit Address Label"
msgstr "Modifica spazio indirizzo"
#: ../../../ui.cpp:2339
#: ../../../ui.cpp:2345
msgid "Add Address"
msgstr "Aggiungi indirizzo"
#: ../../../ui.cpp:2421
msgid "Bitcoin"
msgstr "Bitcoin"
#: ../../../ui.cpp:2423
msgid "Bitcoin - Generating"
msgstr "Bitcoin - Generando"
#: ../../../ui.cpp:2425
msgid "Bitcoin - (not connected)"
msgstr "Bitcoin - (non connesso)"
#: ../../../ui.cpp:2500
msgid "&Open Bitcoin"
msgstr "&Apri Bitcoin"
#: ../../../ui.cpp:2501
msgid "O&ptions..."
msgstr "O&pzioni..."
#: ../../../ui.cpp:2502
#: ../../../uibase.cpp:34
msgid "&Generate Coins"
msgstr "&Genera monete"
#: ../../../ui.cpp:2505
#: ../../../uibase.cpp:27
msgid "E&xit"
msgstr "E&sci"
#: ../../../uibase.cpp:30
msgid "&File"
msgstr "&File"
#: ../../../uibase.cpp:38
msgid "&Your Receiving Addresses..."
msgstr "&Il tuo indirizzo di ricezione..."
#: ../../../uibase.cpp:42
msgid "&Options..."
msgstr "&Opzioni..."
#: ../../../uibase.cpp:45
msgid "&Settings"
msgstr "I&mpostazioni"
#: ../../../uibase.cpp:49
msgid "&About..."
msgstr "&Info..."
#: ../../../uibase.cpp:52
msgid "&Help"
msgstr "&Aiuto"
#: ../../../uibase.cpp:62
msgid "Address Book"
msgstr "Rubrica indirizzi"
#: ../../../uibase.cpp:77
msgid "Your Bitcoin Address:"
msgstr "Il tuo indirizzo Bitcoin:"
#: ../../../uibase.cpp:84
msgid " &New... "
msgstr " &Nuovo... "
#: ../../../uibase.cpp:87
#: ../../../uibase.cpp:851
#: ../../../uibase.cpp:954
msgid " &Copy to Clipboard "
msgstr " &Copia nella Clipboard "
#: ../../../uibase.cpp:102
msgid "Balance:"
msgstr "Capitali:"
#: ../../../uibase.cpp:121
msgid " All"
msgstr " Tutte"
#: ../../../uibase.cpp:121
msgid " Sent"
msgstr " Inviato"
#: ../../../uibase.cpp:121
msgid " Received"
msgstr " Ricevuto"
#: ../../../uibase.cpp:121
msgid " In Progress"
msgstr " In lavorazione"
#: ../../../uibase.cpp:142
msgid "All Transactions"
msgstr "Tutte le operazioni"
#: ../../../uibase.cpp:153
msgid "Sent/Received"
msgstr "Inviato/Ricevuto"
#: ../../../uibase.cpp:164
msgid "Sent"
msgstr "Inviato"
#: ../../../uibase.cpp:175
msgid "Received"
msgstr "Ricevuto"
#: ../../../uibase.cpp:318
#: ../../../uibase.cpp:479
#: ../../../uibase.cpp:580
#: ../../../uibase.cpp:793
#: ../../../uibase.cpp:854
#: ../../../uibase.cpp:963
#: ../../../uibase.cpp:1052
msgid "OK"
msgstr "OK"
#: ../../../uibase.cpp:361
msgid "Optional transaction fee you give to the nodes that process your transactions."
msgstr "Costo aggiuntivo opzionale che tu dai ai nodi che realizzano i tuoi trasferimenti"
#: ../../../uibase.cpp:370
msgid "Transaction fee:"
msgstr "Costo trasferimento:"
#: ../../../uibase.cpp:386
msgid "&Limit coin generation to"
msgstr "&Limita la generazione moneta a"
#: ../../../uibase.cpp:393
msgid "processors"
msgstr "processori"
#: ../../../uibase.cpp:399
msgid "&Start Bitcoin on system startup"
msgstr "A&vvia Bitcoin all'avvio del sistema"
#: ../../../uibase.cpp:403
msgid "&Minimize to the tray instead of the taskbar"
msgstr "&Minimizza nella tray invece che nella barra"
#: ../../../uibase.cpp:407
msgid "M&inimize to the tray on close"
msgstr "M&inimizza nella tray alla chiusura"
#: ../../../uibase.cpp:414
msgid "&Connect through socks4 proxy: "
msgstr "%Connesso attraverso proxy socks4: "
#: ../../../uibase.cpp:426
msgid "Proxy &IP:"
msgstr "Proxy &IP:"
#: ../../../uibase.cpp:434
msgid " &Port:"
msgstr " &Porta:"
#: ../../../uibase.cpp:456
msgid "// [don't translate] Test panel 2 for future expansion"
msgstr ""
#: ../../../uibase.cpp:460
msgid "// [don't translate] Let's not start multiple pages until the first page is filled up"
msgstr ""
#: ../../../uibase.cpp:482
#: ../../../uibase.cpp:735
#: ../../../uibase.cpp:798
#: ../../../uibase.cpp:857
#: ../../../uibase.cpp:966
#: ../../../uibase.cpp:1055
msgid "Cancel"
msgstr "Cancella"
#: ../../../uibase.cpp:485
msgid "&Apply"
msgstr "&Accetta"
#: ../../../uibase.cpp:546
msgid "Bitcoin "
msgstr "Bitcoin "
#: ../../../uibase.cpp:552
msgid "version"
msgstr "versione"
#: ../../../uibase.cpp:563
msgid ""
"Copyright (c) 2009-2010 Satoshi Nakamoto.\n"
"\n"
"This is experimental software. Do not rely on it for actual financial transactions.\n"
"\n"
"Distributed under the MIT/X11 software license, see the accompanying file \n"
"license.txt or http://www.opensource.org/licenses/mit-license.php.\n"
"\n"
"This product includes software developed by the OpenSSL Project for use in the \n"
"OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by \n"
"Eric Young (eay@cryptsoft.com)."
msgstr ""
"Copyright (c) 2009-2010 Satoshi Nakamoto.\n"
"\n"
"Questo è un software sperimentale. Non affidartici per gli attuali trasferimenti finanziari.\n"
"\n"
"Distribuito sotto la licenza software MIT/X11, guarda il file license.txt incluso oppure su http://www.opensource.org/licenses/mit-license.php.\n"
"\n"
"Questo prodoto include software sviluppato dal progetto OpenSSL per l'uso del \n"
"(http://www.openssl.org/) e il software criptografico scritto da \n"
"Eric Young (eay@cryptsoft.com)."
#: ../../../uibase.cpp:619
msgid "Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)"
msgstr "Inserisci un indirizzo Bitcoin (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) o un indirizzo IP (e.g. 123.45.6.7)"
#: ../../../uibase.cpp:633
msgid "Pay &To:"
msgstr "Paga %a:"
#: ../../../uibase.cpp:648
msgid "&Paste"
msgstr "&Incolla"
#: ../../../uibase.cpp:651
msgid " Address &Book..."
msgstr " &Rubrica degli indirizzi..."
#: ../../../uibase.cpp:658
msgid "&Amount:"
msgstr "&Quantità"
#: ../../../uibase.cpp:668
msgid "T&ransfer:"
msgstr "T&rasferimento:"
#: ../../../uibase.cpp:674
msgid " Standard"
msgstr " Standard"
#: ../../../uibase.cpp:696
msgid "&From:"
msgstr "&Proveniente da:"
#: ../../../uibase.cpp:713
msgid "&Message:"
msgstr "&Messaggio:"
#: ../../../uibase.cpp:730
msgid "&Send"
msgstr "&Invia"
#: ../../../uibase.cpp:782
msgid ""
"\n"
"\n"
"Connecting..."
msgstr ""
"\n"
"\n"
"Connessione in corso..."
#: ../../../uibase.cpp:832
msgid "These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window."
msgstr "Questi sono i tuoi indirizzi Bitcoin per ricevere pagamenti. Potrai darne uno diverso ad ognuno per cosi tenere traccia di chi ti sta pagando. L'indirizzo selezionato sarà quello mostrato nella finestra principale."
#: ../../../uibase.cpp:845
#: ../../../uibase.cpp:957
msgid "&Edit..."
msgstr "&Cambia..."
#: ../../../uibase.cpp:848
#: ../../../uibase.cpp:960
msgid " &New Address... "
msgstr " &Nuovo indirizzo... "
#: ../../../uibase.cpp:920
msgid "Sending"
msgstr "Inviando"
#: ../../../uibase.cpp:928
msgid "These are your Bitcoin addresses for receiving payments. You can give a different one to each sender to keep track of who is paying you. The highlighted address will be displayed in the main window."
msgstr "Questi sono i tuoi indirizzi Bitcoin per ricevere pagamenti. Potrai darne uno diverso ad ognuno per cosi tenere traccia di chi ti sta pagando. L'indirizzo selezionato sarà quello mostrato nella finestra principale."
#: ../../../uibase.cpp:941
msgid "Receiving"
msgstr "Ricevendo"
#: ../../../uibase.cpp:951
msgid "&Delete"
msgstr "&Cancella"
#: ../../../uibase.h:150
msgid "Transaction Details"
msgstr "Dettagli operazione"
#: ../../../uibase.h:203
msgid "Options"
msgstr "Opzioni"
#: ../../../uibase.h:231
msgid "About Bitcoin"
msgstr "Info Bitcoin"
#: ../../../uibase.h:341
msgid "Your Bitcoin Addresses"
msgstr "Il tuo indirizzo Bitcoin"
"%file: ./locale/nl/LC_MESSAGES/bitcoin.mo"
Þ•¥Dßl
èé5ù/>S eow‰ Ž ›¥ «µÔ åñ 
:BKQXhn ˆ’,¥Ò àìó ù $A`o›)¸âðþ/ ?Kd r~˜  ­¾Üåíö% 59?y €#Š®ÌÐÚ«Ã ÈÔê ðýar„!¢Ää×ìOÄ$9@_ o(y¢f»X"{Ž¥·ÆÞJøC&Ip”¢ ¸ÄÇÚNè7 ?IRds6‡)¾
èóü 
6AIZ
mx}‹£´
»©ÆÐpÈAÓ
FÞe% ŋ Q!$V!{!!£!¿!Ð!å!ÿ!"-"J"i""
–"¡"©"±"lÆ"3$6B$y$‡$¡$ ±$½$Æ$Ù$à$
ï$
ú$
%!%2% C%O%a%j%
x%ƒ%
Ÿ%
ª%µ%¾%Ä%Ô%Ú% ÷%&2&Q&
_&j& s&}&*Œ&·&!Ï&ñ&''-'2F'y' ˆ'•'«'È'Ø'æ' ÿ' ('(D(J(X()i(“(›(£(¬(Ç(Û( é(>õ(4) =)I)h) ‚)é)y+‘+ —+¤+
¹+ Ä+Ñ+vä+[,*q,.œ,,Ë,ø,Þÿ,FÞ-"%.H.N.m. }.-‰.·.x×.wP/È0Ú0ï0ÿ01$1J?1Š1+1&¼1ã1 é1õ1ú1222 12M=2‹2’2›2©2»2Ð2?å2,%3
R3 ]3g3 …3!3±3 À3Ê3ß3 ù3 44$4:4Q4 X4·e4Ø5Ôö5êË6E¶7xü7¾u849.;9j9}9”9°9Á9Ú9÷9
:'$:!L:n:‚:
–:¡:ª:±:q9p7%F¡i[~}2^.Žo$:Kveh;{*AŒ†–wHs¤u„] /ZE‹n…Bx—g?‘4-mW”Yc'>ž˜ =ˆœŠV€5D_br,d£šO
N|R‰T’ƒ!#al¢`fP)¥k0GtXL@6 SJ•yI™ C“& 81‡U(3jMz"Ÿ+Q\‚›<
Connecting... %d connections %d blocks %d transactions Generating &Copy to Clipboard &New Address... &New... &Port: Address &Book... All In Progress Received Sent Standard transaction fee is included %d confirmations%d/offline?%d/unconfirmed&About...&Amount:&Apply&Connect through socks4 proxy: &Delete&Edit...&File&From:&Generate Coins&Help&Limit coin generation to&Message:&Minimize on close&Minimize to the tray instead of the taskbar&Open Bitcoin&Options...&Paste&Send&Settings&Start Bitcoin on system startup&Your Receiving Addresses...(%s matures in %d more blocks)(not accepted)(not connected), broadcast through %d node, broadcast through %d nodes, has not been successfully broadcast yet<b>Date:</b> <b>From:</b> <b>Net amount:</b> <b>Source:</b> Generated<br><b>Status:</b> <b>To:</b> <b>Transaction fee:</b> About BitcoinAdd AddressAdd a node to connect to
AddressAddress BookAll TransactionsAmount exceeds your balance Balance:BitcoinBitcoin Bitcoin - (not connected)Bitcoin - GeneratingBitcoin AddressCANCELLEDCan't include a message when sending to a Bitcoin addressCancelCancelledConnect only to the specified node
Connect through socks4 proxy
Connecting...Copyright (c) 2009-2010 Satoshi Nakamoto.
This is experimental software. Do not rely on it for actual financial transactions.
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/) and cryptographic software written by
Eric Young (eay@cryptsoft.com).Creating transaction...DateDescriptionDon't generate coins
E&xitEdit AddressEdit Address LabelEnter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)Error in amount Error loading addr.dat
Error loading blkindex.dat
Error loading wallet.dat
Error: Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.Error: This is an oversized transaction that requires a transaction fee of %s Error: Transaction creation failed From: From: unknown, Received with: Generate coins
GeneratedGenerated (%s matures in %d more blocks)Generated (not accepted)Generated - Warning: This block was not received by any other nodes and will probably not be accepted!Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to "not accepted" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.Insufficient fundsInvalid -proxy addressInvalid address Invalid amountInvalid bitcoin addressInvalid response receivedIt's good policy to use a new address for each payment you receive.
LabelLabelLost connection, transaction cancelledM&inimize to the tray on closeMainMessage:NameNew Receiving AddressO&ptions...OKOpen for %d blocksOpen until %sOptional transaction fee you give to the nodes that process your transactions.OptionsOptions:
Pay &To:Payment completedPayment sent Payment to yourselfPayment was sent, but an invalid response was receivedProgram has crashed and will terminate. Proxy &IP:ReceivedReceived public key...ReceivingRequesting public key...Send CoinsSendingSending %s to %sSending payment...Sending...SentSent/ReceivedSpecify data directory
Start minimized
StatusT&ransfer:The payment was sent, but the recipient was unable to verify it.
The transaction is recorded and will credit to the recipient,
but the comment information will be blank.The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.These are your Bitcoin addresses for receiving payments. You can give a different one to each sender to keep track of who is paying you. The highlighted address will be displayed in the main window.These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window.This is an oversized transaction that requires a transaction fee of %sThis is one of your own addresses for receiving payments and cannot be entered in the address book. This transaction is over the size limit. You can still send it for a fee of %s, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?To: Total exceeds your balance when the Transaction DetailsTransaction abortedTransaction creation failedTransaction fee:Transfer cancelled Transfer was not acceptedUnable to connectWaiting for confirmation...Warning: Disk space is low Will appear as "From: Unknown"Your Bitcoin Address:Your Bitcoin Addressesprocessorsunknownversionversion 0.%d.%d betaProject-Id-Version:
Report-Msgid-Bugs-To:
POT-Creation-Date: 2010-05-26 22:02-0000
PO-Revision-Date: 2010-06-02 22:57-0000
Last-Translator: Satoshi Nakamoto
Language-Team:
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Poedit-KeywordsList: _;gettext;gettext_noop
X-Poedit-Basepath: .
X-Poedit-SearchPath-0: ../../..
Verbinden... %d verbindingen %d blokken %d transacties Genereert &Kopieer naar Plakboord &New Adres... &Nieuw... &Poort: Adressen &Boek... Alles Word Verwerkt Ontvangen Verstuurd Standaard transactie fooi is bijgerekend %d bevestigingen%d/offline?%d/niet bevestigd&Over...&Hoeveelheid:&Toepassen&Verbind via socks4 proxy: &Verwijder&Bewerk...&Bestand&Van:&Genereer Coins&Help&Limiteer coin generatie tot&Mededeling:&Minimalizeer bij sluiten&Minimalizeer tot systeemvak inplaats van taakbalk&Open Bitcoin&Opties...&Plakken&Verstuur&Eigenschappen&Start Bitcoin wanneer het systeem opstart&Uw Ontvang Adressen...(%s word volwassen in %d blokken)(niet geaccepteerd(niet verbonden), verstuurd via %d node, verstuurd via %d nodes, is nog niet succesvol verstuurd naar het netwerk<b>Datum:</b> <b>Van:</b> <b>Netto bedrag:</b> <b>Bron:</b> Gegenereerd<br><b>Status:</b> <b>Naar:</b> <b>Transactie fooi:</b> Over BitcoinAdres ToevoegenVoeg een node om naar te verbinden toe
AdresAdressen BoekAlle transactiesHoeveelheid hoger dan uw huidige balans Balans:BitcoinBitcoin Bitcoin - (niet verbonden)Bitcoin - GenereertBitcoin AdresGEANNULEERDKan geen mededeling versturen bij gebruik van Bitcoin adressenAnnuleerGeannuleerdVerbind alleen naar deze node
Verbind via socks4 proxy
Verbinden...Copyright (c) 2009-2010 Satoshi Nakamoto.
Dit is experimentele software. Vertrouw niet op het voor echte financiele transacties.
Gedistributeerd onder de MIT/X11 software licentie, see het bijbehorende bestand
license.txt of "http://www.opensource.org/licenses/mit-license.php.
Dit product komt met software ontwikkeld door het OpenSSL Project for gebruik in de
OpenSSL Toolkit (http://www.openssl.org/) and de cryptografische software geschreven door
Eric Young (eay@cryptsoft.com).Maakt transactie aan...DatumBeschrijvingGenereer geen coins
A&fsluitenBewerk AdresBewerk Adres LabelVoer een Bitcoin adres (bijvoorbeeld: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) of IP address (bijvoorbeeld: 123.45.6.7) in.Fout in hoeveelheid Fout bij laden van bestand addr.dat
Fout bij laden van bestand blkindex.dat
Fout bij laden van bestand wallet.dat
Fout: Fout: De transactie was afgekeurd. Dit kan komen als bepaalde coins in uw Portefeuille al zijn uitgegeven. Dit kan komen doordat u wallet.dat heeft gekopieerd en wat coins heeft uitgegeven en niet terug gekopieerd heeft.Fout: Dit is een te grote transactie die een fooi nodig heeft van %s Fout: Transactie aanmaak gefaald Van: Van: onbekend, Ontvangen met: Genereer coins
GegenereerdGegenereerd (%s word volwassen in %d blokken)Gegenereerd (niet geaccepteerd)Gegenereerd - Waarschuwing: Dit blok is niet ontvangen door andere nodes en zal waarschijnlijk niet geaccepteerd worden!Gegenereerde coins moeten 120 blokken wachten voordat ze uitgegeven kunnen worden. Wanneer je dit blok genereerde, werd het naar het netwerk gestuurd om opgenomen teworden in de rest van de blokken. Als dit faalt, dan zal de dit veranderen in "niet geaccepteerd" en zal niet uitgeefbaar zijn. Dit kan soms gebeuren als een node ook een blok rond dezelfde periode genereerd.Onvoldoende coinsFoutief -proxy adresFoutief adres Foutief aantalFoutief bitcoin adresFoutief antwoord ontvangenHet is goed beleid om een nieuw adres voor elke betaling te hebben.
LabelLabelVerbinding verloren, transactie geannuleerdM&inimalizeer tot taakbalk bij sluitenHoofdMededeling:NaamNieuw Ontvangings AdresO&ptiesOKOpen voor %d blocksOpen tot %sOptionele transactie fooi die u geeft aan de nodes doe uw betaling verwerken.OptiesOpties:
Betaal &Naar:Betaling voltooidBetaling verstuurd Betaling naar u zelfBetaling was verstuurd, maar een foutief antword was ontvangen.Programma is gecrashed en word afgesloten. Proxy &IP:OntvangenPublieke sleutel ontvangen...OntvangenAanvragen van publieke sleutel...Verstuur CoinsVersturenVerstuurd %s naar %sVersturen van betaling...Versturen...VerstuurdVerstuurd/OntvangenSpecificeer data map
Start geminimalizeerd
StatusO&verdracht:De betaling was verstuurd, maar de ontvanger kon het niet verifieeren.
De transactie is opgenomen en word uitbetaald aan de ontvanger,
maar de mededeling blijft blank bij de ontanger.De transactie was afgekeurd. Dit kan komen als bepaalde coins in uw Portefeuille al zijn uitgegeven. Dit kan komen doordat u wallet.dat heeft gekopieerd en wat coins heeft uitgegeven en niet terug gekopieerd heeft.Dit zijn uw Bitcoin adressen voor het ontvangen van betalingen. U kunt een aan elk contact persoon geven zodat u een overzicht kunt houden wie u betaald. Dit adres zal wergeven worden in het hoofd main venster.Dit zijn uw Bitcoin Adressen voor het ontvangen van betalingen. Misschien wilt u elk contact persoon een ander adres geven zodat u kunt bij houden wie er u heeft betaald. De opgelichte adressen worden weergeven in het hoofd venster.Dit is een te grote transactie die een transactie fooi vereist van %sDit is een van uw eigen adressen voor het ontvangen van betalingen en can niet worden toegevoegd aan uw adressen boek. Deze transactie is over het limiet. U kunt nog door gaan met de transactie door een fooi te betalen van %s, deze word betaald aan de node die uw tranactie verwerkt. Wilt u de fooi betalen?Naar: Totaal groter dan uw huidige balans wanner de Transactie DetailsTransactie geannuleerdTransactie aanmaak gefaald.Transactie fooi:Transactie geannuleerd Transactie niet geaccepteerdKan niet verbindenWachten op bevestiging...Waarschuwng: Gebrek aan schijf ruimte Word vertoont als "Van: Onbekend"Uw Bitcoin Address:Uw Bitcoin Adressenprocessorsonbekendversieversie 0.%d.%d beta
"%file: ./locale/nl/LC_MESSAGES/bitcoin.po"
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-05-26 22:02-0000\n"
"PO-Revision-Date: 2010-05-27 19:27+0100\n"
"Last-Translator: Xunie\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-KeywordsList: _;gettext;gettext_noop\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-SearchPath-0: ../../..\n"
#: ../../../init.cpp:342
msgid "Usage: bitcoin [options]"
msgstr ""
#: ../../../init.cpp:343
msgid "Options:\n"
msgstr "Opties:\n"
#: ../../../init.cpp:344
msgid "Generate coins\n"
msgstr "Genereer coins\n"
#: ../../../init.cpp:345
msgid "Don't generate coins\n"
msgstr "Genereer geen coins\n"
#: ../../../init.cpp:346
msgid "Start minimized\n"
msgstr "Start geminimalizeerd\n"
#: ../../../init.cpp:347
msgid "Specify data directory\n"
msgstr "Specificeer data map\n"
#: ../../../init.cpp:348
msgid "Connect through socks4 proxy\n"
msgstr "Verbind via socks4 proxy\n"
#: ../../../init.cpp:349
msgid "Add a node to connect to\n"
msgstr "Voeg een node om naar te verbinden toe\n"
#: ../../../init.cpp:350
msgid "Connect only to the specified node\n"
msgstr "Verbind alleen naar deze node\n"
#: ../../../init.cpp:351
msgid "This help message\n"
msgstr ""
#: ../../../init.cpp:455
msgid "Error loading addr.dat \n"
msgstr "Fout bij laden van bestand addr.dat \n"
#: ../../../init.cpp:461
msgid "Error loading blkindex.dat \n"
msgstr "Fout bij laden van bestand blkindex.dat \n"
#: ../../../init.cpp:468
msgid "Error loading wallet.dat \n"
msgstr "Fout bij laden van bestand wallet.dat \n"
#: ../../../init.cpp:536
msgid "Invalid -proxy address"
msgstr "Foutief -proxy adres"
#: ../../../init.cpp:629
msgid "Program has crashed and will terminate. "
msgstr "Programma is gecrashed en word afgesloten. "
#: ../../../main.cpp:1465
msgid "Warning: Disk space is low "
msgstr "Waarschuwng: Gebrek aan schijf ruimte "
#: ../../../main.cpp:2994
#, c-format
msgid "Error: This is an oversized transaction that requires a transaction fee of %s "
msgstr "Fout: Dit is een te grote transactie die een fooi nodig heeft van %s "
#: ../../../main.cpp:2996
msgid "Error: Transaction creation failed "
msgstr "Fout: Transactie aanmaak gefaald "
#: ../../../main.cpp:3001
#: ../../../ui.cpp:1761
#: ../../../ui.cpp:1763
#: ../../../ui.cpp:1904
#: ../../../ui.cpp:2053
msgid "Sending..."
msgstr "Versturen..."
#: ../../../main.cpp:3005
msgid "Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."
msgstr "Fout: De transactie was afgekeurd. Dit kan komen als bepaalde coins in uw Portefeuille al zijn uitgegeven. Dit kan komen doordat u wallet.dat heeft gekopieerd en wat coins heeft uitgegeven en niet terug gekopieerd heeft."
#: ../../../main.cpp:3017
msgid "Invalid amount"
msgstr "Foutief aantal"
#: ../../../main.cpp:3019
#: ../../../ui.cpp:1971
#: ../../../ui.cpp:2038
msgid "Insufficient funds"
msgstr "Onvoldoende coins"
#: ../../../main.cpp:3024
msgid "Invalid bitcoin address"
msgstr "Foutief bitcoin adres"
#: ../../../ui.cpp:189
#, c-format
msgid "This transaction is over the size limit. You can still send it for a fee of %s, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?"
msgstr "Deze transactie is over het limiet. U kunt nog door gaan met de transactie door een fooi te betalen van %s, deze word betaald aan de node die uw tranactie verwerkt. Wilt u de fooi betalen?"
#: ../../../ui.cpp:285
msgid "Status"
msgstr "Status"
#: ../../../ui.cpp:286
msgid "Date"
msgstr "Datum"
#: ../../../ui.cpp:287
msgid "Description"
msgstr "Beschrijving"
#: ../../../ui.cpp:288
msgid "Debit"
msgstr ""
#: ../../../ui.cpp:289
msgid "Credit"
msgstr ""
#: ../../../ui.cpp:489
#, c-format
msgid "Open for %d blocks"
msgstr "Open voor %d blocks"
#: ../../../ui.cpp:491
#, c-format
msgid "Open until %s"
msgstr "Open tot %s"
#: ../../../ui.cpp:497
#, c-format
msgid "%d/offline?"
msgstr "%d/offline?"
#: ../../../ui.cpp:499
#, c-format
msgid "%d/unconfirmed"
msgstr "%d/niet bevestigd"
#: ../../../ui.cpp:501
#, c-format
msgid "%d confirmations"
msgstr "%d bevestigingen"
#: ../../../ui.cpp:584
msgid "Generated"
msgstr "Gegenereerd"
#: ../../../ui.cpp:592
#, c-format
msgid "Generated (%s matures in %d more blocks)"
msgstr "Gegenereerd (%s word volwassen in %d blokken)"
#: ../../../ui.cpp:596
msgid "Generated - Warning: This block was not received by any other nodes and will probably not be accepted!"
msgstr "Gegenereerd - Waarschuwing: Dit blok is niet ontvangen door andere nodes en zal waarschijnlijk niet geaccepteerd worden!"
#: ../../../ui.cpp:600
msgid "Generated (not accepted)"
msgstr "Gegenereerd (niet geaccepteerd)"
#: ../../../ui.cpp:610
msgid "From: "
msgstr "Van: "
#: ../../../ui.cpp:634
msgid "From: unknown, Received with: "
msgstr "Van: onbekend, Ontvangen met: "
#: ../../../ui.cpp:676
msgid "Payment to yourself"
msgstr "Betaling naar u zelf"
#: ../../../ui.cpp:713
msgid "To: "
msgstr "Naar: "
#: ../../../ui.cpp:1009
msgid " Generating"
msgstr " Genereert"
#: ../../../ui.cpp:1011
msgid "(not connected)"
msgstr "(niet verbonden)"
#: ../../../ui.cpp:1014
#, c-format
msgid " %d connections %d blocks %d transactions"
msgstr " %d verbindingen %d blokken %d transacties"
#: ../../../ui.cpp:1123
#: ../../../ui.cpp:2351
msgid "New Receiving Address"
msgstr "Nieuw Ontvangings Adres"
#: ../../../ui.cpp:1124
#: ../../../ui.cpp:2352
msgid ""
"It's good policy to use a new address for each payment you receive.\n"
"\n"
"Label"
msgstr ""
"Het is goed beleid om een nieuw adres voor elke betaling te hebben.\n"
"\n"
"Label"
#: ../../../ui.cpp:1193
msgid "<b>Status:</b> "
msgstr "<b>Status:</b> "
#: ../../../ui.cpp:1198
msgid ", has not been successfully broadcast yet"
msgstr ", is nog niet succesvol verstuurd naar het netwerk"
#: ../../../ui.cpp:1200
#, c-format
msgid ", broadcast through %d node"
msgstr ", verstuurd via %d node"
#: ../../../ui.cpp:1202
#, c-format
msgid ", broadcast through %d nodes"
msgstr ", verstuurd via %d nodes"
#: ../../../ui.cpp:1206
msgid "<b>Date:</b> "
msgstr "<b>Datum:</b> "
#: ../../../ui.cpp:1214
msgid "<b>Source:</b> Generated<br>"
msgstr "<b>Bron:</b> Gegenereerd<br>"
#: ../../../ui.cpp:1220
#: ../../../ui.cpp:1238
msgid "<b>From:</b> "
msgstr "<b>Van:</b> "
#: ../../../ui.cpp:1238
msgid "unknown"
msgstr "onbekend"
#: ../../../ui.cpp:1239
#: ../../../ui.cpp:1263
#: ../../../ui.cpp:1322
msgid "<b>To:</b> "
msgstr "<b>Naar:</b> "
#: ../../../ui.cpp:1242
msgid " (yours, label: "
msgstr ""
#: ../../../ui.cpp:1244
#, fuzzy
msgid " (yours)"
msgstr ""
#: ../../../ui.cpp:1281
#: ../../../ui.cpp:1293
#: ../../../ui.cpp:1356
msgid "<b>Credit:</b> "
msgstr ""
#: ../../../ui.cpp:1283
#, c-format
msgid "(%s matures in %d more blocks)"
msgstr "(%s word volwassen in %d blokken)"
#: ../../../ui.cpp:1285
msgid "(not accepted)"
msgstr "(niet geaccepteerd"
#: ../../../ui.cpp:1330
#: ../../../ui.cpp:1353
msgid "<b>Debit:</b> "
msgstr ""
#: ../../../ui.cpp:1344
msgid "<b>Transaction fee:</b> "
msgstr "<b>Transactie fooi:</b> "
#: ../../../ui.cpp:1360
msgid "<b>Net amount:</b> "
msgstr "<b>Netto bedrag:</b> "
#: ../../../ui.cpp:1367
msgid "Message:"
msgstr "Mededeling:"
#: ../../../ui.cpp:1370
msgid "Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours."
msgstr "Gegenereerde coins moeten 120 blokken wachten voordat ze uitgegeven kunnen worden. Wanneer je dit blok genereerde, werd het naar het netwerk gestuurd om opgenomen teworden in de rest van de blokken. Als dit faalt, dan zal de dit veranderen in \"niet geaccepteerd\" en zal niet uitgeefbaar zijn. Dit kan soms gebeuren als een node ook een blok rond dezelfde periode genereerd."
#: ../../../ui.cpp:1437
msgid "Main"
msgstr "Hoofd"
#: ../../../ui.cpp:1442
msgid "&Minimize on close"
msgstr "&Minimalizeer bij sluiten"
#: ../../../ui.cpp:1595
#, c-format
msgid "version 0.%d.%d beta"
msgstr "versie 0.%d.%d beta"
#: ../../../ui.cpp:1681
msgid "Will appear as \"From: Unknown\""
msgstr "Word vertoont als \"Van: Onbekend\""
#: ../../../ui.cpp:1682
msgid "Can't include a message when sending to a Bitcoin address"
msgstr "Kan geen mededeling versturen bij gebruik van Bitcoin adressen"
#: ../../../ui.cpp:1735
msgid "Error in amount "
msgstr "Fout in hoeveelheid "
#: ../../../ui.cpp:1735
#: ../../../ui.cpp:1740
#: ../../../ui.cpp:1745
#: ../../../ui.cpp:1771
#: ../../../uibase.cpp:61
msgid "Send Coins"
msgstr "Verstuur Coins"
#: ../../../ui.cpp:1740
msgid "Amount exceeds your balance "
msgstr "Hoeveelheid hoger dan uw huidige balans "
#: ../../../ui.cpp:1745
msgid "Total exceeds your balance when the "
msgstr "Totaal groter dan uw huidige balans wanner de "
#: ../../../ui.cpp:1745
msgid " transaction fee is included "
msgstr " transactie fooi is bijgerekend "
#: ../../../ui.cpp:1761
msgid "Payment sent "
msgstr "Betaling verstuurd "
#: ../../../ui.cpp:1771
msgid "Invalid address "
msgstr "Foutief adres "
#: ../../../ui.cpp:1825
#, c-format
msgid "Sending %s to %s"
msgstr "Verstuurd %s naar %s"
#: ../../../ui.cpp:1898
#: ../../../ui.cpp:1931
msgid "CANCELLED"
msgstr "GEANNULEERD"
#: ../../../ui.cpp:1902
msgid "Cancelled"
msgstr "Geannuleerd"
#: ../../../ui.cpp:1904
msgid "Transfer cancelled "
msgstr "Transactie geannuleerd "
#: ../../../ui.cpp:1957
msgid "Error: "
msgstr "Fout: "
#: ../../../ui.cpp:1976
msgid "Connecting..."
msgstr "Verbinden..."
#: ../../../ui.cpp:1981
msgid "Unable to connect"
msgstr "Kan niet verbinden"
#: ../../../ui.cpp:1986
msgid "Requesting public key..."
msgstr "Aanvragen van publieke sleutel..."
#: ../../../ui.cpp:1998
msgid "Received public key..."
msgstr "Publieke sleutel ontvangen..."
#: ../../../ui.cpp:2010
msgid "Transfer was not accepted"
msgstr "Transactie niet geaccepteerd"
#: ../../../ui.cpp:2019
msgid "Invalid response received"
msgstr "Foutief antwoord ontvangen"
#: ../../../ui.cpp:2034
msgid "Creating transaction..."
msgstr "Maakt transactie aan..."
#: ../../../ui.cpp:2046
#, c-format
msgid "This is an oversized transaction that requires a transaction fee of %s"
msgstr "Dit is een te grote transactie die een transactie fooi vereist van %s"
#: ../../../ui.cpp:2048
msgid "Transaction creation failed"
msgstr "Transactie aanmaak gefaald."
#: ../../../ui.cpp:2055
msgid "Transaction aborted"
msgstr "Transactie geannuleerd"
#: ../../../ui.cpp:2063
msgid "Lost connection, transaction cancelled"
msgstr "Verbinding verloren, transactie geannuleerd"
#: ../../../ui.cpp:2079
msgid "Sending payment..."
msgstr "Versturen van betaling..."
#: ../../../ui.cpp:2085
msgid "The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."
msgstr "De transactie was afgekeurd. Dit kan komen als bepaalde coins in uw Portefeuille al zijn uitgegeven. Dit kan komen doordat u wallet.dat heeft gekopieerd en wat coins heeft uitgegeven en niet terug gekopieerd heeft."
#: ../../../ui.cpp:2092
msgid "Waiting for confirmation..."
msgstr "Wachten op bevestiging..."
#: ../../../ui.cpp:2110
msgid ""
"The payment was sent, but the recipient was unable to verify it.\n"
"The transaction is recorded and will credit to the recipient,\n"
"but the comment information will be blank."
msgstr ""
"De betaling was verstuurd, maar de ontvanger kon het niet verifieeren.\n"
"De transactie is opgenomen en word uitbetaald aan de ontvanger,\n"
"maar de mededeling blijft blank bij de ontanger."
#: ../../../ui.cpp:2119
msgid "Payment was sent, but an invalid response was received"
msgstr "Betaling was verstuurd, maar een foutief antword was ontvangen."
#: ../../../ui.cpp:2125
msgid "Payment completed"
msgstr "Betaling voltooid"
#: ../../../ui.cpp:2156
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2339
msgid "Name"
msgstr "Naam"
#: ../../../ui.cpp:2157
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2339
msgid "Address"
msgstr "Adres"
#: ../../../ui.cpp:2159
#: ../../../ui.cpp:2314
msgid "Label"
msgstr "Label"
#: ../../../ui.cpp:2160
#: ../../../uibase.cpp:908
msgid "Bitcoin Address"
msgstr "Bitcoin Adres"
#: ../../../ui.cpp:2284
msgid "This is one of your own addresses for receiving payments and cannot be entered in the address book. "
msgstr "Dit is een van uw eigen adressen voor het ontvangen van betalingen en can niet worden toegevoegd aan uw adressen boek. "
#: ../../../ui.cpp:2302
#: ../../../ui.cpp:2308
msgid "Edit Address"
msgstr "Bewerk Adres"
#: ../../../ui.cpp:2314
msgid "Edit Address Label"
msgstr "Bewerk Adres Label"
#: ../../../ui.cpp:2339
#: ../../../ui.cpp:2345
msgid "Add Address"
msgstr "Adres Toevoegen"
#: ../../../ui.cpp:2421
msgid "Bitcoin"
msgstr "Bitcoin"
#: ../../../ui.cpp:2423
msgid "Bitcoin - Generating"
msgstr "Bitcoin - Genereert"
#: ../../../ui.cpp:2425
msgid "Bitcoin - (not connected)"
msgstr "Bitcoin - (niet verbonden)"
#: ../../../ui.cpp:2500
msgid "&Open Bitcoin"
msgstr "&Open Bitcoin"
#: ../../../ui.cpp:2501
msgid "O&ptions..."
msgstr "O&pties"
#: ../../../ui.cpp:2502
#: ../../../uibase.cpp:34
msgid "&Generate Coins"
msgstr "&Genereer Coins"
#: ../../../ui.cpp:2505
#: ../../../uibase.cpp:27
msgid "E&xit"
msgstr "A&fsluiten"
#: ../../../uibase.cpp:30
msgid "&File"
msgstr "&Bestand"
#: ../../../uibase.cpp:38
msgid "&Your Receiving Addresses..."
msgstr "&Uw Ontvang Adressen..."
#: ../../../uibase.cpp:42
msgid "&Options..."
msgstr "&Opties..."
#: ../../../uibase.cpp:45
msgid "&Settings"
msgstr "&Eigenschappen"
#: ../../../uibase.cpp:49
msgid "&About..."
msgstr "&Over..."
#: ../../../uibase.cpp:52
msgid "&Help"
msgstr "&Help"
#: ../../../uibase.cpp:62
msgid "Address Book"
msgstr "Adressen Boek"
#: ../../../uibase.cpp:77
msgid "Your Bitcoin Address:"
msgstr "Uw Bitcoin Address:"
#: ../../../uibase.cpp:84
msgid " &New... "
msgstr " &Nieuw... "
#: ../../../uibase.cpp:87
#: ../../../uibase.cpp:851
#: ../../../uibase.cpp:954
msgid " &Copy to Clipboard "
msgstr " &Kopieer naar Plakboord "
#: ../../../uibase.cpp:102
msgid "Balance:"
msgstr "Balans:"
#: ../../../uibase.cpp:121
msgid " All"
msgstr " Alles"
#: ../../../uibase.cpp:121
msgid " Sent"
msgstr " Verstuurd"
#: ../../../uibase.cpp:121
msgid " Received"
msgstr " Ontvangen"
#: ../../../uibase.cpp:121
msgid " In Progress"
msgstr " Word Verwerkt"
#: ../../../uibase.cpp:142
msgid "All Transactions"
msgstr "Alle transacties"
#: ../../../uibase.cpp:153
msgid "Sent/Received"
msgstr "Verstuurd/Ontvangen"
#: ../../../uibase.cpp:164
msgid "Sent"
msgstr "Verstuurd"
#: ../../../uibase.cpp:175
msgid "Received"
msgstr "Ontvangen"
#: ../../../uibase.cpp:318
#: ../../../uibase.cpp:479
#: ../../../uibase.cpp:580
#: ../../../uibase.cpp:793
#: ../../../uibase.cpp:854
#: ../../../uibase.cpp:963
#: ../../../uibase.cpp:1052
msgid "OK"
msgstr "OK"
#: ../../../uibase.cpp:361
msgid "Optional transaction fee you give to the nodes that process your transactions."
msgstr "Optionele transactie fooi die u geeft aan de nodes doe uw betaling verwerken."
#: ../../../uibase.cpp:370
msgid "Transaction fee:"
msgstr "Transactie fooi:"
#: ../../../uibase.cpp:386
msgid "&Limit coin generation to"
msgstr "&Limiteer coin generatie tot"
#: ../../../uibase.cpp:393
msgid "processors"
msgstr "processors"
#: ../../../uibase.cpp:399
msgid "&Start Bitcoin on system startup"
msgstr "&Start Bitcoin wanneer het systeem opstart"
#: ../../../uibase.cpp:403
msgid "&Minimize to the tray instead of the taskbar"
msgstr "&Minimalizeer tot systeemvak inplaats van taakbalk"
#: ../../../uibase.cpp:407
msgid "M&inimize to the tray on close"
msgstr "M&inimalizeer tot taakbalk bij sluiten"
#: ../../../uibase.cpp:414
msgid "&Connect through socks4 proxy: "
msgstr "&Verbind via socks4 proxy: "
#: ../../../uibase.cpp:426
msgid "Proxy &IP:"
msgstr "Proxy &IP:"
#: ../../../uibase.cpp:434
msgid " &Port:"
msgstr " &Poort:"
#: ../../../uibase.cpp:456
msgid "// [don't translate] Test panel 2 for future expansion"
msgstr ""
#: ../../../uibase.cpp:460
msgid "// [don't translate] Let's not start multiple pages until the first page is filled up"
msgstr ""
#: ../../../uibase.cpp:482
#: ../../../uibase.cpp:735
#: ../../../uibase.cpp:798
#: ../../../uibase.cpp:857
#: ../../../uibase.cpp:966
#: ../../../uibase.cpp:1055
msgid "Cancel"
msgstr "Annuleer"
#: ../../../uibase.cpp:485
msgid "&Apply"
msgstr "&Toepassen"
#: ../../../uibase.cpp:546
msgid "Bitcoin "
msgstr "Bitcoin "
#: ../../../uibase.cpp:552
msgid "version"
msgstr "versie"
#: ../../../uibase.cpp:563
msgid ""
"Copyright (c) 2009-2010 Satoshi Nakamoto.\n"
"\n"
"This is experimental software. Do not rely on it for actual financial transactions.\n"
"\n"
"Distributed under the MIT/X11 software license, see the accompanying file \n"
"license.txt or http://www.opensource.org/licenses/mit-license.php.\n"
"\n"
"This product includes software developed by the OpenSSL Project for use in the \n"
"OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by \n"
"Eric Young (eay@cryptsoft.com)."
msgstr ""
"Copyright (c) 2009-2010 Satoshi Nakamoto.\n"
"\n"
"Dit is experimentele software. Vertrouw niet op het voor echte financiele transacties.\n"
"\n"
"Gedistributeerd onder de MIT/X11 software licentie, see het bijbehorende bestand \n"
"license.txt of \"http://www.opensource.org/licenses/mit-license.php.\n"
"\n"
"Dit product komt met software ontwikkeld door het OpenSSL Project for gebruik in de\n"
"OpenSSL Toolkit (http://www.openssl.org/) and de cryptografische software geschreven door \n"
"Eric Young (eay@cryptsoft.com)."
#: ../../../uibase.cpp:619
msgid "Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)"
msgstr "Voer een Bitcoin adres (bijvoorbeeld: 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) of IP address (bijvoorbeeld: 123.45.6.7) in."
#: ../../../uibase.cpp:633
msgid "Pay &To:"
msgstr "Betaal &Naar:"
#: ../../../uibase.cpp:648
msgid "&Paste"
msgstr "&Plakken"
#: ../../../uibase.cpp:651
msgid " Address &Book..."
msgstr " Adressen &Boek..."
#: ../../../uibase.cpp:658
msgid "&Amount:"
msgstr "&Hoeveelheid:"
#: ../../../uibase.cpp:668
msgid "T&ransfer:"
msgstr "O&verdracht:"
#: ../../../uibase.cpp:674
msgid " Standard"
msgstr " Standaard"
#: ../../../uibase.cpp:696
msgid "&From:"
msgstr "&Van:"
#: ../../../uibase.cpp:713
msgid "&Message:"
msgstr "&Mededeling:"
#: ../../../uibase.cpp:730
msgid "&Send"
msgstr "&Verstuur"
#: ../../../uibase.cpp:782
msgid ""
"\n"
"\n"
"Connecting..."
msgstr ""
"\n"
"\n"
"Verbinden..."
#: ../../../uibase.cpp:832
msgid "These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window."
msgstr "Dit zijn uw Bitcoin Adressen voor het ontvangen van betalingen. Misschien wilt u elk contact persoon een ander adres geven zodat u kunt bij houden wie er u heeft betaald. De opgelichte adressen worden weergeven in het hoofd venster."
#: ../../../uibase.cpp:845
#: ../../../uibase.cpp:957
msgid "&Edit..."
msgstr "&Bewerk..."
#: ../../../uibase.cpp:848
#: ../../../uibase.cpp:960
msgid " &New Address... "
msgstr " &New Adres... "
#: ../../../uibase.cpp:920
msgid "Sending"
msgstr "Versturen"
#: ../../../uibase.cpp:928
msgid "These are your Bitcoin addresses for receiving payments. You can give a different one to each sender to keep track of who is paying you. The highlighted address will be displayed in the main window."
msgstr "Dit zijn uw Bitcoin adressen voor het ontvangen van betalingen. U kunt een aan elk contact persoon geven zodat u een overzicht kunt houden wie u betaald. Dit adres zal wergeven worden in het hoofd main venster."
#: ../../../uibase.cpp:941
msgid "Receiving"
msgstr "Ontvangen"
#: ../../../uibase.cpp:951
msgid "&Delete"
msgstr "&Verwijder"
#: ../../../uibase.h:150
msgid "Transaction Details"
msgstr "Transactie Details"
#: ../../../uibase.h:203
msgid "Options"
msgstr "Opties"
#: ../../../uibase.h:231
msgid "About Bitcoin"
msgstr "Over Bitcoin"
#: ../../../uibase.h:341
msgid "Your Bitcoin Addresses"
msgstr "Uw Bitcoin Adressen"
"%file: ./locale/readme.txt"
put bitcoin.po and bitcoin.mo files at:
locale/<langcode>/LC_MESSAGES/bitcoin.mo and .po
.po is the sourcefile
.mo is the compiled translation
"%file: ./main.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 COutPoint;
class CInPoint;
class CDiskTxPos;
class CCoinBase;
class CTxIn;
class CTxOut;
class CTransaction;
class CBlock;
class CBlockIndex;
class CWalletTx;
class CKeyItem;
static const unsigned int MAX_SIZE = 0x02000000;
static const int64 COIN = 100000000;
static const int64 CENT = 1000000;
static const int COINBASE_MATURITY = 100;
static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
extern CCriticalSection cs_main;
extern map<uint256, CBlockIndex*> mapBlockIndex;
extern const uint256 hashGenesisBlock;
extern CBlockIndex* pindexGenesisBlock;
extern int nBestHeight;
extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated;
extern map<uint256, int> mapRequestCount;
extern CCriticalSection cs_mapRequestCount;
extern map<string, string> mapAddressBook;
extern CCriticalSection cs_mapAddressBook;
extern vector<unsigned char> vchDefaultKey;
// Settings
extern int fGenerateBitcoins;
extern int64 nTransactionFee;
extern CAddress addrIncoming;
extern int fLimitProcessors;
extern int nLimitProcessors;
extern int fMinimizeToTray;
extern int fMinimizeOnClose;
bool CheckDiskSpace(int64 nAdditionalBytes=0);
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
FILE* AppendBlockFile(unsigned int& nFileRet);
bool AddKey(const CKey& key);
vector<unsigned char> GenerateNewKey();
bool AddToWallet(const CWalletTx& wtxIn);
void WalletUpdateSpent(const COutPoint& prevout);
void ReacceptWalletTransactions();
bool LoadBlockIndex(bool fAllowNew=true);
void PrintBlockTree();
bool ProcessMessages(CNode* pfrom);
bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv);
bool SendMessages(CNode* pto, bool fSendTrickle);
int64 GetBalance();
bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CKey& keyRet, int64& nFeeRequiredRet);
bool CommitTransaction(CWalletTx& wtxNew, const CKey& key);
bool BroadcastTransaction(CWalletTx& wtxNew);
string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
void GenerateBitcoins(bool fGenerate);
void ThreadBitcoinMiner(void* parg);
void BitcoinMiner();
class CDiskTxPos
{
public:
unsigned int nFile;
unsigned int nBlockPos;
unsigned int nTxPos;
CDiskTxPos()
{
SetNull();
}
CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn)
{
nFile = nFileIn;
nBlockPos = nBlockPosIn;
nTxPos = nTxPosIn;
}
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; }
bool IsNull() const { return (nFile == -1); }
friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b)
{
return (a.nFile == b.nFile &&
a.nBlockPos == b.nBlockPos &&
a.nTxPos == b.nTxPos);
}
friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b)
{
return !(a == b);
}
string ToString() const
{
if (IsNull())
return strprintf("null");
else
return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);
}
void print() const
{
printf("%s", ToString().c_str());
}
};
class CInPoint
{
public:
CTransaction* ptx;
unsigned int n;
CInPoint() { SetNull(); }
CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
void SetNull() { ptx = NULL; n = -1; }
bool IsNull() const { return (ptx == NULL && n == -1); }
};
class COutPoint
{
public:
uint256 hash;
unsigned int n;
COutPoint() { SetNull(); }
COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
void SetNull() { hash = 0; n = -1; }
bool IsNull() const { return (hash == 0 && n == -1); }
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
{
return (a.hash == b.hash && a.n == b.n);
}
friend bool operator!=(const COutPoint& a, const COutPoint& b)
{
return !(a == b);
}
string ToString() const
{
return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,6).c_str(), n);
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
//
// An input of a transaction. It contains the location of the previous
// transaction's output that it claims and a signature that matches the
// output's public key.
//
class CTxIn
{
public:
COutPoint prevout;
CScript scriptSig;
unsigned int nSequence;
CTxIn()
{
nSequence = UINT_MAX;
}
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX)
{
prevout = prevoutIn;
scriptSig = scriptSigIn;
nSequence = nSequenceIn;
}
CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX)
{
prevout = COutPoint(hashPrevTx, nOut);
scriptSig = scriptSigIn;
nSequence = nSequenceIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(prevout);
READWRITE(scriptSig);
READWRITE(nSequence);
)
bool IsFinal() const
{
return (nSequence == UINT_MAX);
}
friend bool operator==(const CTxIn& a, const CTxIn& b)
{
return (a.prevout == b.prevout &&
a.scriptSig == b.scriptSig &&
a.nSequence == b.nSequence);
}
friend bool operator!=(const CTxIn& a, const CTxIn& b)
{
return !(a == b);
}
string ToString() const
{
string str;
str += strprintf("CTxIn(");
str += prevout.ToString();
if (prevout.IsNull())
str += strprintf(", coinbase %s", HexStr(scriptSig.begin(), scriptSig.end(), false).c_str());
else
str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
if (nSequence != UINT_MAX)
str += strprintf(", nSequence=%u", nSequence);
str += ")";
return str;
}
void print() const
{
printf("%s\n", ToString().c_str());
}
bool IsMine() const;
int64 GetDebit() const;
};
//
// An output of a transaction. It contains the public key that the next input
// must be able to sign with to claim it.
//
class CTxOut
{
public:
int64 nValue;
CScript scriptPubKey;
public:
CTxOut()
{
SetNull();
}
CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
{
nValue = nValueIn;
scriptPubKey = scriptPubKeyIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(nValue);
READWRITE(scriptPubKey);
)
void SetNull()
{
nValue = -1;
scriptPubKey.clear();
}
bool IsNull()
{
return (nValue == -1);
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
bool IsMine() const
{
return ::IsMine(scriptPubKey);
}
int64 GetCredit() const
{
if (IsMine())
return nValue;
return 0;
}
friend bool operator==(const CTxOut& a, const CTxOut& b)
{
return (a.nValue == b.nValue &&
a.scriptPubKey == b.scriptPubKey);
}
friend bool operator!=(const CTxOut& a, const CTxOut& b)
{
return !(a == b);
}
string ToString() const
{
if (scriptPubKey.size() < 6)
return "CTxOut(error)";
return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,24).c_str());
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
//
// The basic transaction that is broadcasted on the network and contained in
// blocks. A transaction can contain multiple inputs and outputs.
//
class CTransaction
{
public:
int nVersion;
vector<CTxIn> vin;
vector<CTxOut> vout;
unsigned int nLockTime;
CTransaction()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(vin);
READWRITE(vout);
READWRITE(nLockTime);
)
void SetNull()
{
nVersion = 1;
vin.clear();
vout.clear();
nLockTime = 0;
}
bool IsNull() const
{
return (vin.empty() && vout.empty());
}
uint256 GetHash() const
{
return SerializeHash(*this);
}
bool IsFinal(int64 nBlockTime=0) const
{
// Time based nLockTime implemented in 0.1.6,
// do not use time based until most 0.1.5 nodes have upgraded.
if (nLockTime == 0)
return true;
if (nBlockTime == 0)
nBlockTime = GetAdjustedTime();
if (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime))
return true;
foreach(const CTxIn& txin, vin)
if (!txin.IsFinal())
return false;
return true;
}
bool IsNewerThan(const CTransaction& old) const
{
if (vin.size() != old.vin.size())
return false;
for (int i = 0; i < vin.size(); i++)
if (vin[i].prevout != old.vin[i].prevout)
return false;
bool fNewer = false;
unsigned int nLowest = UINT_MAX;
for (int i = 0; i < vin.size(); i++)
{
if (vin[i].nSequence != old.vin[i].nSequence)
{
if (vin[i].nSequence <= nLowest)
{
fNewer = false;
nLowest = vin[i].nSequence;
}
if (old.vin[i].nSequence < nLowest)
{
fNewer = true;
nLowest = old.vin[i].nSequence;
}
}
}
return fNewer;
}
bool IsCoinBase() const
{
return (vin.size() == 1 && vin[0].prevout.IsNull());
}
bool CheckTransaction() const
{
// Basic checks that don't depend on any context
if (vin.empty() || vout.empty())
return error("CTransaction::CheckTransaction() : vin or vout empty");
// Check for negative values
foreach(const CTxOut& txout, vout)
if (txout.nValue < 0)
return error("CTransaction::CheckTransaction() : txout.nValue negative");
if (IsCoinBase())
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
return error("CTransaction::CheckTransaction() : coinbase script size");
}
else
{
foreach(const CTxIn& txin, vin)
if (txin.prevout.IsNull())
return error("CTransaction::CheckTransaction() : prevout is null");
}
return true;
}
bool IsMine() const
{
foreach(const CTxOut& txout, vout)
if (txout.IsMine())
return true;
return false;
}
int64 GetDebit() const
{
int64 nDebit = 0;
foreach(const CTxIn& txin, vin)
nDebit += txin.GetDebit();
return nDebit;
}
int64 GetCredit() const
{
int64 nCredit = 0;
foreach(const CTxOut& txout, vout)
nCredit += txout.GetCredit();
return nCredit;
}
int64 GetValueOut() const
{
int64 nValueOut = 0;
foreach(const CTxOut& txout, vout)
{
if (txout.nValue < 0)
throw runtime_error("CTransaction::GetValueOut() : negative value");
nValueOut += txout.nValue;
}
return nValueOut;
}
int64 GetMinFee(unsigned int nBlockSize=1) const
{
// Base fee is 1 cent per kilobyte
unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
int64 nMinFee = (1 + (int64)nBytes / 1000) * CENT;
// Transactions under 60K are free as long as block size is under 80K
// (about 27,000bc if made of 50bc inputs)
if (nBytes < 60000 && nBlockSize < 80000)
nMinFee = 0;
// Transactions under 3K are free as long as block size is under 200K
if (nBytes < 3000 && nBlockSize < 200000)
nMinFee = 0;
// To limit dust spam, require a 0.01 fee if any output is less than 0.01
if (nMinFee < CENT)
foreach(const CTxOut& txout, vout)
if (txout.nValue < CENT)
nMinFee = CENT;
return nMinFee;
}
bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)
{
CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb");
if (!filein)
return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");
// Read transaction
if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
return error("CTransaction::ReadFromDisk() : fseek failed");
filein >> *this;
// Return file pointer
if (pfileRet)
{
if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
return error("CTransaction::ReadFromDisk() : second fseek failed");
*pfileRet = filein.release();
}
return true;
}
friend bool operator==(const CTransaction& a, const CTransaction& b)
{
return (a.nVersion == b.nVersion &&
a.vin == b.vin &&
a.vout == b.vout &&
a.nLockTime == b.nLockTime);
}
friend bool operator!=(const CTransaction& a, const CTransaction& b)
{
return !(a == b);
}
string ToString() const
{
string str;
str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
GetHash().ToString().substr(0,6).c_str(),
nVersion,
vin.size(),
vout.size(),
nLockTime);
for (int i = 0; i < vin.size(); i++)
str += " " + vin[i].ToString() + "\n";
for (int i = 0; i < vout.size(); i++)
str += " " + vout[i].ToString() + "\n";
return str;
}
void print() const
{
printf("%s", ToString().c_str());
}
bool DisconnectInputs(CTxDB& txdb);
bool ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx, int nHeight, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
bool ClientConnectInputs();
bool AcceptTransaction(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
bool AcceptTransaction(bool fCheckInputs=true, bool* pfMissingInputs=NULL)
{
CTxDB txdb("r");
return AcceptTransaction(txdb, fCheckInputs, pfMissingInputs);
}
protected:
bool AddToMemoryPool();
public:
bool RemoveFromMemoryPool();
};
//
// A transaction with a merkle branch linking it to the block chain
//
class CMerkleTx : public CTransaction
{
public:
uint256 hashBlock;
vector<uint256> vMerkleBranch;
int nIndex;
// memory only
mutable bool fMerkleVerified;
mutable bool fGetCreditCached;
mutable int64 nGetCreditCached;
CMerkleTx()
{
Init();
}
CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
{
Init();
}
void Init()
{
hashBlock = 0;
nIndex = -1;
fMerkleVerified = false;
fGetCreditCached = false;
nGetCreditCached = 0;
}
IMPLEMENT_SERIALIZE
(
nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
nVersion = this->nVersion;
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
)
int64 GetCredit(bool fUseCache=false) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
// GetBalance can assume transactions in mapWallet won't change
if (fUseCache && fGetCreditCached)
return nGetCreditCached;
nGetCreditCached = CTransaction::GetCredit();
fGetCreditCached = true;
return nGetCreditCached;
}
int SetMerkleBranch(const CBlock* pblock=NULL);
int GetDepthInMainChain(int& nHeightRet) const;
int GetDepthInMainChain() const { int nHeight; return GetDepthInMainChain(nHeight); }
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
int GetBlocksToMaturity() const;
bool AcceptTransaction(CTxDB& txdb, bool fCheckInputs=true);
bool AcceptTransaction() { CTxDB txdb("r"); return AcceptTransaction(txdb); }
};
//
// A transaction with a bunch of additional info that only the owner cares
// about. It includes any unrecorded transactions needed to link it back
// to the block chain.
//
class CWalletTx : public CMerkleTx
{
public:
vector<CMerkleTx> vtxPrev;
map<string, string> mapValue;
vector<pair<string, string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime;
unsigned int nTimeReceived; // time received by this node
char fFromMe;
char fSpent;
//// probably need to sign the order info so know it came from payer
// memory only UI hints
mutable unsigned int nTimeDisplayed;
mutable int nLinesDisplayed;
CWalletTx()
{
Init();
}
CWalletTx(const CMerkleTx& txIn) : CMerkleTx(txIn)
{
Init();
}
CWalletTx(const CTransaction& txIn) : CMerkleTx(txIn)
{
Init();
}
void Init()
{
fTimeReceivedIsTxTime = false;
nTimeReceived = 0;
fFromMe = false;
fSpent = false;
nTimeDisplayed = 0;
nLinesDisplayed = 0;
}
IMPLEMENT_SERIALIZE
(
nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action);
nVersion = this->nVersion;
READWRITE(vtxPrev);
READWRITE(mapValue);
READWRITE(vOrderForm);
READWRITE(fTimeReceivedIsTxTime);
READWRITE(nTimeReceived);
READWRITE(fFromMe);
READWRITE(fSpent);
)
bool WriteToDisk()
{
return CWalletDB().WriteTx(GetHash(), *this);
}
int64 GetTxTime() const;
int GetRequestCount() const;
void AddSupportingTransactions(CTxDB& txdb);
bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true);
bool AcceptWalletTransaction() { CTxDB txdb("r"); return AcceptWalletTransaction(txdb); }
void RelayWalletTransaction(CTxDB& txdb);
void RelayWalletTransaction() { CTxDB txdb("r"); RelayWalletTransaction(txdb); }
};
//
// A txdb record that contains the disk location of a transaction and the
// locations of transactions that spend its outputs. vSpent is really only
// used as a flag, but having the location is very helpful for debugging.
//
class CTxIndex
{
public:
CDiskTxPos pos;
vector<CDiskTxPos> vSpent;
CTxIndex()
{
SetNull();
}
CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs)
{
pos = posIn;
vSpent.resize(nOutputs);
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(pos);
READWRITE(vSpent);
)
void SetNull()
{
pos.SetNull();
vSpent.clear();
}
bool IsNull()
{
return pos.IsNull();
}
friend bool operator==(const CTxIndex& a, const CTxIndex& b)
{
if (a.pos != b.pos || a.vSpent.size() != b.vSpent.size())
return false;
for (int i = 0; i < a.vSpent.size(); i++)
if (a.vSpent[i] != b.vSpent[i])
return false;
return true;
}
friend bool operator!=(const CTxIndex& a, const CTxIndex& b)
{
return !(a == b);
}
};
//
// Nodes collect new transactions into a block, hash them into a hash tree,
// and scan through nonce values to make the block's hash satisfy proof-of-work
// requirements. When they solve the proof-of-work, they broadcast the block
// to everyone and the block is added to the block chain. The first transaction
// in the block is a special one that creates a new coin owned by the creator
// of the block.
//
// Blocks are appended to blk0001.dat files on disk. Their location on disk
// is indexed by CBlockIndex objects in memory.
//
class CBlock
{
public:
// header
int nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
// network and disk
vector<CTransaction> vtx;
// memory only
mutable vector<uint256> vMerkleTree;
CBlock()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
// ConnectBlock depends on vtx being last so it can calculate offset
if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))
READWRITE(vtx);
else if (fRead)
const_cast<CBlock*>(this)->vtx.clear();
)
void SetNull()
{
nVersion = 1;
hashPrevBlock = 0;
hashMerkleRoot = 0;
nTime = 0;
nBits = 0;
nNonce = 0;
vtx.clear();
vMerkleTree.clear();
}
bool IsNull() const
{
return (nBits == 0);
}
uint256 GetHash() const
{
return Hash(BEGIN(nVersion), END(nNonce));
}
uint256 BuildMerkleTree() const
{
vMerkleTree.clear();
foreach(const CTransaction& tx, vtx)
vMerkleTree.push_back(tx.GetHash());
int j = 0;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
for (int i = 0; i < nSize; i += 2)
{
int i2 = min(i+1, nSize-1);
vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
}
j += nSize;
}
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}
vector<uint256> GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())
BuildMerkleTree();
vector<uint256> vMerkleBranch;
int j = 0;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
int i = min(nIndex^1, nSize-1);
vMerkleBranch.push_back(vMerkleTree[j+i]);
nIndex >>= 1;
j += nSize;
}
return vMerkleBranch;
}
static uint256 CheckMerkleBranch(uint256 hash, const vector<uint256>& vMerkleBranch, int nIndex)
{
if (nIndex == -1)
return 0;
foreach(const uint256& otherside, vMerkleBranch)
{
if (nIndex & 1)
hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
else
hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
nIndex >>= 1;
}
return hash;
}
bool WriteToDisk(bool fWriteTransactions, unsigned int& nFileRet, unsigned int& nBlockPosRet)
{
// Open history file to append
CAutoFile fileout = AppendBlockFile(nFileRet);
if (!fileout)
return error("CBlock::WriteToDisk() : AppendBlockFile failed");
if (!fWriteTransactions)
fileout.nType |= SER_BLOCKHEADERONLY;
// Write index header
unsigned int nSize = fileout.GetSerializeSize(*this);
fileout << FLATDATA(pchMessageStart) << nSize;
// Write block
nBlockPosRet = ftell(fileout);
if (nBlockPosRet == -1)
return error("CBlock::WriteToDisk() : ftell failed");
fileout << *this;
// Flush stdio buffers and commit to disk before returning
fflush(fileout);
#ifdef __WXMSW__
_commit(_fileno(fileout));
#else
fsync(fileno(fileout));
#endif
return true;
}
bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true)
{
SetNull();
// Open history file to read
CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb");
if (!filein)
return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
if (!fReadTransactions)
filein.nType |= SER_BLOCKHEADERONLY;
// Read block
filein >> *this;
// Check the header
if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)
return error("CBlock::ReadFromDisk() : nBits errors in block header");
if (GetHash() > CBigNum().SetCompact(nBits).getuint256())
return error("CBlock::ReadFromDisk() : GetHash() errors in block header");
return true;
}
void print() const
{
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n",
GetHash().ToString().substr(0,16).c_str(),
nVersion,
hashPrevBlock.ToString().substr(0,16).c_str(),
hashMerkleRoot.ToString().substr(0,6).c_str(),
nTime, nBits, nNonce,
vtx.size());
for (int i = 0; i < vtx.size(); i++)
{
printf(" ");
vtx[i].print();
}
printf(" vMerkleTree: ");
for (int i = 0; i < vMerkleTree.size(); i++)
printf("%s ", vMerkleTree[i].ToString().substr(0,6).c_str());
printf("\n");
}
int64 GetBlockValue(int64 nFees) const;
bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions=true);
bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
bool CheckBlock() const;
bool AcceptBlock();
};
//
// The block chain is a tree shaped structure starting with the
// genesis block at the root, with each block potentially having multiple
// candidates to be the next block. pprev and pnext link a path through the
// main/longest chain. A blockindex may have multiple pprev pointing back
// to it, but pnext will only point forward to the longest branch, or will
// be null if the block is not part of the longest chain.
//
class CBlockIndex
{
public:
const uint256* phashBlock;
CBlockIndex* pprev;
CBlockIndex* pnext;
unsigned int nFile;
unsigned int nBlockPos;
int nHeight;
// block header
int nVersion;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
CBlockIndex()
{
phashBlock = NULL;
pprev = NULL;
pnext = NULL;
nFile = 0;
nBlockPos = 0;
nHeight = 0;
nVersion = 0;
hashMerkleRoot = 0;
nTime = 0;
nBits = 0;
nNonce = 0;
}
CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block)
{
phashBlock = NULL;
pprev = NULL;
pnext = NULL;
nFile = nFileIn;
nBlockPos = nBlockPosIn;
nHeight = 0;
nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot;
nTime = block.nTime;
nBits = block.nBits;
nNonce = block.nNonce;
}
uint256 GetBlockHash() const
{
return *phashBlock;
}
bool IsInMainChain() const
{
return (pnext || this == pindexBest);
}
bool EraseBlockFromDisk()
{
// Open history file
CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+");
if (!fileout)
return false;
// Overwrite with empty null block
CBlock block;
block.SetNull();
fileout << block;
return true;
}
enum { nMedianTimeSpan=11 };
int64 GetMedianTimePast() const
{
unsigned int pmedian[nMedianTimeSpan];
unsigned int* pbegin = &pmedian[nMedianTimeSpan];
unsigned int* pend = &pmedian[nMedianTimeSpan];
const CBlockIndex* pindex = this;
for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
*(--pbegin) = pindex->nTime;
sort(pbegin, pend);
return pbegin[(pend - pbegin)/2];
}
int64 GetMedianTime() const
{
const CBlockIndex* pindex = this;
for (int i = 0; i < nMedianTimeSpan/2; i++)
{
if (!pindex->pnext)
return nTime;
pindex = pindex->pnext;
}
return pindex->GetMedianTimePast();
}
string ToString() const
{
return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",
pprev, pnext, nFile, nBlockPos, nHeight,
hashMerkleRoot.ToString().substr(0,6).c_str(),
GetBlockHash().ToString().substr(0,16).c_str());
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
//
// Used to marshal pointers into hashes for db storage.
//
class CDiskBlockIndex : public CBlockIndex
{
public:
uint256 hashPrev;
uint256 hashNext;
CDiskBlockIndex()
{
hashPrev = 0;
hashNext = 0;
}
explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex)
{
hashPrev = (pprev ? pprev->GetBlockHash() : 0);
hashNext = (pnext ? pnext->GetBlockHash() : 0);
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(hashNext);
READWRITE(nFile);
READWRITE(nBlockPos);
READWRITE(nHeight);
// block header
READWRITE(this->nVersion);
READWRITE(hashPrev);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
)
uint256 GetBlockHash() const
{
CBlock block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
return block.GetHash();
}
string ToString() const
{
string str = "CDiskBlockIndex(";
str += CBlockIndex::ToString();
str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)",
GetBlockHash().ToString().c_str(),
hashPrev.ToString().substr(0,16).c_str(),
hashNext.ToString().substr(0,16).c_str());
return str;
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
//
// Describes a place in the block chain to another node such that if the
// other node doesn't have the same branch, it can find a recent common trunk.
// The further back it is, the further before the fork it may be.
//
class CBlockLocator
{
protected:
vector<uint256> vHave;
public:
CBlockLocator()
{
}
explicit CBlockLocator(const CBlockIndex* pindex)
{
Set(pindex);
}
explicit CBlockLocator(uint256 hashBlock)
{
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end())
Set((*mi).second);
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vHave);
)
void Set(const CBlockIndex* pindex)
{
vHave.clear();
int nStep = 1;
while (pindex)
{
vHave.push_back(pindex->GetBlockHash());
// Exponentially larger steps back
for (int i = 0; pindex && i < nStep; i++)
pindex = pindex->pprev;
if (vHave.size() > 10)
nStep *= 2;
}
vHave.push_back(hashGenesisBlock);
}
int GetDistanceBack()
{
// Retrace how far back it was in the sender's branch
int nDistance = 0;
int nStep = 1;
foreach(const uint256& hash, vHave)
{
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (pindex->IsInMainChain())
return nDistance;
}
nDistance += nStep;
if (nDistance > 10)
nStep *= 2;
}
return nDistance;
}
CBlockIndex* GetBlockIndex()
{
// Find the first block the caller has in the main chain
foreach(const uint256& hash, vHave)
{
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (pindex->IsInMainChain())
return pindex;
}
}
return pindexGenesisBlock;
}
uint256 GetBlockHash()
{
// Find the first block the caller has in the main chain
foreach(const uint256& hash, vHave)
{
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (pindex->IsInMainChain())
return hash;
}
}
return hashGenesisBlock;
}
int GetHeight()
{
CBlockIndex* pindex = GetBlockIndex();
if (!pindex)
return 0;
return pindex->nHeight;
}
};
//
// Private key that includes an expiration date in case it never gets used.
//
class CWalletKey
{
public:
CPrivKey vchPrivKey;
int64 nTimeCreated;
int64 nTimeExpires;
string strComment;
//// todo: add something to note what created it (user, getnewaddress, change)
//// maybe should have a map<string, string> property map
CWalletKey(int64 nTimeExpiresIn=0)
{
nTimeCreated = (nTimeExpiresIn ? GetTime() : 0);
nTimeExpires = nTimeExpiresIn;
}
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vchPrivKey);
READWRITE(nTimeCreated);
READWRITE(nTimeExpires);
READWRITE(strComment);
)
};
extern map<uint256, CTransaction> mapTransactions;
extern map<uint256, CWalletTx> mapWallet;
extern vector<uint256> vWalletUpdated;
extern CCriticalSection cs_mapWallet;
extern map<vector<unsigned char>, CPrivKey> mapKeys;
extern map<uint160, vector<unsigned char> > mapPubKeys;
extern CCriticalSection cs_mapKeys;
extern CKey keyUser;
"%file: ./main.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"
#include "sha.h"
//
// Global state
//
CCriticalSection cs_main;
map<uint256, CTransaction> mapTransactions;
CCriticalSection cs_mapTransactions;
unsigned int nTransactionsUpdated = 0;
map<COutPoint, CInPoint> mapNextTx;
map<uint256, CBlockIndex*> mapBlockIndex;
const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL;
int64 nTimeBestReceived = 0;
map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
map<uint256, CDataStream*> mapOrphanTransactions;
multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
map<uint256, CWalletTx> mapWallet;
vector<uint256> vWalletUpdated;
CCriticalSection cs_mapWallet;
map<vector<unsigned char>, CPrivKey> mapKeys;
map<uint160, vector<unsigned char> > mapPubKeys;
CCriticalSection cs_mapKeys;
CKey keyUser;
map<uint256, int> mapRequestCount;
CCriticalSection cs_mapRequestCount;
map<string, string> mapAddressBook;
CCriticalSection cs_mapAddressBook;
vector<unsigned char> vchDefaultKey;
// Settings
int fGenerateBitcoins = false;
int64 nTransactionFee = 0;
CAddress addrIncoming;
int fLimitProcessors = false;
int nLimitProcessors = 1;
int fMinimizeToTray = true;
int fMinimizeOnClose = true;
//////////////////////////////////////////////////////////////////////////////
//
// mapKeys
//
bool AddKey(const CKey& key)
{
CRITICAL_BLOCK(cs_mapKeys)
{
mapKeys[key.GetPubKey()] = key.GetPrivKey();
mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
}
return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey());
}
vector<unsigned char> GenerateNewKey()
{
CKey key;
key.MakeNewKey();
if (!AddKey(key))
throw runtime_error("GenerateNewKey() : AddKey failed\n");
return key.GetPubKey();
}
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
//
bool AddToWallet(const CWalletTx& wtxIn)
{
uint256 hash = wtxIn.GetHash();
CRITICAL_BLOCK(cs_mapWallet)
{
// Inserts only if not already there, returns tx inserted or tx found
pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
bool fInsertedNew = ret.second;
if (fInsertedNew)
wtx.nTimeReceived = GetAdjustedTime();
bool fUpdated = false;
if (!fInsertedNew)
{
// Merge
if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
{
wtx.hashBlock = wtxIn.hashBlock;
fUpdated = true;
}
if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
{
wtx.vMerkleBranch = wtxIn.vMerkleBranch;
wtx.nIndex = wtxIn.nIndex;
fUpdated = true;
}
if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
{
wtx.fFromMe = wtxIn.fFromMe;
fUpdated = true;
}
if (wtxIn.fSpent && wtxIn.fSpent != wtx.fSpent)
{
wtx.fSpent = wtxIn.fSpent;
fUpdated = true;
}
}
//// debug print
printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,6).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
// Write to disk
if (fInsertedNew || fUpdated)
if (!wtx.WriteToDisk())
return false;
// If default receiving address gets used, replace it with a new one
CScript scriptDefaultKey;
scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
foreach(const CTxOut& txout, wtx.vout)
{
if (txout.scriptPubKey == scriptDefaultKey)
{
CWalletDB walletdb;
walletdb.WriteDefaultKey(GenerateNewKey());
walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
}
}
// Notify UI
vWalletUpdated.push_back(hash);
}
// Refresh UI
MainFrameRepaint();
return true;
}
bool AddToWalletIfMine(const CTransaction& tx, const CBlock* pblock)
{
if (tx.IsMine() || mapWallet.count(tx.GetHash()))
{
CWalletTx wtx(tx);
// Get merkle branch if transaction was found in a block
if (pblock)
wtx.SetMerkleBranch(pblock);
return AddToWallet(wtx);
}
return true;
}
bool EraseFromWallet(uint256 hash)
{
CRITICAL_BLOCK(cs_mapWallet)
{
if (mapWallet.erase(hash))
CWalletDB().EraseTx(hash);
}
return true;
}
void WalletUpdateSpent(const COutPoint& prevout)
{
// Anytime a signature is successfully verified, it's proof the outpoint is spent.
// Update the wallet spent flag if it doesn't know due to wallet.dat being
// restored from backup or the user making copies of wallet.dat.
CRITICAL_BLOCK(cs_mapWallet)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
if (mi != mapWallet.end())
{
CWalletTx& wtx = (*mi).second;
if (!wtx.fSpent && wtx.vout[prevout.n].IsMine())
{
printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
wtx.fSpent = true;
wtx.WriteToDisk();
vWalletUpdated.push_back(prevout.hash);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
//
void AddOrphanTx(const CDataStream& vMsg)
{
CTransaction tx;
CDataStream(vMsg) >> tx;
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
return;
CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
foreach(const CTxIn& txin, tx.vin)
mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
}
void EraseOrphanTx(uint256 hash)
{
if (!mapOrphanTransactions.count(hash))
return;
const CDataStream* pvMsg = mapOrphanTransactions[hash];
CTransaction tx;
CDataStream(*pvMsg) >> tx;
foreach(const CTxIn& txin, tx.vin)
{
for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash);
mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);)
{
if ((*mi).second == pvMsg)
mapOrphanTransactionsByPrev.erase(mi++);
else
mi++;
}
}
delete pvMsg;
mapOrphanTransactions.erase(hash);
}
//////////////////////////////////////////////////////////////////////////////
//
// CTransaction
//
bool CTxIn::IsMine() const
{
CRITICAL_BLOCK(cs_mapWallet)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size())
if (prev.vout[prevout.n].IsMine())
return true;
}
}
return false;
}
int64 CTxIn::GetDebit() const
{
CRITICAL_BLOCK(cs_mapWallet)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size())
if (prev.vout[prevout.n].IsMine())
return prev.vout[prevout.n].nValue;
}
}
return 0;
}
int64 CWalletTx::GetTxTime() const
{
if (!fTimeReceivedIsTxTime && hashBlock != 0)
{
// If we did not receive the transaction directly, we rely on the block's
// time to figure out when it happened. We use the median over a range
// of blocks to try to filter out inaccurate block times.
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (pindex)
return pindex->GetMedianTime();
}
}
return nTimeReceived;
}
int CWalletTx::GetRequestCount() const
{
// Returns -1 if it wasn't being tracked
int nRequests = -1;
CRITICAL_BLOCK(cs_mapRequestCount)
{
if (IsCoinBase())
{
// Generated block
if (hashBlock != 0)
{
map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
if (mi != mapRequestCount.end())
nRequests = (*mi).second;
}
}
else
{
// Did anyone request this transaction?
map<uint256, int>::iterator mi = mapRequestCount.find(GetHash());
if (mi != mapRequestCount.end())
{
nRequests = (*mi).second;
// How about the block it's in?
if (nRequests == 0 && hashBlock != 0)
{
map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
if (mi != mapRequestCount.end())
nRequests = (*mi).second;
else
nRequests = 1; // If it's in someone else's block it must have got out
}
}
}
}
return nRequests;
}
int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
{
if (fClient)
{
if (hashBlock == 0)
return 0;
}
else
{
CBlock blockTmp;
if (pblock == NULL)
{
// Load the block this tx is in
CTxIndex txindex;
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
return 0;
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
return 0;
pblock = &blockTmp;
}
// Update the tx's hashBlock
hashBlock = pblock->GetHash();
// Locate the transaction
for (nIndex = 0; nIndex < pblock->vtx.size(); nIndex++)
if (pblock->vtx[nIndex] == *(CTransaction*)this)
break;
if (nIndex == pblock->vtx.size())
{
vMerkleBranch.clear();
nIndex = -1;
printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
return 0;
}
// Fill in merkle branch
vMerkleBranch = pblock->GetMerkleBranch(nIndex);
}
// Is the tx in a block that's in the main chain
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !pindex->IsInMainChain())
return 0;
return pindexBest->nHeight - pindex->nHeight + 1;
}
void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
{
vtxPrev.clear();
const int COPY_DEPTH = 3;
if (SetMerkleBranch() < COPY_DEPTH)
{
vector<uint256> vWorkQueue;
foreach(const CTxIn& txin, vin)
vWorkQueue.push_back(txin.prevout.hash);
// This critsect is OK because txdb is already open
CRITICAL_BLOCK(cs_mapWallet)
{
map<uint256, const CMerkleTx*> mapWalletPrev;
set<uint256> setAlreadyDone;
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hash = vWorkQueue[i];
if (setAlreadyDone.count(hash))
continue;
setAlreadyDone.insert(hash);
CMerkleTx tx;
if (mapWallet.count(hash))
{
tx = mapWallet[hash];
foreach(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev)
mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
}
else if (mapWalletPrev.count(hash))
{
tx = *mapWalletPrev[hash];
}
else if (!fClient && txdb.ReadDiskTx(hash, tx))
{
;
}
else
{
printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
continue;
}
int nDepth = tx.SetMerkleBranch();
vtxPrev.push_back(tx);
if (nDepth < COPY_DEPTH)
foreach(const CTxIn& txin, tx.vin)
vWorkQueue.push_back(txin.prevout.hash);
}
}
}
reverse(vtxPrev.begin(), vtxPrev.end());
}
bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
{
if (pfMissingInputs)
*pfMissingInputs = false;
// Coinbase is only valid in a block, not as a loose transaction
if (IsCoinBase())
return error("AcceptTransaction() : coinbase as individual tx");
if (!CheckTransaction())
return error("AcceptTransaction() : CheckTransaction failed");
// To help v0.1.5 clients who would see it as a negative number
if (nLockTime > INT_MAX)
return error("AcceptTransaction() : not accepting nLockTime beyond 2038");
// Do we already have it?
uint256 hash = GetHash();
CRITICAL_BLOCK(cs_mapTransactions)
if (mapTransactions.count(hash))
return false;
if (fCheckInputs)
if (txdb.ContainsTx(hash))
return false;
// Check for conflicts with in-memory transactions
CTransaction* ptxOld = NULL;
for (int i = 0; i < vin.size(); i++)
{
COutPoint outpoint = vin[i].prevout;
if (mapNextTx.count(outpoint))
{
// Allow replacing with a newer version of the same transaction
if (i != 0)
return false;
ptxOld = mapNextTx[outpoint].ptx;
if (!IsNewerThan(*ptxOld))
return false;
for (int i = 0; i < vin.size(); i++)
{
COutPoint outpoint = vin[i].prevout;
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
return false;
}
break;
}
}
// Check against previous transactions
map<uint256, CTxIndex> mapUnused;
int64 nFees = 0;
if (fCheckInputs && !ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), 0, nFees, false, false))
{
if (pfMissingInputs)
*pfMissingInputs = true;
return error("AcceptTransaction() : ConnectInputs failed %s", hash.ToString().substr(0,6).c_str());
}
// Store transaction in memory
CRITICAL_BLOCK(cs_mapTransactions)
{
if (ptxOld)
{
printf("mapTransaction.erase(%s) replacing with new version\n", ptxOld->GetHash().ToString().c_str());
mapTransactions.erase(ptxOld->GetHash());
}
AddToMemoryPool();
}
///// are we sure this is ok when loading transactions or restoring block txes
// If updated, erase old tx from wallet
if (ptxOld)
EraseFromWallet(ptxOld->GetHash());
printf("AcceptTransaction(): accepted %s\n", hash.ToString().substr(0,6).c_str());
return true;
}
bool CTransaction::AddToMemoryPool()
{
// Add to memory pool without checking anything. Don't call this directly,
// call AcceptTransaction to properly check the transaction first.
CRITICAL_BLOCK(cs_mapTransactions)
{
uint256 hash = GetHash();
mapTransactions[hash] = *this;
for (int i = 0; i < vin.size(); i++)
mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
nTransactionsUpdated++;
}
return true;
}
bool CTransaction::RemoveFromMemoryPool()
{
// Remove transaction from memory pool
CRITICAL_BLOCK(cs_mapTransactions)
{
foreach(const CTxIn& txin, vin)
mapNextTx.erase(txin.prevout);
mapTransactions.erase(GetHash());
nTransactionsUpdated++;
}
return true;
}
int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const
{
if (hashBlock == 0 || nIndex == -1)
return 0;
// Find the block it claims to be in
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi == mapBlockIndex.end())
return 0;
CBlockIndex* pindex = (*mi).second;
if (!pindex || !pindex->IsInMainChain())
return 0;
// Make sure the merkle branch connects to this block
if (!fMerkleVerified)
{
if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
return 0;
fMerkleVerified = true;
}
nHeightRet = pindex->nHeight;
return pindexBest->nHeight - pindex->nHeight + 1;
}
int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
return 0;
return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());
}
bool CMerkleTx::AcceptTransaction(CTxDB& txdb, bool fCheckInputs)
{
if (fClient)
{
if (!IsInMainChain() && !ClientConnectInputs())
return false;
return CTransaction::AcceptTransaction(txdb, false);
}
else
{
return CTransaction::AcceptTransaction(txdb, fCheckInputs);
}
}
bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
{
CRITICAL_BLOCK(cs_mapTransactions)
{
foreach(CMerkleTx& tx, vtxPrev)
{
if (!tx.IsCoinBase())
{
uint256 hash = tx.GetHash();
if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash))
tx.AcceptTransaction(txdb, fCheckInputs);
}
}
if (!IsCoinBase())
return AcceptTransaction(txdb, fCheckInputs);
}
return true;
}
void ReacceptWalletTransactions()
{
CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
{
foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
CWalletTx& wtx = item.second;
if (wtx.fSpent && wtx.IsCoinBase())
continue;
CTxIndex txindex;
if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
{
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
if (!wtx.fSpent)
{
if (txindex.vSpent.size() != wtx.vout.size())
{
printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
continue;
}
for (int i = 0; i < txindex.vSpent.size(); i++)
{
if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine())
{
printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
wtx.fSpent = true;
wtx.WriteToDisk();
break;
}
}
}
}
else
{
// Reaccept any txes of ours that aren't already in a block
if (!wtx.IsCoinBase())
wtx.AcceptWalletTransaction(txdb, false);
}
}
}
}
void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
{
foreach(const CMerkleTx& tx, vtxPrev)
{
if (!tx.IsCoinBase())
{
uint256 hash = tx.GetHash();
if (!txdb.ContainsTx(hash))
RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
}
}
if (!IsCoinBase())
{
uint256 hash = GetHash();
if (!txdb.ContainsTx(hash))
{
printf("Relaying wtx %s\n", hash.ToString().substr(0,6).c_str());
RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
}
}
}
void ResendWalletTransactions()
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
static int64 nNextTime;
if (GetTime() < nNextTime)
return;
bool fFirst = (nNextTime == 0);
nNextTime = GetTime() + GetRand(120 * 60);
if (fFirst)
return;
// Rebroadcast any of our txes that aren't in a block yet
printf("ResendWalletTransactions()\n");
CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
{
// Sort them in chronological order
multimap<unsigned int, CWalletTx*> mapSorted;
foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
CWalletTx& wtx = item.second;
// Don't rebroadcast until it's had plenty of time that
// it should have gotten in already by now.
if (nTimeBestReceived - wtx.nTimeReceived > 60 * 60)
mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
}
foreach(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
CWalletTx& wtx = *item.second;
wtx.RelayWalletTransaction(txdb);
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// CBlock and CBlockIndex
//
bool CBlock::ReadFromDisk(const CBlockIndex* pblockindex, bool fReadTransactions)
{
return ReadFromDisk(pblockindex->nFile, pblockindex->nBlockPos, fReadTransactions);
}
uint256 GetOrphanRoot(const CBlock* pblock)
{
// Work back to the first block in the orphan chain
while (mapOrphanBlocks.count(pblock->hashPrevBlock))
pblock = mapOrphanBlocks[pblock->hashPrevBlock];
return pblock->GetHash();
}
int64 CBlock::GetBlockValue(int64 nFees) const
{
int64 nSubsidy = 50 * COIN;
// Subsidy is cut in half every 4 years
nSubsidy >>= (nBestHeight / 210000);
return nSubsidy + nFees;
}
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
{
const unsigned int nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
const unsigned int nTargetSpacing = 10 * 60;
const unsigned int nInterval = nTargetTimespan / nTargetSpacing;
// Genesis block
if (pindexLast == NULL)
return bnProofOfWorkLimit.GetCompact();
// Only change once per interval
if ((pindexLast->nHeight+1) % nInterval != 0)
return pindexLast->nBits;
// Go back by what we want to be 14 days worth of blocks
const CBlockIndex* pindexFirst = pindexLast;
for (int i = 0; pindexFirst && i < nInterval-1; i++)
pindexFirst = pindexFirst->pprev;
assert(pindexFirst);
// Limit adjustment step
unsigned int nActualTimespan = pindexLast->nTime - pindexFirst->nTime;
printf(" nActualTimespan = %d before bounds\n", nActualTimespan);
if (nActualTimespan < nTargetTimespan/4)
nActualTimespan = nTargetTimespan/4;
if (nActualTimespan > nTargetTimespan*4)
nActualTimespan = nTargetTimespan*4;
// Retarget
CBigNum bnNew;
bnNew.SetCompact(pindexLast->nBits);
bnNew *= nActualTimespan;
bnNew /= nTargetTimespan;
if (bnNew > bnProofOfWorkLimit)
bnNew = bnProofOfWorkLimit;
/// debug print
printf("GetNextWorkRequired RETARGET\n");
printf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);
printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
return bnNew.GetCompact();
}
bool CTransaction::DisconnectInputs(CTxDB& txdb)
{
// Relinquish previous transactions' spent pointers
if (!IsCoinBase())
{
foreach(const CTxIn& txin, vin)
{
COutPoint prevout = txin.prevout;
// Get prev txindex from disk
CTxIndex txindex;
if (!txdb.ReadTxIndex(prevout.hash, txindex))
return error("DisconnectInputs() : ReadTxIndex failed");
if (prevout.n >= txindex.vSpent.size())
return error("DisconnectInputs() : prevout.n out of range");
// Mark outpoint as not spent
txindex.vSpent[prevout.n].SetNull();
// Write back
txdb.UpdateTxIndex(prevout.hash, txindex);
}
}
// Remove transaction from index
if (!txdb.EraseTxIndex(*this))
return error("DisconnectInputs() : EraseTxPos failed");
return true;
}
bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx, int nHeight, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee)
{
// Take over previous transactions' spent pointers
if (!IsCoinBase())
{
int64 nValueIn = 0;
for (int i = 0; i < vin.size(); i++)
{
COutPoint prevout = vin[i].prevout;
// Read txindex
CTxIndex txindex;
bool fFound = true;
if (fMiner && mapTestPool.count(prevout.hash))
{
// Get txindex from current proposed changes
txindex = mapTestPool[prevout.hash];
}
else
{
// Read txindex from txdb
fFound = txdb.ReadTxIndex(prevout.hash, txindex);
}
if (!fFound && (fBlock || fMiner))
return fMiner ? false : error("ConnectInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str());
// Read txPrev
CTransaction txPrev;
if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
{
// Get prev tx from single transactions in memory
CRITICAL_BLOCK(cs_mapTransactions)
{
if (!mapTransactions.count(prevout.hash))
return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str());
txPrev = mapTransactions[prevout.hash];
}
if (!fFound)
txindex.vSpent.resize(txPrev.vout.size());
}
else
{
// Get prev tx from disk
if (!txPrev.ReadFromDisk(txindex.pos))
return error("ConnectInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,6).c_str(), prevout.hash.ToString().substr(0,6).c_str());
}
if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,6).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,6).c_str(), txPrev.ToString().c_str());
// If prev is coinbase, check that it's matured
if (txPrev.IsCoinBase())
for (CBlockIndex* pindex = pindexBest; pindex && nBestHeight - pindex->nHeight < COINBASE_MATURITY-1; pindex = pindex->pprev)
if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
return error("ConnectInputs() : tried to spend coinbase at depth %d", nBestHeight - pindex->nHeight);
// Verify signature
if (!VerifySignature(txPrev, *this, i))
return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,6).c_str());
// Check for conflicts
if (!txindex.vSpent[prevout.n].IsNull())
return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,6).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
// Mark outpoints as spent
txindex.vSpent[prevout.n] = posThisTx;
// Write back
if (fBlock)
txdb.UpdateTxIndex(prevout.hash, txindex);
else if (fMiner)
mapTestPool[prevout.hash] = txindex;
nValueIn += txPrev.vout[prevout.n].nValue;
}
// Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0)
return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,6).c_str());
if (nTxFee < nMinFee)
return false;
nFees += nTxFee;
}
if (fBlock)
{
// Add transaction to disk index
if (!txdb.AddTxIndex(*this, posThisTx, nHeight))
return error("ConnectInputs() : AddTxPos failed");
}
else if (fMiner)
{
// Add transaction to test pool
mapTestPool[GetHash()] = CTxIndex(CDiskTxPos(1,1,1), vout.size());
}
return true;
}
bool CTransaction::ClientConnectInputs()
{
if (IsCoinBase())
return false;
// Take over previous transactions' spent pointers
CRITICAL_BLOCK(cs_mapTransactions)
{
int64 nValueIn = 0;
for (int i = 0; i < vin.size(); i++)
{
// Get prev tx from single transactions in memory
COutPoint prevout = vin[i].prevout;
if (!mapTransactions.count(prevout.hash))
return false;
CTransaction& txPrev = mapTransactions[prevout.hash];
if (prevout.n >= txPrev.vout.size())
return false;
// Verify signature
if (!VerifySignature(txPrev, *this, i))
return error("ConnectInputs() : VerifySignature failed");
///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of
///// this has to go away now that posNext is gone
// // Check for conflicts
// if (!txPrev.vout[prevout.n].posNext.IsNull())
// return error("ConnectInputs() : prev tx already used");
//
// // Flag outpoints as used
// txPrev.vout[prevout.n].posNext = posThisTx;
nValueIn += txPrev.vout[prevout.n].nValue;
}
if (GetValueOut() > nValueIn)
return false;
}
return true;
}
bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex)
{
// Disconnect in reverse order
for (int i = vtx.size()-1; i >= 0; i--)
if (!vtx[i].DisconnectInputs(txdb))
return false;
// Update block index on disk without changing it in memory.
// The memory index structure will be changed after the db commits.
if (pindex->pprev)
{
CDiskBlockIndex blockindexPrev(pindex->pprev);
blockindexPrev.hashNext = 0;
txdb.WriteBlockIndex(blockindexPrev);
}
return true;
}
bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
{
//// issue here: it doesn't know the version
unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
map<uint256, CTxIndex> mapUnused;
int64 nFees = 0;
foreach(CTransaction& tx, vtx)
{
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
nTxPos += ::GetSerializeSize(tx, SER_DISK);
if (!tx.ConnectInputs(txdb, mapUnused, posThisTx, pindex->nHeight, nFees, true, false))
return false;
}
if (vtx[0].GetValueOut() > GetBlockValue(nFees))
return false;
// Update block index on disk without changing it in memory.
// The memory index structure will be changed after the db commits.
if (pindex->pprev)
{
CDiskBlockIndex blockindexPrev(pindex->pprev);
blockindexPrev.hashNext = pindex->GetBlockHash();
txdb.WriteBlockIndex(blockindexPrev);
}
// Watch for transactions paying to me
foreach(CTransaction& tx, vtx)
AddToWalletIfMine(tx, this);
return true;
}
bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{
printf("REORGANIZE\n");
// Find the fork
CBlockIndex* pfork = pindexBest;
CBlockIndex* plonger = pindexNew;
while (pfork != plonger)
{
if (!(pfork = pfork->pprev))
return error("Reorganize() : pfork->pprev is null");
while (plonger->nHeight > pfork->nHeight)
if (!(plonger = plonger->pprev))
return error("Reorganize() : plonger->pprev is null");
}
// List of what to disconnect
vector<CBlockIndex*> vDisconnect;
for (CBlockIndex* pindex = pindexBest; pindex != pfork; pindex = pindex->pprev)
vDisconnect.push_back(pindex);
// List of what to connect
vector<CBlockIndex*> vConnect;
for (CBlockIndex* pindex = pindexNew; pindex != pfork; pindex = pindex->pprev)
vConnect.push_back(pindex);
reverse(vConnect.begin(), vConnect.end());
// Disconnect shorter branch
vector<CTransaction> vResurrect;
foreach(CBlockIndex* pindex, vDisconnect)
{
CBlock block;
if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))
return error("Reorganize() : ReadFromDisk for disconnect failed");
if (!block.DisconnectBlock(txdb, pindex))
return error("Reorganize() : DisconnectBlock failed");
// Queue memory transactions to resurrect
foreach(const CTransaction& tx, block.vtx)
if (!tx.IsCoinBase())
vResurrect.push_back(tx);
}
// Connect longer branch
vector<CTransaction> vDelete;
for (int i = 0; i < vConnect.size(); i++)
{
CBlockIndex* pindex = vConnect[i];
CBlock block;
if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))
return error("Reorganize() : ReadFromDisk for connect failed");
if (!block.ConnectBlock(txdb, pindex))
{
// Invalid block, delete the rest of this branch
txdb.TxnAbort();
for (int j = i; j < vConnect.size(); j++)
{
CBlockIndex* pindex = vConnect[j];
pindex->EraseBlockFromDisk();
txdb.EraseBlockIndex(pindex->GetBlockHash());
mapBlockIndex.erase(pindex->GetBlockHash());
delete pindex;
}
return error("Reorganize() : ConnectBlock failed");
}
// Queue memory transactions to delete
foreach(const CTransaction& tx, block.vtx)
vDelete.push_back(tx);
}
if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash()))
return error("Reorganize() : WriteHashBestChain failed");
// Commit now because resurrecting could take some time
txdb.TxnCommit();
// Disconnect shorter branch
foreach(CBlockIndex* pindex, vDisconnect)
if (pindex->pprev)
pindex->pprev->pnext = NULL;
// Connect longer branch
foreach(CBlockIndex* pindex, vConnect)
if (pindex->pprev)
pindex->pprev->pnext = pindex;
// Resurrect memory transactions that were in the disconnected branch
foreach(CTransaction& tx, vResurrect)
tx.AcceptTransaction(txdb, false);
// Delete redundant memory transactions that are in the connected branch
foreach(CTransaction& tx, vDelete)
tx.RemoveFromMemoryPool();
return true;
}
bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
{
// Check for duplicate
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,16).c_str());
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);
if (!pindexNew)
return error("AddToBlockIndex() : new CBlockIndex failed");
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
if (miPrev != mapBlockIndex.end())
{
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
}
CTxDB txdb;
txdb.TxnBegin();
txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
// New best
if (pindexNew->nHeight > nBestHeight)
{
if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
{
pindexGenesisBlock = pindexNew;
txdb.WriteHashBestChain(hash);
}
else if (hashPrevBlock == hashBestChain)
{
// Adding to current best branch
if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
{
txdb.TxnAbort();
pindexNew->EraseBlockFromDisk();
mapBlockIndex.erase(pindexNew->GetBlockHash());
delete pindexNew;
return error("AddToBlockIndex() : ConnectBlock failed");
}
txdb.TxnCommit();
pindexNew->pprev->pnext = pindexNew;
// Delete redundant memory transactions
foreach(CTransaction& tx, vtx)
tx.RemoveFromMemoryPool();
}
else
{
// New best branch
if (!Reorganize(txdb, pindexNew))
{
txdb.TxnAbort();
return error("AddToBlockIndex() : Reorganize failed");
}
}
// New best block
hashBestChain = hash;
pindexBest = pindexNew;
nBestHeight = pindexBest->nHeight;
nTimeBestReceived = GetTime();
nTransactionsUpdated++;
printf("AddToBlockIndex: new best=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);
}
txdb.TxnCommit();
txdb.Close();
if (pindexNew == pindexBest)
{
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
CRITICAL_BLOCK(cs_mapWallet)
vWalletUpdated.push_back(hashPrevBestCoinBase);
hashPrevBestCoinBase = vtx[0].GetHash();
}
MainFrameRepaint();
return true;
}
bool CBlock::CheckBlock() const
{
// These are checks that are independent of context
// that can be verified before saving an orphan block.
// Size limits
if (vtx.empty() || vtx.size() > MAX_SIZE || ::GetSerializeSize(*this, SER_DISK) > MAX_SIZE)
return error("CheckBlock() : size limits failed");
// Check timestamp
if (nTime > GetAdjustedTime() + 2 * 60 * 60)
return error("CheckBlock() : block timestamp too far in the future");
// First transaction must be coinbase, the rest must not be
if (vtx.empty() || !vtx[0].IsCoinBase())
return error("CheckBlock() : first tx is not coinbase");
for (int i = 1; i < vtx.size(); i++)
if (vtx[i].IsCoinBase())
return error("CheckBlock() : more than one coinbase");
// Check transactions
foreach(const CTransaction& tx, vtx)
if (!tx.CheckTransaction())
return error("CheckBlock() : CheckTransaction failed");
// Check proof of work matches claimed amount
if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)
return error("CheckBlock() : nBits below minimum work");
if (GetHash() > CBigNum().SetCompact(nBits).getuint256())
return error("CheckBlock() : hash doesn't match nBits");
// Check merkleroot
if (hashMerkleRoot != BuildMerkleTree())
return error("CheckBlock() : hashMerkleRoot mismatch");
return true;
}
bool CBlock::AcceptBlock()
{
// Check for duplicate
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
return error("AcceptBlock() : block already in mapBlockIndex");
// Get prev block index
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
if (mi == mapBlockIndex.end())
return error("AcceptBlock() : prev block not found");
CBlockIndex* pindexPrev = (*mi).second;
// Check timestamp against prev
if (nTime <= pindexPrev->GetMedianTimePast())
return error("AcceptBlock() : block's timestamp is too early");
// Check that all transactions are finalized
foreach(const CTransaction& tx, vtx)
if (!tx.IsFinal(nTime))
return error("AcceptBlock() : contains a non-final transaction");
// Check proof of work
if (nBits != GetNextWorkRequired(pindexPrev))
return error("AcceptBlock() : incorrect proof of work");
// Write block to history file
if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
return error("AcceptBlock() : out of disk space");
unsigned int nFile;
unsigned int nBlockPos;
if (!WriteToDisk(!fClient, nFile, nBlockPos))
return error("AcceptBlock() : WriteToDisk failed");
if (!AddToBlockIndex(nFile, nBlockPos))
return error("AcceptBlock() : AddToBlockIndex failed");
// Relay inventory, but don't relay old inventory during initial block download
if (hashBestChain == hash)
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 55000))
pnode->PushInventory(CInv(MSG_BLOCK, hash));
return true;
}
bool ProcessBlock(CNode* pfrom, CBlock* pblock)
{
// Check for duplicate
uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash))
return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,16).c_str());
if (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,16).c_str());
// Preliminary checks
if (!pblock->CheckBlock())
{
delete pblock;
return error("ProcessBlock() : CheckBlock FAILED");
}
// If don't already have its previous block, shunt it off to holding area until we get it
if (!mapBlockIndex.count(pblock->hashPrevBlock))
{
printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,16).c_str());
mapOrphanBlocks.insert(make_pair(hash, pblock));
mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock));
// Ask this guy to fill in what we're missing
if (pfrom)
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock));
return true;
}
// Store to disk
if (!pblock->AcceptBlock())
{
delete pblock;
return error("ProcessBlock() : AcceptBlock FAILED");
}
delete pblock;
// Recursively process any orphan blocks that depended on this one
vector<uint256> vWorkQueue;
vWorkQueue.push_back(hash);
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);
++mi)
{
CBlock* pblockOrphan = (*mi).second;
if (pblockOrphan->AcceptBlock())
vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash());
delete pblockOrphan;
}
mapOrphanBlocksByPrev.erase(hashPrev);
}
printf("ProcessBlock: ACCEPTED\n");
return true;
}
template<typename Stream>
bool ScanMessageStart(Stream& s)
{
// Scan ahead to the next pchMessageStart, which should normally be immediately
// at the file pointer. Leaves file pointer at end of pchMessageStart.
s.clear(0);
short prevmask = s.exceptions(0);
const char* p = BEGIN(pchMessageStart);
try
{
loop
{
char c;
s.read(&c, 1);
if (s.fail())
{
s.clear(0);
s.exceptions(prevmask);
return false;
}
if (*p != c)
p = BEGIN(pchMessageStart);
if (*p == c)
{
if (++p == END(pchMessageStart))
{
s.clear(0);
s.exceptions(prevmask);
return true;
}
}
}
}
catch (...)
{
s.clear(0);
s.exceptions(prevmask);
return false;
}
}
bool CheckDiskSpace(int64 nAdditionalBytes)
{
uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
// Check for 15MB because database could create another 10MB log file at any time
if (nFreeBytesAvailable < (int64)15000000 + nAdditionalBytes)
{
fShutdown = true;
ThreadSafeMessageBox(_("Warning: Disk space is low "), "Bitcoin", wxOK | wxICON_EXCLAMATION);
CreateThread(Shutdown, NULL);
return false;
}
return true;
}
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode)
{
if (nFile == -1)
return NULL;
FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
if (!file)
return NULL;
if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
{
if (fseek(file, nBlockPos, SEEK_SET) != 0)
{
fclose(file);
return NULL;
}
}
return file;
}
static unsigned int nCurrentBlockFile = 1;
FILE* AppendBlockFile(unsigned int& nFileRet)
{
nFileRet = 0;
loop
{
FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab");
if (!file)
return NULL;
if (fseek(file, 0, SEEK_END) != 0)
return NULL;
// FAT32 filesize max 4GB, fseek and ftell max 2GB, so we must stay under 2GB
if (ftell(file) < 0x7F000000 - MAX_SIZE)
{
nFileRet = nCurrentBlockFile;
return file;
}
fclose(file);
nCurrentBlockFile++;
}
}
bool LoadBlockIndex(bool fAllowNew)
{
//
// Load block index
//
CTxDB txdb("cr");
if (!txdb.LoadBlockIndex())
return false;
txdb.Close();
//
// Init with genesis block
//
if (mapBlockIndex.empty())
{
if (!fAllowNew)
return false;
// Genesis Block:
// GetHash() = 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
// hashMerkleRoot = 0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
// txNew.vin[0].scriptSig = 486604799 4 0x736B6E616220726F662074756F6C69616220646E6F63657320666F206B6E697262206E6F20726F6C6C65636E61684320393030322F6E614A2F33302073656D695420656854
// txNew.vout[0].nValue = 5000000000
// txNew.vout[0].scriptPubKey = 0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704 OP_CHECKSIG
// block.nVersion = 1
// block.nTime = 1231006505
// block.nBits = 0x1d00ffff
// block.nNonce = 2083236893
// CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
// CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
// CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
// CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
// vMerkleTree: 4a5e1e
// Genesis block
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
CTransaction txNew;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vout[0].nValue = 50 * COIN;
CBigNum bnPubKey;
bnPubKey.SetHex("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704");
txNew.vout[0].scriptPubKey = CScript() << bnPubKey << OP_CHECKSIG;
CBlock block;
block.vtx.push_back(txNew);
block.hashPrevBlock = 0;
block.hashMerkleRoot = block.BuildMerkleTree();
block.nVersion = 1;
block.nTime = 1231006505;
block.nBits = 0x1d00ffff;
block.nNonce = 2083236893;
//// debug print
printf("%s\n", block.GetHash().ToString().c_str());
printf("%s\n", block.hashMerkleRoot.ToString().c_str());
printf("%s\n", hashGenesisBlock.ToString().c_str());
txNew.vout[0].scriptPubKey.print();
block.print();
assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
assert(block.GetHash() == hashGenesisBlock);
// Start new block file
unsigned int nFile;
unsigned int nBlockPos;
if (!block.WriteToDisk(!fClient, nFile, nBlockPos))
return error("LoadBlockIndex() : writing genesis block to disk failed");
if (!block.AddToBlockIndex(nFile, nBlockPos))
return error("LoadBlockIndex() : genesis block not accepted");
}
return true;
}
void PrintBlockTree()
{
// precompute tree structure
map<CBlockIndex*, vector<CBlockIndex*> > mapNext;
for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
{
CBlockIndex* pindex = (*mi).second;
mapNext[pindex->pprev].push_back(pindex);
// test
//while (rand() % 3 == 0)
// mapNext[pindex->pprev].push_back(pindex);
}
vector<pair<int, CBlockIndex*> > vStack;
vStack.push_back(make_pair(0, pindexGenesisBlock));
int nPrevCol = 0;
while (!vStack.empty())
{
int nCol = vStack.back().first;
CBlockIndex* pindex = vStack.back().second;
vStack.pop_back();
// print split or gap
if (nCol > nPrevCol)
{
for (int i = 0; i < nCol-1; i++)
printf("| ");
printf("|\\\n");
}
else if (nCol < nPrevCol)
{
for (int i = 0; i < nCol; i++)
printf("| ");
printf("|\n");
}
nPrevCol = nCol;
// print columns
for (int i = 0; i < nCol; i++)
printf("| ");
// print item
CBlock block;
block.ReadFromDisk(pindex);
printf("%d (%u,%u) %s %s tx %d",
pindex->nHeight,
pindex->nFile,
pindex->nBlockPos,
block.GetHash().ToString().substr(0,16).c_str(),
DateTimeStrFormat("%x %H:%M:%S", block.nTime).c_str(),
block.vtx.size());
CRITICAL_BLOCK(cs_mapWallet)
{
if (mapWallet.count(block.vtx[0].GetHash()))
{
CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
}
}
printf("\n");
// put the main timechain first
vector<CBlockIndex*>& vNext = mapNext[pindex];
for (int i = 0; i < vNext.size(); i++)
{
if (vNext[i]->pnext)
{
swap(vNext[0], vNext[i]);
break;
}
}
// iterate children
for (int i = 0; i < vNext.size(); i++)
vStack.push_back(make_pair(nCol+i, vNext[i]));
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Messages
//
bool AlreadyHave(CTxDB& txdb, const CInv& inv)
{
switch (inv.type)
{
case MSG_TX: return mapTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
}
// Don't know what it is, just say we already got one
return true;
}
bool ProcessMessages(CNode* pfrom)
{
CDataStream& vRecv = pfrom->vRecv;
if (vRecv.empty())
return true;
//if (fDebug)
// printf("ProcessMessages(%d bytes)\n", vRecv.size());
//
// Message format
// (4) message start
// (12) command
// (4) size
// (4) checksum
// (x) data
//
loop
{
// Scan for message start
CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
if (vRecv.end() - pstart < nHeaderSize)
{
if (vRecv.size() > nHeaderSize)
{
printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
}
break;
}
if (pstart - vRecv.begin() > 0)
printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin());
vRecv.erase(vRecv.begin(), pstart);
// Read header
vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
CMessageHeader hdr;
vRecv >> hdr;
if (!hdr.IsValid())
{
printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
continue;
}
string strCommand = hdr.GetCommand();
// Message size
unsigned int nMessageSize = hdr.nMessageSize;
if (nMessageSize > vRecv.size())
{
// Rewind and wait for rest of message
///// need a mechanism to give up waiting for overlong message size error
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
break;
}
// Copy message to its own buffer
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
vRecv.ignore(nMessageSize);
// Checksum
if (vRecv.GetVersion() >= 209)
{
uint256 hash = Hash(vMsg.begin(), vMsg.end());
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum)
{
printf("ProcessMessage(%s, %d bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
continue;
}
}
// Process message
bool fRet = false;
try
{
CRITICAL_BLOCK(cs_main)
fRet = ProcessMessage(pfrom, strCommand, vMsg);
if (fShutdown)
return true;
}
catch (std::ios_base::failure& e)
{
if (strstr(e.what(), "CDataStream::read() : end of data"))
{
// Allow exceptions from underlength message on vRecv
printf("ProcessMessage(%s, %d bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
}
else if (strstr(e.what(), ": size too large"))
{
// Allow exceptions from overlong size
printf("ProcessMessage(%s, %d bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
}
else
{
PrintException(&e, "ProcessMessage()");
}
}
catch (std::exception& e) {
PrintException(&e, "ProcessMessage()");
} catch (...) {
PrintException(NULL, "ProcessMessage()");
}
if (!fRet)
printf("ProcessMessage(%s, %d bytes) FAILED\n", strCommand.c_str(), nMessageSize);
}
vRecv.Compact();
return true;
}
bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
static map<unsigned int, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon();
if (fDebug)
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
printf("dropmessagestest DROPPING RECV MESSAGE\n");
return true;
}
if (strCommand == "version")
{
// Each connection can only send one version message
if (pfrom->nVersion != 0)
return false;
int64 nTime;
CAddress addrMe;
CAddress addrFrom;
uint64 nNonce = 1;
string strSubVer;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
if (pfrom->nVersion >= 106 && !vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (pfrom->nVersion >= 106 && !vRecv.empty())
vRecv >> strSubVer;
if (pfrom->nVersion >= 209 && !vRecv.empty())
vRecv >> pfrom->nStartingHeight;
if (pfrom->nVersion == 0)
return false;
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
{
pfrom->fDisconnect = true;
return true;
}
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
if (pfrom->fClient)
{
pfrom->vSend.nType |= SER_BLOCKHEADERONLY;
pfrom->vRecv.nType |= SER_BLOCKHEADERONLY;
}
AddTimeData(pfrom->addr.ip, nTime);
// Change version
if (pfrom->nVersion >= 209)
pfrom->PushMessage("verack");
pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
if (pfrom->nVersion < 209)
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
// Ask the first connected node for block updates
static int nAskedForBlocks;
if (!pfrom->fClient && (nAskedForBlocks < 1 || vNodes.size() <= 1))
{
nAskedForBlocks++;
pfrom->PushGetBlocks(pindexBest, uint256(0));
}
pfrom->fSuccessfullyConnected = true;
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
}
else if (pfrom->nVersion == 0)
{
// Must have a version message before anything else
return false;
}
else if (strCommand == "verack")
{
pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
}
else if (strCommand == "addr")
{
vector<CAddress> vAddr;
vRecv >> vAddr;
if (pfrom->nVersion < 200) // don't want addresses from 0.1.5
return true;
if (vAddr.size() > 1000)
return error("message addr size() = %d", vAddr.size());
// Store the new addresses
foreach(CAddress& addr, vAddr)
{
if (fShutdown)
return true;
addr.nTime = GetAdjustedTime() - 2 * 60 * 60;
if (pfrom->fGetAddr || vAddr.size() > 10)
addr.nTime -= 5 * 24 * 60 * 60;
AddAddress(addr);
pfrom->AddAddressKnown(addr);
if (!pfrom->fGetAddr && addr.IsRoutable())
{
// Relay to a limited number of other nodes
CRITICAL_BLOCK(cs_vNodes)
{
// Use deterministic randomness to send to
// the same places for an hour at a time
static uint256 hashSalt;
if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
uint256 hashRand = addr.ip ^ (GetTime()/3600) ^ hashSalt;
multimap<uint256, CNode*> mapMix;
foreach(CNode* pnode, vNodes)
mapMix.insert(make_pair(hashRand = Hash(BEGIN(hashRand), END(hashRand)), pnode));
int nRelayNodes = 10; // reduce this to 5 when the network is large
for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
((*mi).second)->PushAddress(addr);
}
}
}
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
}
else if (strCommand == "inv")
{
vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > 50000)
return error("message inv size() = %d", vInv.size());
CTxDB txdb("r");
foreach(const CInv& inv, vInv)
{
if (fShutdown)
return true;
pfrom->AddInventoryKnown(inv);
bool fAlreadyHave = AlreadyHave(txdb, inv);
printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
if (!fAlreadyHave)
pfrom->AskFor(inv);
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
// Track requests for our stuff
CRITICAL_BLOCK(cs_mapRequestCount)
{
map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
}
}
else if (strCommand == "getdata")
{
vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > 50000)
return error("message getdata size() = %d", vInv.size());
foreach(const CInv& inv, vInv)
{
if (fShutdown)
return true;
printf("received getdata for: %s\n", inv.ToString().c_str());
if (inv.type == MSG_BLOCK)
{
// Send block from disk
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);
if (mi != mapBlockIndex.end())
{
//// could optimize this to send header straight from blockindex for client
CBlock block;
block.ReadFromDisk((*mi).second, !pfrom->fClient);
pfrom->PushMessage("block", block);
// Trigger them to send a getblocks request for the next batch of inventory
if (inv.hash == pfrom->hashContinue)
{
// Bypass PushInventory, this must send even if redundant,
// and we want it right after the last block so they don't
// wait for other stuff first.
vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
pfrom->PushMessage("inv", vInv);
pfrom->hashContinue = 0;
}
}
}
else if (inv.IsKnownType())
{
// Send stream from relay memory
CRITICAL_BLOCK(cs_mapRelay)
{
map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
if (mi != mapRelay.end())
pfrom->PushMessage(inv.GetCommand(), (*mi).second);
}
}
// Track requests for our stuff
CRITICAL_BLOCK(cs_mapRequestCount)
{
map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
}
}
else if (strCommand == "getblocks")
{
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
// Find the first block the caller has in the main chain
CBlockIndex* pindex = locator.GetBlockIndex();
// Send the rest of the chain
if (pindex)
pindex = pindex->pnext;
int nLimit = 500 + locator.GetDistanceBack();
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,16).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
if (pindex->GetBlockHash() == hashStop)
{
printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,16).c_str());
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
if (--nLimit <= 0)
{
// When this block is requested, we'll send an inv that'll make them
// getblocks the next batch of inventory.
printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,16).c_str());
pfrom->hashContinue = pindex->GetBlockHash();
break;
}
}
}
else if (strCommand == "tx")
{
vector<uint256> vWorkQueue;
CDataStream vMsg(vRecv);
CTransaction tx;
vRecv >> tx;
CInv inv(MSG_TX, tx.GetHash());
pfrom->AddInventoryKnown(inv);
bool fMissingInputs = false;
if (tx.AcceptTransaction(true, &fMissingInputs))
{
AddToWalletIfMine(tx, NULL);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
// Recursively process any orphan transactions that depended on this one
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);
mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev);
++mi)
{
const CDataStream& vMsg = *((*mi).second);
CTransaction tx;
CDataStream(vMsg) >> tx;
CInv inv(MSG_TX, tx.GetHash());
if (tx.AcceptTransaction(true))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,6).c_str());
AddToWalletIfMine(tx, NULL);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
}
}
}
foreach(uint256 hash, vWorkQueue)
EraseOrphanTx(hash);
}
else if (fMissingInputs)
{
printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,6).c_str());
AddOrphanTx(vMsg);
}
}
else if (strCommand == "block")
{
auto_ptr<CBlock> pblock(new CBlock);
vRecv >> *pblock;
//// debug print
printf("received block %s\n", pblock->GetHash().ToString().substr(0,16).c_str());
// pblock->print();
CInv inv(MSG_BLOCK, pblock->GetHash());
pfrom->AddInventoryKnown(inv);
if (ProcessBlock(pfrom, pblock.release()))
mapAlreadyAskedFor.erase(inv);
}
else if (strCommand == "getaddr")
{
// This includes all nodes that are currently online,
// since they rebroadcast an addr every 24 hours
pfrom->vAddrToSend.clear();
int64 nSince = GetAdjustedTime() - 24 * 60 * 60; // in the last 24 hours
CRITICAL_BLOCK(cs_mapAddresses)
{
unsigned int nSize = mapAddresses.size();
foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
if (fShutdown)
return true;
const CAddress& addr = item.second;
if (addr.nTime > nSince)
pfrom->PushAddress(addr);
}
}
}
else if (strCommand == "checkorder")
{
uint256 hashReply;
CWalletTx order;
vRecv >> hashReply >> order;
/// we have a chance to check the order here
// Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip))
mapReuseKey[pfrom->addr.ip] = GenerateNewKey();
// Send back approval of order and pubkey to use
CScript scriptPubKey;
scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
}
else if (strCommand == "submitorder")
{
uint256 hashReply;
CWalletTx wtxNew;
vRecv >> hashReply >> wtxNew;
wtxNew.fFromMe = false;
// Broadcast
if (!wtxNew.AcceptWalletTransaction())
{
pfrom->PushMessage("reply", hashReply, (int)1);
return error("submitorder AcceptWalletTransaction() failed, returning error 1");
}
wtxNew.fTimeReceivedIsTxTime = true;
AddToWallet(wtxNew);
wtxNew.RelayWalletTransaction();
mapReuseKey.erase(pfrom->addr.ip);
// Send back confirmation
pfrom->PushMessage("reply", hashReply, (int)0);
}
else if (strCommand == "reply")
{
uint256 hashReply;
vRecv >> hashReply;
CRequestTracker tracker;
CRITICAL_BLOCK(pfrom->cs_mapRequests)
{
map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
if (mi != pfrom->mapRequests.end())
{
tracker = (*mi).second;
pfrom->mapRequests.erase(mi);
}
}
if (!tracker.IsNull())
tracker.fn(tracker.param1, vRecv);
}
else if (strCommand == "ping")
{
}
else
{
// Ignore unknown commands for extensibility
}
// Update the last seen time for this node's address
if (pfrom->fNetworkNode)
if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")
AddressCurrentlyConnected(pfrom->addr);
return true;
}
bool SendMessages(CNode* pto, bool fSendTrickle)
{
CRITICAL_BLOCK(cs_main)
{
// Don't send anything until we get their version message
if (pto->nVersion == 0)
return true;
// Keep-alive ping
if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
pto->PushMessage("ping");
// Address refresh broadcast
static int64 nLastRebroadcast;
if (GetTime() - nLastRebroadcast > 24 * 60 * 60) // every 24 hours
{
nLastRebroadcast = GetTime();
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodes)
{
// Periodically clear setAddrKnown to allow refresh broadcasts
pnode->setAddrKnown.clear();
// Rebroadcast our address
if (addrLocalHost.IsRoutable() && !fUseProxy)
pnode->PushAddress(addrLocalHost);
}
}
}
// Resend wallet transactions that haven't gotten in a block yet
ResendWalletTransactions();
//
// Message: addr
//
if (fSendTrickle)
{
vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());
foreach(const CAddress& addr, pto->vAddrToSend)
{
// returns true if wasn't already contained in the set
if (pto->setAddrKnown.insert(addr).second)
{
vAddr.push_back(addr);
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
pto->PushMessage("addr", vAddr);
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
pto->PushMessage("addr", vAddr);
}
//
// Message: inventory
//
vector<CInv> vInv;
vector<CInv> vInvWait;
CRITICAL_BLOCK(pto->cs_inventory)
{
vInv.reserve(pto->vInventoryToSend.size());
vInvWait.reserve(pto->vInventoryToSend.size());
foreach(const CInv& inv, pto->vInventoryToSend)
{
if (pto->setInventoryKnown.count(inv))
continue;
// trickle out tx inv to protect privacy
if (inv.type == MSG_TX && !fSendTrickle)
{
// 1/4 of tx invs blast to all immediately
static uint256 hashSalt;
if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
uint256 hashRand = inv.hash ^ hashSalt;
hashRand = Hash(BEGIN(hashRand), END(hashRand));
bool fTrickleWait = ((hashRand & 3) != 0);
// always trickle our own transactions
if (!fTrickleWait)
{
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(inv.hash);
if (mi != mapWallet.end())
{
CWalletTx& wtx = (*mi).second;
if (wtx.fFromMe)
fTrickleWait = true;
}
}
}
if (fTrickleWait)
{
vInvWait.push_back(inv);
continue;
}
}
// returns true if wasn't already contained in the set
if (pto->setInventoryKnown.insert(inv).second)
{
vInv.push_back(inv);
if (vInv.size() >= 1000)
{
pto->PushMessage("inv", vInv);
vInv.clear();
}
}
}
pto->vInventoryToSend = vInvWait;
}
if (!vInv.empty())
pto->PushMessage("inv", vInv);
//
// Message: getdata
//
vector<CInv> vGetData;
int64 nNow = GetTime() * 1000000;
CTxDB txdb("r");
while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
{
const CInv& inv = (*pto->mapAskFor.begin()).second;
if (!AlreadyHave(txdb, inv))
{
printf("sending getdata: %s\n", inv.ToString().c_str());
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
pto->PushMessage("getdata", vGetData);
vGetData.clear();
}
}
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
pto->PushMessage("getdata", vGetData);
}
return true;
}
//////////////////////////////////////////////////////////////////////////////
//
// BitcoinMiner
//
void GenerateBitcoins(bool fGenerate)
{
if (fGenerateBitcoins != fGenerate)
{
fGenerateBitcoins = fGenerate;
CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
MainFrameRepaint();
}
if (fGenerateBitcoins)
{
int nProcessors = wxThread::GetCPUCount();
printf("%d processors\n", nProcessors);
if (nProcessors < 1)
nProcessors = 1;
if (fLimitProcessors && nProcessors > nLimitProcessors)
nProcessors = nLimitProcessors;
int nAddThreads = nProcessors - vnThreadsRunning[3];
printf("Starting %d BitcoinMiner threads\n", nAddThreads);
for (int i = 0; i < nAddThreads; i++)
{
if (!CreateThread(ThreadBitcoinMiner, NULL))
printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
Sleep(10);
}
}
}
void ThreadBitcoinMiner(void* parg)
{
try
{
vnThreadsRunning[3]++;
BitcoinMiner();
vnThreadsRunning[3]--;
}
catch (std::exception& e) {
vnThreadsRunning[3]--;
PrintException(&e, "ThreadBitcoinMiner()");
} catch (...) {
vnThreadsRunning[3]--;
PrintException(NULL, "ThreadBitcoinMiner()");
}
printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
}
int FormatHashBlocks(void* pbuffer, unsigned int len)
{
unsigned char* pdata = (unsigned char*)pbuffer;
unsigned int blocks = 1 + ((len + 8) / 64);
unsigned char* pend = pdata + 64 * blocks;
memset(pdata + len, 0, 64 * blocks - len);
pdata[len] = 0x80;
unsigned int bits = len * 8;
pend[-1] = (bits >> 0) & 0xff;
pend[-2] = (bits >> 8) & 0xff;
pend[-3] = (bits >> 16) & 0xff;
pend[-4] = (bits >> 24) & 0xff;
return blocks;
}
using CryptoPP::ByteReverse;
static int detectlittleendian = 1;
void BlockSHA256(const void* pin, unsigned int nBlocks, void* pout)
{
unsigned int* pinput = (unsigned int*)pin;
unsigned int* pstate = (unsigned int*)pout;
CryptoPP::SHA256::InitState(pstate);
if (*(char*)&detectlittleendian != 0)
{
for (int n = 0; n < nBlocks; n++)
{
unsigned int pbuf[16];
for (int i = 0; i < 16; i++)
pbuf[i] = ByteReverse(pinput[n * 16 + i]);
CryptoPP::SHA256::Transform(pstate, pbuf);
}
for (int i = 0; i < 8; i++)
pstate[i] = ByteReverse(pstate[i]);
}
else
{
for (int n = 0; n < nBlocks; n++)
CryptoPP::SHA256::Transform(pstate, pinput + n * 16);
}
}
void BitcoinMiner()
{
printf("BitcoinMiner started\n");
CKey key;
key.MakeNewKey();
CBigNum bnExtraNonce = 0;
while (fGenerateBitcoins)
{
SetThreadPriority(THREAD_PRIORITY_LOWEST);
Sleep(50);
if (fShutdown)
return;
while (vNodes.empty())
{
Sleep(1000);
if (fShutdown)
return;
if (!fGenerateBitcoins)
return;
}
unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
CBlockIndex* pindexPrev = pindexBest;
unsigned int nBits = GetNextWorkRequired(pindexPrev);
//
// Create coinbase tx
//
CTransaction txNew;
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vin[0].scriptSig << nBits << ++bnExtraNonce;
txNew.vout.resize(1);
txNew.vout[0].scriptPubKey << key.GetPubKey() << OP_CHECKSIG;
//
// Create new block
//
auto_ptr<CBlock> pblock(new CBlock());
if (!pblock.get())
return;
// Add our coinbase tx as first transaction
pblock->vtx.push_back(txNew);
// Collect the latest transactions into the block
int64 nFees = 0;
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapTransactions)
{
CTxDB txdb("r");
map<uint256, CTxIndex> mapTestPool;
vector<char> vfAlreadyAdded(mapTransactions.size());
bool fFoundSomething = true;
unsigned int nBlockSize = 0;
while (fFoundSomething && nBlockSize < MAX_SIZE/2)
{
fFoundSomething = false;
unsigned int n = 0;
for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi, ++n)
{
if (vfAlreadyAdded[n])
continue;
CTransaction& tx = (*mi).second;
if (tx.IsCoinBase() || !tx.IsFinal())
continue;
// Transaction fee based on block size
int64 nMinFee = tx.GetMinFee(nBlockSize);
map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), 0, nFees, false, true, nMinFee))
continue;
swap(mapTestPool, mapTestPoolTmp);
pblock->vtx.push_back(tx);
nBlockSize += ::GetSerializeSize(tx, SER_NETWORK);
vfAlreadyAdded[n] = true;
fFoundSomething = true;
}
}
}
pblock->nBits = nBits;
pblock->vtx[0].vout[0].nValue = pblock->GetBlockValue(nFees);
printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());
//
// Prebuild hash buffer
//
struct unnamed1
{
struct unnamed2
{
int nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
}
block;
unsigned char pchPadding0[64];
uint256 hash1;
unsigned char pchPadding1[64];
}
tmp;
tmp.block.nVersion = pblock->nVersion;
tmp.block.hashPrevBlock = pblock->hashPrevBlock = (pindexPrev ? pindexPrev->GetBlockHash() : 0);
tmp.block.hashMerkleRoot = pblock->hashMerkleRoot = pblock->BuildMerkleTree();
tmp.block.nTime = pblock->nTime = max((pindexPrev ? pindexPrev->GetMedianTimePast()+1 : 0), GetAdjustedTime());
tmp.block.nBits = pblock->nBits = nBits;
tmp.block.nNonce = pblock->nNonce = 1;
unsigned int nBlocks0 = FormatHashBlocks(&tmp.block, sizeof(tmp.block));
unsigned int nBlocks1 = FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
//
// Search
//
int64 nStart = GetTime();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
uint256 hash;
loop
{
BlockSHA256(&tmp.block, nBlocks0, &tmp.hash1);
BlockSHA256(&tmp.hash1, nBlocks1, &hash);
if (hash <= hashTarget)
{
pblock->nNonce = tmp.block.nNonce;
assert(hash == pblock->GetHash());
//// debug print
printf("BitcoinMiner:\n");
printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
pblock->print();
SetThreadPriority(THREAD_PRIORITY_NORMAL);
CRITICAL_BLOCK(cs_main)
{
if (pindexPrev == pindexBest)
{
// Save key
if (!AddKey(key))
return;
key.MakeNewKey();
// Track how many getdata requests this block gets
CRITICAL_BLOCK(cs_mapRequestCount)
mapRequestCount[pblock->GetHash()] = 0;
// Process this block the same as if we had received it from another node
if (!ProcessBlock(NULL, pblock.release()))
printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n");
}
}
SetThreadPriority(THREAD_PRIORITY_LOWEST);
Sleep(500);
break;
}
// Update nTime every few seconds
if ((++tmp.block.nNonce & 0xffff) == 0)
{
if (fShutdown)
return;
if (!fGenerateBitcoins)
return;
if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
return;
if (vNodes.empty())
break;
if (tmp.block.nNonce == 0)
break;
if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
if (pindexPrev != pindexBest)
{
// Pause generating during initial download
if (GetTime() - nStart < 20)
{
CBlockIndex* pindexTmp;
do
{
pindexTmp = pindexBest;
for (int i = 0; i < 10; i++)
{
Sleep(1000);
if (fShutdown)
return;
}
}
while (pindexTmp != pindexBest);
}
break;
}
tmp.block.nTime = pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Actions
//
int64 GetBalance()
{
int64 nStart = GetTimeMillis();
int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsFinal() || pcoin->fSpent)
continue;
nTotal += pcoin->GetCredit(true);
}
}
//printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
return nTotal;
}
bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
{
setCoinsRet.clear();
// List of values less than target
int64 nLowestLarger = INT64_MAX;
CWalletTx* pcoinLowestLarger = NULL;
vector<pair<int64, CWalletTx*> > vValue;
int64 nTotalLower = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsFinal() || pcoin->fSpent)
continue;
int64 n = pcoin->GetCredit();
if (n <= 0)
continue;
if (n < nTargetValue)
{
vValue.push_back(make_pair(n, pcoin));
nTotalLower += n;
}
else if (n == nTargetValue)
{
setCoinsRet.insert(pcoin);
return true;
}
else if (n < nLowestLarger)
{
nLowestLarger = n;
pcoinLowestLarger = pcoin;
}
}
}
if (nTotalLower < nTargetValue)
{
if (pcoinLowestLarger == NULL)
return false;
setCoinsRet.insert(pcoinLowestLarger);
return true;
}
// Solve subset sum by stochastic approximation
sort(vValue.rbegin(), vValue.rend());
vector<char> vfIncluded;
vector<char> vfBest(vValue.size(), true);
int64 nBest = nTotalLower;
for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
{
vfIncluded.assign(vValue.size(), false);
int64 nTotal = 0;
bool fReachedTarget = false;
for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
{
for (int i = 0; i < vValue.size(); i++)
{
if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
{
nTotal += vValue[i].first;
vfIncluded[i] = true;
if (nTotal >= nTargetValue)
{
fReachedTarget = true;
if (nTotal < nBest)
{
nBest = nTotal;
vfBest = vfIncluded;
}
nTotal -= vValue[i].first;
vfIncluded[i] = false;
}
}
}
}
}
// If the next larger is still closer, return it
if (pcoinLowestLarger && nLowestLarger - nTargetValue <= nBest - nTargetValue)
setCoinsRet.insert(pcoinLowestLarger);
else
{
for (int i = 0; i < vValue.size(); i++)
if (vfBest[i])
setCoinsRet.insert(vValue[i].second);
//// debug print
printf("SelectCoins() best subset: ");
for (int i = 0; i < vValue.size(); i++)
if (vfBest[i])
printf("%s ", FormatMoney(vValue[i].first).c_str());
printf("total %s\n", FormatMoney(nBest).c_str());
}
return true;
}
bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CKey& keyRet, int64& nFeeRequiredRet)
{
nFeeRequiredRet = 0;
CRITICAL_BLOCK(cs_main)
{
// txdb must be opened before the mapWallet lock
CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
{
int64 nFee = nTransactionFee;
loop
{
wtxNew.vin.clear();
wtxNew.vout.clear();
wtxNew.fFromMe = true;
if (nValue < 0)
return false;
int64 nValueOut = nValue;
int64 nTotalValue = nValue + nFee;
// Choose coins to use
set<CWalletTx*> setCoins;
if (!SelectCoins(nTotalValue, setCoins))
return false;
int64 nValueIn = 0;
foreach(CWalletTx* pcoin, setCoins)
nValueIn += pcoin->GetCredit();
// Fill a vout to the payee
bool fChangeFirst = GetRand(2);
if (!fChangeFirst)
wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey));
// Fill a vout back to self with any change
if (nValueIn > nTotalValue)
{
// Note: We use a new key here to keep it from being obvious which side is the change.
// The drawback is that by not reusing a previous key, the change may be lost if a
// backup is restored, if the backup doesn't have the new private key for the change.
// If we reused the old key, it would be possible to add code to look for and
// rediscover unknown transactions that were written with keys of ours to recover
// post-backup change.
// New private key
if (keyRet.IsNull())
keyRet.MakeNewKey();
// Fill a vout to ourself, using same address type as the payment
CScript scriptChange;
if (scriptPubKey.GetBitcoinAddressHash160() != 0)
scriptChange.SetBitcoinAddress(keyRet.GetPubKey());
else
scriptChange << keyRet.GetPubKey() << OP_CHECKSIG;
wtxNew.vout.push_back(CTxOut(nValueIn - nTotalValue, scriptChange));
}
// Fill a vout to the payee
if (fChangeFirst)
wtxNew.vout.push_back(CTxOut(nValueOut, scriptPubKey));
// Fill vin
foreach(CWalletTx* pcoin, setCoins)
for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
if (pcoin->vout[nOut].IsMine())
wtxNew.vin.push_back(CTxIn(pcoin->GetHash(), nOut));
// Sign
int nIn = 0;
foreach(CWalletTx* pcoin, setCoins)
for (int nOut = 0; nOut < pcoin->vout.size(); nOut++)
if (pcoin->vout[nOut].IsMine())
SignSignature(*pcoin, wtxNew, nIn++);
// Check that enough fee is included
if (nFee < wtxNew.GetMinFee())
{
nFee = nFeeRequiredRet = wtxNew.GetMinFee();
continue;
}
// Fill vtxPrev by copying from previous transactions vtxPrev
wtxNew.AddSupportingTransactions(txdb);
wtxNew.fTimeReceivedIsTxTime = true;
break;
}
}
}
return true;
}
// Call after CreateTransaction unless you want to abort
bool CommitTransaction(CWalletTx& wtxNew, const CKey& key)
{
CRITICAL_BLOCK(cs_main)
{
printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
CRITICAL_BLOCK(cs_mapWallet)
{
// This is only to keep the database open to defeat the auto-flush for the
// duration of this scope. This is the only place where this optimization
// maybe makes sense; please don't do it anywhere else.
CWalletDB walletdb("r");
// Add the change's private key to wallet
if (!key.IsNull() && !AddKey(key))
throw runtime_error("CommitTransaction() : AddKey failed\n");
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
AddToWallet(wtxNew);
// Mark old coins as spent
set<CWalletTx*> setCoins;
foreach(const CTxIn& txin, wtxNew.vin)
setCoins.insert(&mapWallet[txin.prevout.hash]);
foreach(CWalletTx* pcoin, setCoins)
{
pcoin->fSpent = true;
pcoin->WriteToDisk();
vWalletUpdated.push_back(pcoin->GetHash());
}
}
// Track how many getdata requests our transaction gets
CRITICAL_BLOCK(cs_mapRequestCount)
mapRequestCount[wtxNew.GetHash()] = 0;
// Broadcast
if (!wtxNew.AcceptTransaction())
{
// This must not fail. The transaction has already been signed and recorded.
printf("CommitTransaction() : Error: Transaction not valid");
return false;
}
wtxNew.RelayWalletTransaction();
}
MainFrameRepaint();
return true;
}
string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
{
CRITICAL_BLOCK(cs_main)
{
CKey key;
int64 nFeeRequired;
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, key, nFeeRequired))
{
string strError;
if (nValue + nFeeRequired > GetBalance())
strError = strprintf(_("Error: This is an oversized transaction that requires a transaction fee of %s "), FormatMoney(nFeeRequired).c_str());
else
strError = _("Error: Transaction creation failed ");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
return "ABORTED";
if (!CommitTransaction(wtxNew, key))
return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
MainFrameRepaint();
return "";
}
string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
{
// Check amount
if (nValue <= 0)
return _("Invalid amount");
if (nValue + nTransactionFee > GetBalance())
return _("Insufficient funds");
// Parse bitcoin address
CScript scriptPubKey;
if (!scriptPubKey.SetBitcoinAddress(strAddress))
return _("Invalid bitcoin address");
return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
}
"%file: ./makefile.mingw"
# 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.
# for wxWidgets-2.8.x, search and replace "mswud"->"mswd" and "29u"->"28"
INCLUDEPATHS= \
-I"/boost" \
-I"/db/build_unix" \
-I"/openssl/include" \
-I"/wxwidgets/lib/gcc_lib/mswud" \
-I"/wxwidgets/include"
LIBPATHS= \
-L"/boost/stage/lib" \
-L"/db/build_unix" \
-L"/openssl/out" \
-L"/wxwidgets/lib/gcc_lib"
WXLIBS= \
-l wxmsw29ud_html -l wxmsw29ud_core -l wxmsw29ud_adv -l wxbase29ud -l wxtiffd -l wxjpegd -l wxpngd -l wxzlibd
LIBS= \
-l libboost_system-mgw34-mt-d -l libboost_filesystem-mgw34-mt-d \
-l db_cxx \
-l eay32 \
-l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi
WXDEFS=-DWIN32 -D__WXMSW__ -D_WINDOWS -DNOPCH
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-mthreads -O2 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h
all: bitcoin.exe
headers.h.gch: headers.h $(HEADERS)
g++ -c $(CFLAGS) -o $@ $<
obj/%.o: %.cpp $(HEADERS) headers.h.gch
g++ -c $(CFLAGS) -o $@ $<
obj/sha.o: sha.cpp sha.h
g++ -c $(CFLAGS) -O3 -o $@ $<
obj/ui_res.o: ui.rc rc/bitcoin.ico rc/check.ico rc/send16.bmp rc/send16mask.bmp rc/send16masknoshadow.bmp rc/send20.bmp rc/send20mask.bmp rc/addressbook16.bmp rc/addressbook16mask.bmp rc/addressbook20.bmp rc/addressbook20mask.bmp
windres $(WXDEFS) $(INCLUDEPATHS) -o $@ -i $<
OBJS= \
obj/util.o \
obj/script.o \
obj/db.o \
obj/net.o \
obj/irc.o \
obj/main.o \
obj/rpc.o \
obj/init.o
bitcoin.exe: $(OBJS) obj/ui.o obj/uibase.o obj/sha.o obj/ui_res.o
g++ $(CFLAGS) -mwindows -Wl,--subsystem,windows -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS)
obj/nogui/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -DwxUSE_GUI=0 -o $@ $<
bitcoind.exe: $(OBJS:obj/%=obj/nogui/%) obj/sha.o obj/ui_res.o
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -l wxbase29ud $(LIBS)
clean:
-del /Q obj\*
-del /Q obj\nogui\*
-del /Q headers.h.gch
/*
"%file: ./makefile.osx"
# 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.
# Mac OS X makefile for bitcoin
# Laszlo Hanyecz (solar@heliacal.net)
DEPSDIR=/Users/macosuser/bitcoin/deps
INCLUDEPATHS= \
-I"$(DEPSDIR)/include"
LIBPATHS= \
-L"$(DEPSDIR)/lib"
WXLIBS=$(shell $(DEPSDIR)/bin/wx-config --libs --static)
LIBS= -dead_strip \
$(DEPSDIR)/lib/libdb_cxx-4.8.a \
$(DEPSDIR)/lib/libboost_system.a \
$(DEPSDIR)/lib/libboost_filesystem.a \
$(DEPSDIR)/lib/libcrypto.a
WXDEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -DNOPCH -DMSG_NOSIGNAL=0
DEBUGFLAGS=-g -DwxDEBUG_LEVEL=0
# ppc doesn't work because we don't support big-endian
CFLAGS=-mmacosx-version-min=10.5 -arch i386 -arch x86_64 -O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h
all: bitcoin
obj/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -o $@ $<
obj/sha.o: sha.cpp sha.h
g++ -c $(CFLAGS) -O3 -o $@ $<
OBJS= \
obj/util.o \
obj/script.o \
obj/db.o \
obj/net.o \
obj/irc.o \
obj/main.o \
obj/rpc.o \
obj/init.o
bitcoin: $(OBJS) obj/ui.o obj/uibase.o obj/sha.o
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS)
obj/nogui/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -DwxUSE_GUI=0 -o $@ $<
bitcoind: $(OBJS:obj/%=obj/nogui/%) obj/sha.o
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS)
clean:
-rm -f obj/*.o
-rm -f obj/nogui/*.o
"%file: ./makefile.unix"
# 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.
INCLUDEPATHS= \
-I"/usr/include" \
-I"/usr/local/include/wx-2.9" \
-I"/usr/local/lib/wx/include/gtk2-unicode-debug-static-2.9"
LIBPATHS= \
-L"/usr/lib" \
-L"/usr/local/lib"
WXLIBS= \
-Wl,-Bstatic \
-l wx_gtk2ud-2.9 \
-Wl,-Bdynamic \
-l gtk-x11-2.0 -l SM
LIBS= \
-Wl,-Bstatic \
-l boost_system-mt -l boost_filesystem-mt \
-l db_cxx \
-Wl,-Bdynamic \
-l crypto \
-l gthread-2.0
WXDEFS=-D__WXGTK__ -DNOPCH
DEBUGFLAGS=-g -D__WXDEBUG__
CFLAGS=-O0 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h
all: bitcoin
headers.h.gch: headers.h $(HEADERS)
g++ -c $(CFLAGS) -o $@ $<
obj/%.o: %.cpp $(HEADERS) headers.h.gch
g++ -c $(CFLAGS) -o $@ $<
obj/sha.o: sha.cpp sha.h
g++ -c $(CFLAGS) -O3 -o $@ $<
OBJS= \
obj/util.o \
obj/script.o \
obj/db.o \
obj/net.o \
obj/irc.o \
obj/main.o \
obj/rpc.o \
obj/init.o
bitcoin: $(OBJS) obj/ui.o obj/uibase.o obj/sha.o
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(WXLIBS) $(LIBS)
obj/nogui/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -DwxUSE_GUI=0 -o $@ $<
bitcoind: $(OBJS:obj/%=obj/nogui/%) obj/sha.o
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -l wx_baseud-2.9 $(LIBS)
clean:
-rm obj/*
-rm obj/nogui/*
-rm headers.h.gch
"%file: ./makefile.vc"
# 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.
# for wxWidgets-2.8.x, search and replace "mswud"->"mswd" and "29u"->"28"
INCLUDEPATHS= \
/I"/boost" \
/I"/db/build_windows" \
/I"/openssl/include" \
/I"/wxwidgets/lib/vc_lib/mswud" \
/I"/wxwidgets/include"
LIBPATHS= \
/LIBPATH:"/boost/stage/lib" \
/LIBPATH:"/db/build_windows/debug" \
/LIBPATH:"/openssl/out" \
/LIBPATH:"/wxwidgets/lib/vc_lib"
LIBS= \
libboost_system-vc80-mt-gd.lib libboost_filesystem-vc80-mt-gd.lib \
libdb47sd.lib \
libeay32.lib \
wxmsw29ud_html.lib wxmsw29ud_core.lib wxmsw29ud_adv.lib wxbase29ud.lib wxtiffd.lib wxjpegd.lib wxpngd.lib wxzlibd.lib \
kernel32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib winmm.lib shell32.lib comctl32.lib ole32.lib oleaut32.lib uuid.lib rpcrt4.lib advapi32.lib ws2_32.lib shlwapi.lib
WXDEFS=/DWIN32 /D__WXMSW__ /D_WINDOWS /DNOPCH
DEBUGFLAGS=/Zi /Od /D__WXDEBUG__
CFLAGS=/c /nologo /Ob0 /MDd /EHsc /GR /Zm300 $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
script.h db.h net.h irc.h main.h rpc.h uibase.h ui.h init.h sha.h
all: bitcoin.exe
.cpp{obj}.obj:
cl $(CFLAGS) /Fo$@ %s
obj\util.obj: $(HEADERS)
obj\script.obj: $(HEADERS)
obj\db.obj: $(HEADERS)
obj\net.obj: $(HEADERS)
obj\irc.obj: $(HEADERS)
obj\main.obj: $(HEADERS)
obj\rpc.obj: $(HEADERS)
obj\init.obj: $(HEADERS)
obj\ui.obj: $(HEADERS)
obj\uibase.obj: $(HEADERS)
obj\sha.obj: sha.cpp sha.h
cl $(CFLAGS) /O2 /Fo$@ %s
obj\ui.res: ui.rc rc/bitcoin.ico rc/check.ico rc/send16.bmp rc/send16mask.bmp rc/send16masknoshadow.bmp rc/send20.bmp rc/send20mask.bmp rc/addressbook16.bmp rc/addressbook16mask.bmp rc/addressbook20.bmp rc/addressbook20mask.bmp
rc $(INCLUDEPATHS) $(WXDEFS) /Fo$@ %s
OBJS= \
obj\util.obj \
obj\script.obj \
obj\db.obj \
obj\net.obj \
obj\irc.obj \
obj\main.obj \
obj\rpc.obj \
obj\init.obj
bitcoin.exe: $(OBJS) obj\ui.obj obj\uibase.obj obj\sha.obj obj\ui.res
link /nologo /DEBUG /SUBSYSTEM:WINDOWS /OUT:$@ $(LIBPATHS) $** $(LIBS)
.cpp{obj\nogui}.obj:
cl $(CFLAGS) /DwxUSE_GUI=0 /Fo$@ %s
obj\nogui\util.obj: $(HEADERS)
obj\nogui\script.obj: $(HEADERS)
obj\nogui\db.obj: $(HEADERS)
obj\nogui\net.obj: $(HEADERS)
obj\nogui\irc.obj: $(HEADERS)
obj\nogui\main.obj: $(HEADERS)
obj\nogui\rpc.obj: $(HEADERS)
obj\nogui\init.obj: $(HEADERS)
bitcoind.exe: $(OBJS:obj\=obj\nogui\) obj\sha.obj obj\ui.res
link /nologo /DEBUG /OUT:$@ $(LIBPATHS) $** $(LIBS)
clean:
-del /Q obj\*
-del *.ilk
-del *.pdb
*/
"%file: ./net.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 CMessageHeader;
class CAddress;
class CInv;
class CRequestTracker;
class CNode;
class CBlockIndex;
extern int nBestHeight;
#define DEFAULT_PORT htons(8333)
static const unsigned int PUBLISH_HOPS = 5;
enum
{
NODE_NETWORK = (1 << 0),
};
bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet);
bool GetMyExternalIP(unsigned int& ipRet);
bool AddAddress(CAddress addr);
void AddressCurrentlyConnected(const CAddress& addr);
CNode* FindNode(unsigned int ip);
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
bool AnySubscribed(unsigned int nChannel);
bool BindListenPort(string& strError=REF(string()));
void StartNode(void* parg);
bool StopNode();
//
// Message header
// (4) message start
// (12) command
// (4) size
// (4) checksum
// The message start string is designed to be unlikely to occur in normal data.
// The characters are rarely used upper ascii, not valid as UTF-8, and produce
// a large 4-byte int at any alignment.
static const char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
class CMessageHeader
{
public:
enum { COMMAND_SIZE=12 };
char pchMessageStart[sizeof(::pchMessageStart)];
char pchCommand[COMMAND_SIZE];
unsigned int nMessageSize;
unsigned int nChecksum;
CMessageHeader()
{
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
memset(pchCommand, 0, sizeof(pchCommand));
pchCommand[1] = 1;
nMessageSize = -1;
nChecksum = 0;
}
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
{
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
strncpy(pchCommand, pszCommand, COMMAND_SIZE);
nMessageSize = nMessageSizeIn;
nChecksum = 0;
}
IMPLEMENT_SERIALIZE
(
READWRITE(FLATDATA(pchMessageStart));
READWRITE(FLATDATA(pchCommand));
READWRITE(nMessageSize);
if (nVersion >= 209)
READWRITE(nChecksum);
)
string GetCommand()
{
if (pchCommand[COMMAND_SIZE-1] == 0)
return string(pchCommand, pchCommand + strlen(pchCommand));
else
return string(pchCommand, pchCommand + COMMAND_SIZE);
}
bool IsValid()
{
// Check start string
if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
return false;
// Check the command string for errors
for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
{
if (*p1 == 0)
{
// Must be all zeros after the first zero
for (; p1 < pchCommand + COMMAND_SIZE; p1++)
if (*p1 != 0)
return false;
}
else if (*p1 < ' ' || *p1 > 0x7E)
return false;
}
// Message size
if (nMessageSize > 0x10000000)
{
printf("CMessageHeader::IsValid() : nMessageSize too large %u\n", nMessageSize);
return false;
}
return true;
}
};
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
class CAddress
{
public:
uint64 nServices;
unsigned char pchReserved[12];
unsigned int ip;
unsigned short port;
// disk only
unsigned int nTime;
// memory only
unsigned int nLastTry;
CAddress()
{
Init();
}
CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=NODE_NETWORK)
{
Init();
ip = ipIn;
port = portIn;
nServices = nServicesIn;
}
explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK)
{
Init();
ip = sockaddr.sin_addr.s_addr;
port = sockaddr.sin_port;
nServices = nServicesIn;
}
explicit CAddress(const char* pszIn, uint64 nServicesIn=NODE_NETWORK)
{
Init();
SetAddress(pszIn);
nServices = nServicesIn;
}
explicit CAddress(string strIn, uint64 nServicesIn=NODE_NETWORK)
{
Init();
SetAddress(strIn.c_str());
nServices = nServicesIn;
}
void Init()
{
nServices = NODE_NETWORK;
memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
ip = INADDR_NONE;
port = DEFAULT_PORT;
nTime = GetAdjustedTime();
nLastTry = 0;
}
bool SetAddress(const char* pszIn)
{
ip = INADDR_NONE;
port = DEFAULT_PORT;
char psz[100];
strlcpy(psz, pszIn, sizeof(psz));
unsigned int a=0, b=0, c=0, d=0, e=0;
if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4)
return false;
char* pszPort = strchr(psz, ':');
if (pszPort)
{
*pszPort++ = '\0';
port = htons(atoi(pszPort));
if (atoi(pszPort) < 0 || atoi(pszPort) > USHRT_MAX)
port = htons(USHRT_MAX);
}
ip = inet_addr(psz);
return IsValid();
}
bool SetAddress(string strIn)
{
return SetAddress(strIn.c_str());
}
IMPLEMENT_SERIALIZE
(
if (nType & SER_DISK)
{
READWRITE(nVersion);
READWRITE(nTime);
}
READWRITE(nServices);
READWRITE(FLATDATA(pchReserved)); // for IPv6
READWRITE(ip);
READWRITE(port);
)
friend inline bool operator==(const CAddress& a, const CAddress& b)
{
return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
a.ip == b.ip &&
a.port == b.port);
}
friend inline bool operator!=(const CAddress& a, const CAddress& b)
{
return (!(a == b));
}
friend inline bool operator<(const CAddress& a, const CAddress& b)
{
int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
if (ret < 0)
return true;
else if (ret == 0)
{
if (ntohl(a.ip) < ntohl(b.ip))
return true;
else if (a.ip == b.ip)
return ntohs(a.port) < ntohs(b.port);
}
return false;
}
vector<unsigned char> GetKey() const
{
CDataStream ss;
ss.reserve(18);
ss << FLATDATA(pchReserved) << ip << port;
#if defined(_MSC_VER) && _MSC_VER < 1300
return vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
#else
return vector<unsigned char>(ss.begin(), ss.end());
#endif
}
struct sockaddr_in GetSockAddr() const
{
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = ip;
sockaddr.sin_port = port;
return sockaddr;
}
bool IsIPv4() const
{
return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
}
bool IsRoutable() const
{
return IsValid() &&
!(GetByte(3) == 10 ||
(GetByte(3) == 192 && GetByte(2) == 168) ||
GetByte(3) == 127 ||
GetByte(3) == 0);
}
bool IsValid() const
{
// Clean up 3-byte shifted addresses caused by garbage in size field
// of addr messages from versions before 0.2.9 checksum.
// Two consecutive addr messages look like this:
// header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 addr26 addr26...
// so if the first length field is garbled, it reads the second batch
// of addr misaligned by 3 bytes.
if (memcmp(pchReserved, pchIPv4+3, sizeof(pchIPv4)-3) == 0)
return false;
return (ip != 0 && ip != INADDR_NONE && port != htons(USHRT_MAX));
}
unsigned char GetByte(int n) const
{
return ((unsigned char*)&ip)[3-n];
}
string ToStringIPPort() const
{
return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
}
string ToStringIP() const
{
return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
}
string ToStringPort() const
{
return strprintf("%u", ntohs(port));
}
string ToStringLog() const
{
return "";
}
string ToString() const
{
return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
}
void print() const
{
printf("CAddress(%s)\n", ToString().c_str());
}
};
enum
{
MSG_TX = 1,
MSG_BLOCK,
};
static const char* ppszTypeName[] =
{
"ERROR",
"tx",
"block",
};
class CInv
{
public:
int type;
uint256 hash;
CInv()
{
type = 0;
hash = 0;
}
CInv(int typeIn, const uint256& hashIn)
{
type = typeIn;
hash = hashIn;
}
CInv(const string& strType, const uint256& hashIn)
{
int i;
for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
{
if (strType == ppszTypeName[i])
{
type = i;
break;
}
}
if (i == ARRAYLEN(ppszTypeName))
throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
hash = hashIn;
}
IMPLEMENT_SERIALIZE
(
READWRITE(type);
READWRITE(hash);
)
friend inline bool operator<(const CInv& a, const CInv& b)
{
return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
}
bool IsKnownType() const
{
return (type >= 1 && type < ARRAYLEN(ppszTypeName));
}
const char* GetCommand() const
{
if (!IsKnownType())
throw std::out_of_range(strprintf("CInv::GetCommand() : type=% unknown type", type));
return ppszTypeName[type];
}
string ToString() const
{
return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,16).c_str());
}
void print() const
{
printf("CInv(%s)\n", ToString().c_str());
}
};
class CRequestTracker
{
public:
void (*fn)(void*, CDataStream&);
void* param1;
explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
{
fn = fnIn;
param1 = param1In;
}
bool IsNull()
{
return fn == NULL;
}
};
extern bool fClient;
extern uint64 nLocalServices;
extern CAddress addrLocalHost;
extern CNode* pnodeLocalHost;
extern uint64 nLocalHostNonce;
extern array<int, 10> vnThreadsRunning;
extern SOCKET hListenSocket;
extern int64 nThreadSocketHandlerHeartbeat;
extern vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
extern map<vector<unsigned char>, CAddress> mapAddresses;
extern CCriticalSection cs_mapAddresses;
extern map<CInv, CDataStream> mapRelay;
extern deque<pair<int64, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
extern map<CInv, int64> mapAlreadyAskedFor;
// Settings
extern int fUseProxy;
extern CAddress addrProxy;
class CNode
{
public:
// socket
uint64 nServices;
SOCKET hSocket;
CDataStream vSend;
CDataStream vRecv;
CCriticalSection cs_vSend;
CCriticalSection cs_vRecv;
int64 nLastSend;
int64 nLastRecv;
int64 nLastSendEmpty;
int64 nTimeConnected;
unsigned int nHeaderStart;
unsigned int nMessageStart;
CAddress addr;
int nVersion;
bool fClient;
bool fInbound;
bool fNetworkNode;
bool fSuccessfullyConnected;
bool fDisconnect;
protected:
int nRefCount;
public:
int64 nReleaseTime;
map<uint256, CRequestTracker> mapRequests;
CCriticalSection cs_mapRequests;
uint256 hashContinue;
CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd;
int nStartingHeight;
// flood
vector<CAddress> vAddrToSend;
set<CAddress> setAddrKnown;
bool fGetAddr;
// inventory based relay
set<CInv> setInventoryKnown;
vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory;
multimap<int64, CInv> mapAskFor;
// publish and subscription
vector<char> vfSubscribe;
CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
{
nServices = 0;
hSocket = hSocketIn;
vSend.SetType(SER_NETWORK);
vSend.SetVersion(0);
vRecv.SetType(SER_NETWORK);
vRecv.SetVersion(0);
// Version 0.2 obsoletes 20 Feb 2012
if (GetTime() > 1329696000)
{
vSend.SetVersion(209);
vRecv.SetVersion(209);
}
nLastSend = 0;
nLastRecv = 0;
nLastSendEmpty = GetTime();
nTimeConnected = GetTime();
nHeaderStart = -1;
nMessageStart = -1;
addr = addrIn;
nVersion = 0;
fClient = false; // set by version message
fInbound = fInboundIn;
fNetworkNode = false;
fSuccessfullyConnected = false;
fDisconnect = false;
nRefCount = 0;
nReleaseTime = 0;
hashContinue = 0;
pindexLastGetBlocksBegin = 0;
hashLastGetBlocksEnd = 0;
nStartingHeight = -1;
fGetAddr = false;
vfSubscribe.assign(256, false);
// Push a version message
/// when NTP implemented, change to just nTime = GetAdjustedTime()
int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, string(pszSubVer), nBestHeight);
}
~CNode()
{
if (hSocket != INVALID_SOCKET)
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
}
private:
CNode(const CNode&);
void operator=(const CNode&);
public:
int GetRefCount()
{
return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
}
CNode* AddRef(int64 nTimeout=0)
{
if (nTimeout != 0)
nReleaseTime = max(nReleaseTime, GetTime() + nTimeout);
else
nRefCount++;
return this;
}
void Release()
{
nRefCount--;
}
void AddAddressKnown(const CAddress& addr)
{
setAddrKnown.insert(addr);
}
void PushAddress(const CAddress& addr)
{
// Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added
// after addresses were pushed.
if (addr.IsValid() && !setAddrKnown.count(addr))
vAddrToSend.push_back(addr);
}
void AddInventoryKnown(const CInv& inv)
{
CRITICAL_BLOCK(cs_inventory)
setInventoryKnown.insert(inv);
}
void PushInventory(const CInv& inv)
{
CRITICAL_BLOCK(cs_inventory)
if (!setInventoryKnown.count(inv))
vInventoryToSend.push_back(inv);
}
void AskFor(const CInv& inv)
{
// We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent
int64& nRequestTime = mapAlreadyAskedFor[inv];
printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
// Make sure not to reuse time indexes to keep things in the same order
int64 nNow = (GetTime() - 1) * 1000000;
static int64 nLastTime;
nLastTime = nNow = max(nNow, ++nLastTime);
// Each retry is 2 minutes after the last
nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow);
mapAskFor.insert(make_pair(nRequestTime, inv));
}
void BeginMessage(const char* pszCommand)
{
cs_vSend.Enter();
if (nHeaderStart != -1)
AbortMessage();
nHeaderStart = vSend.size();
vSend << CMessageHeader(pszCommand, 0);
nMessageStart = vSend.size();
if (fDebug)
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("sending: %s ", pszCommand);
}
void AbortMessage()
{
if (nHeaderStart == -1)
return;
vSend.resize(nHeaderStart);
nHeaderStart = -1;
nMessageStart = -1;
cs_vSend.Leave();
printf("(aborted)\n");
}
void EndMessage()
{
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
printf("dropmessages DROPPING SEND MESSAGE\n");
AbortMessage();
return;
}
if (nHeaderStart == -1)
return;
// Set the size
unsigned int nSize = vSend.size() - nMessageStart;
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
// Set the checksum
if (vSend.GetVersion() >= 209)
{
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum));
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum));
}
printf("(%d bytes) ", nSize);
printf("\n");
nHeaderStart = -1;
nMessageStart = -1;
cs_vSend.Leave();
}
void EndMessageAbortIfEmpty()
{
if (nHeaderStart == -1)
return;
int nSize = vSend.size() - nMessageStart;
if (nSize > 0)
EndMessage();
else
AbortMessage();
}
const char* GetMessageCommand() const
{
if (nHeaderStart == -1)
return "";
return &vSend[nHeaderStart] + offsetof(CMessageHeader, pchCommand);
}
void PushMessage(const char* pszCommand)
{
try
{
BeginMessage(pszCommand);
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1>
void PushMessage(const char* pszCommand, const T1& a1)
{
try
{
BeginMessage(pszCommand);
vSend << a1;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
void PushRequest(const char* pszCommand,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
CRITICAL_BLOCK(cs_mapRequests)
mapRequests[hashReply] = CRequestTracker(fn, param1);
PushMessage(pszCommand, hashReply);
}
template<typename T1>
void PushRequest(const char* pszCommand, const T1& a1,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
CRITICAL_BLOCK(cs_mapRequests)
mapRequests[hashReply] = CRequestTracker(fn, param1);
PushMessage(pszCommand, hashReply, a1);
}
template<typename T1, typename T2>
void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
CRITICAL_BLOCK(cs_mapRequests)
mapRequests[hashReply] = CRequestTracker(fn, param1);
PushMessage(pszCommand, hashReply, a1, a2);
}
void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
bool IsSubscribed(unsigned int nChannel);
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel);
void CloseSocketDisconnect();
void Cleanup();
};
inline void RelayInventory(const CInv& inv)
{
// Put on lists to offer to the other nodes
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
pnode->PushInventory(inv);
}
template<typename T>
void RelayMessage(const CInv& inv, const T& a)
{
CDataStream ss(SER_NETWORK);
ss.reserve(10000);
ss << a;
RelayMessage(inv, ss);
}
template<>
inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
{
CRITICAL_BLOCK(cs_mapRelay)
{
// Expire old relay messages
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
{
mapRelay.erase(vRelayExpiration.front().second);
vRelayExpiration.pop_front();
}
// Save original serialized message so newer versions are preserved
mapRelay[inv] = ss;
vRelayExpiration.push_back(make_pair(GetTime() + 15 * 60, inv));
}
RelayInventory(inv);
}
//
// Templates for the publish and subscription system.
// The object being published as T& obj needs to have:
// a set<unsigned int> setSources member
// specializations of AdvertInsert and AdvertErase
// Currently implemented for CTable and CProduct.
//
template<typename T>
void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
{
// Add to sources
obj.setSources.insert(pfrom->addr.ip);
if (!AdvertInsert(obj))
return;
// Relay
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
pnode->PushMessage("publish", nChannel, nHops, obj);
}
template<typename T>
void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
{
uint256 hash = obj.GetHash();
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
AdvertErase(obj);
}
template<typename T>
void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
{
// Remove a source
obj.setSources.erase(pfrom->addr.ip);
// If no longer supported by any sources, cancel it
if (obj.setSources.empty())
AdvertStopPublish(pfrom, nChannel, nHops, obj);
}
"%file: ./net.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 ThreadMessageHandler2(void* parg);
void ThreadSocketHandler2(void* parg);
void ThreadOpenConnections2(void* parg);
bool OpenNetworkConnection(const CAddress& addrConnect);
//
// Global state variables
//
bool fClient = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices);
CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0;
array<int, 10> vnThreadsRunning;
SOCKET hListenSocket = INVALID_SOCKET;
int64 nThreadSocketHandlerHeartbeat = INT64_MAX;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
map<vector<unsigned char>, CAddress> mapAddresses;
CCriticalSection cs_mapAddresses;
map<CInv, CDataStream> mapRelay;
deque<pair<int64, CInv> > vRelayExpiration;
CCriticalSection cs_mapRelay;
map<CInv, int64> mapAlreadyAskedFor;
// Settings
int fUseProxy = false;
CAddress addrProxy("127.0.0.1:9050");
void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
{
// Filter out duplicate requests
if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
return;
pindexLastGetBlocksBegin = pindexBegin;
hashLastGetBlocksEnd = hashEnd;
PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
}
bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
{
hSocketRet = INVALID_SOCKET;
SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
return false;
#if defined(__BSD__) || defined(__WXOSX__)
int set = 1;
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif
bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168));
bool fProxy = (fUseProxy && fRoutable);
struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
{
closesocket(hSocket);
return false;
}
if (fProxy)
{
printf("proxy connecting %s\n", addrConnect.ToStringLog().c_str());
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
char* pszSocks4 = pszSocks4IP;
int nSize = sizeof(pszSocks4IP);
int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
if (ret != nSize)
{
closesocket(hSocket);
return error("Error sending to proxy");
}
char pchRet[8];
if (recv(hSocket, pchRet, 8, 0) != 8)
{
closesocket(hSocket);
return error("Error reading proxy response");
}
if (pchRet[1] != 0x5a)
{
closesocket(hSocket);
if (pchRet[1] != 0x5b)
printf("ERROR: Proxy returned error %d\n", pchRet[1]);
return false;
}
printf("proxy connected %s\n", addrConnect.ToStringLog().c_str());
}
hSocketRet = hSocket;
return true;
}
bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
{
SOCKET hSocket;
if (!ConnectSocket(addrConnect, hSocket))
return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());
send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);
string strLine;
while (RecvLine(hSocket, strLine))
{
if (strLine.empty())
{
loop
{
if (!RecvLine(hSocket, strLine))
{
closesocket(hSocket);
return false;
}
if (strLine.find(pszKeyword) != -1)
{
strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
break;
}
}
closesocket(hSocket);
if (strLine.find("<"))
strLine = strLine.substr(0, strLine.find("<"));
strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
strLine.resize(strLine.size()-1);
CAddress addr(strLine.c_str());
printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
return false;
ipRet = addr.ip;
return true;
}
}
closesocket(hSocket);
return error("GetMyExternalIP() : connection closed");
}
bool GetMyExternalIP(unsigned int& ipRet)
{
CAddress addrConnect;
const char* pszGet;
const char* pszKeyword;
if (fUseProxy)
return false;
for (int nLookup = 0; nLookup <= 1; nLookup++)
for (int nHost = 1; nHost <= 2; nHost++)
{
if (nHost == 1)
{
addrConnect = CAddress("70.86.96.218:80"); // www.ipaddressworld.com
if (nLookup == 1)
{
struct hostent* phostent = gethostbyname("www.ipaddressworld.com");
if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80));
}
pszGet = "GET /ip.php HTTP/1.1\r\n"
"Host: www.ipaddressworld.com\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
"Connection: close\r\n"
"\r\n";
pszKeyword = "IP:";
}
else if (nHost == 2)
{
addrConnect = CAddress("208.78.68.70:80"); // checkip.dyndns.org
if (nLookup == 1)
{
struct hostent* phostent = gethostbyname("checkip.dyndns.org");
if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80));
}
pszGet = "GET / HTTP/1.1\r\n"
"Host: checkip.dyndns.org\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
"Connection: close\r\n"
"\r\n";
pszKeyword = "Address:";
}
if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
return true;
}
return false;
}
bool AddAddress(CAddress addr)
{
if (!addr.IsRoutable())
return false;
if (addr.ip == addrLocalHost.ip)
return false;
CRITICAL_BLOCK(cs_mapAddresses)
{
map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
if (it == mapAddresses.end())
{
// New address
printf("AddAddress(%s)\n", addr.ToStringLog().c_str());
mapAddresses.insert(make_pair(addr.GetKey(), addr));
CAddrDB().WriteAddress(addr);
return true;
}
else
{
bool fUpdated = false;
CAddress& addrFound = (*it).second;
if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
{
// Services have been added
addrFound.nServices |= addr.nServices;
fUpdated = true;
}
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
if (addrFound.nTime < addr.nTime - nUpdateInterval)
{
// Periodically update most recently seen time
addrFound.nTime = addr.nTime;
fUpdated = true;
}
if (fUpdated)
CAddrDB().WriteAddress(addrFound);
}
}
return false;
}
void AddressCurrentlyConnected(const CAddress& addr)
{
CRITICAL_BLOCK(cs_mapAddresses)
{
// Only if it's been published already
map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
if (it != mapAddresses.end())
{
CAddress& addrFound = (*it).second;
int64 nUpdateInterval = 20 * 60;
if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
{
// Periodically update most recently seen time
addrFound.nTime = GetAdjustedTime();
CAddrDB addrdb;
addrdb.WriteAddress(addrFound);
}
}
}
}
void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
{
// If the dialog might get closed before the reply comes back,
// call this in the destructor so it doesn't get called after it's deleted.
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodes)
{
CRITICAL_BLOCK(pnode->cs_mapRequests)
{
for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
{
CRequestTracker& tracker = (*mi).second;
if (tracker.fn == fn && tracker.param1 == param1)
pnode->mapRequests.erase(mi++);
else
mi++;
}
}
}
}
}
//
// Subscription methods for the broadcast and subscription system.
// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
//
// The subscription system uses a meet-in-the-middle strategy.
// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
//
bool AnySubscribed(unsigned int nChannel)
{
if (pnodeLocalHost->IsSubscribed(nChannel))
return true;
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
if (pnode->IsSubscribed(nChannel))
return true;
return false;
}
bool CNode::IsSubscribed(unsigned int nChannel)
{
if (nChannel >= vfSubscribe.size())
return false;
return vfSubscribe[nChannel];
}
void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
{
if (nChannel >= vfSubscribe.size())
return;
if (!AnySubscribed(nChannel))
{
// Relay subscribe
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
if (pnode != this)
pnode->PushMessage("subscribe", nChannel, nHops);
}
vfSubscribe[nChannel] = true;
}
void CNode::CancelSubscribe(unsigned int nChannel)
{
if (nChannel >= vfSubscribe.size())
return;
// Prevent from relaying cancel if wasn't subscribed
if (!vfSubscribe[nChannel])
return;
vfSubscribe[nChannel] = false;
if (!AnySubscribed(nChannel))
{
// Relay subscription cancel
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
if (pnode != this)
pnode->PushMessage("sub-cancel", nChannel);
}
}
CNode* FindNode(unsigned int ip)
{
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodes)
if (pnode->addr.ip == ip)
return (pnode);
}
return NULL;
}
CNode* FindNode(CAddress addr)
{
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodes)
if (pnode->addr == addr)
return (pnode);
}
return NULL;
}
CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
{
if (addrConnect.ip == addrLocalHost.ip)
return NULL;
// Look for an existing connection
CNode* pnode = FindNode(addrConnect.ip);
if (pnode)
{
if (nTimeout != 0)
pnode->AddRef(nTimeout);
else
pnode->AddRef();
return pnode;
}
/// debug print
printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
addrConnect.ToStringLog().c_str(),
(double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
(double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
CRITICAL_BLOCK(cs_mapAddresses)
mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
// Connect
SOCKET hSocket;
if (ConnectSocket(addrConnect, hSocket))
{
/// debug print
printf("connected %s\n", addrConnect.ToStringLog().c_str());
// Set to nonblocking
#ifdef __WXMSW__
u_long nOne = 1;
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
#else
if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno);
#endif
// Add node
CNode* pnode = new CNode(hSocket, addrConnect, false);
if (nTimeout != 0)
pnode->AddRef(nTimeout);
else
pnode->AddRef();
CRITICAL_BLOCK(cs_vNodes)
vNodes.push_back(pnode);
pnode->nTimeConnected = GetTime();
return pnode;
}
else
{
return NULL;
}
}
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
if (hSocket != INVALID_SOCKET)
{
if (fDebug)
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("disconnecting node %s\n", addr.ToStringLog().c_str());
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
}
void CNode::Cleanup()
{
// All of a nodes broadcasts and subscriptions are automatically torn down
// when it goes down, so a node has to stay up to keep its broadcast going.
// Cancel subscriptions
for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
if (vfSubscribe[nChannel])
CancelSubscribe(nChannel);
}
void ThreadSocketHandler(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
try
{
vnThreadsRunning[0]++;
ThreadSocketHandler2(parg);
vnThreadsRunning[0]--;
}
catch (std::exception& e) {
vnThreadsRunning[0]--;
PrintException(&e, "ThreadSocketHandler()");
} catch (...) {
vnThreadsRunning[0]--;
throw; // support pthread_cancel()
}
printf("ThreadSocketHandler exiting\n");
}
void ThreadSocketHandler2(void* parg)
{
printf("ThreadSocketHandler started\n");
list<CNode*> vNodesDisconnected;
int nPrevNodeCount = 0;
loop
{
//
// Disconnect nodes
//
CRITICAL_BLOCK(cs_vNodes)
{
// Disconnect unused nodes
vector<CNode*> vNodesCopy = vNodes;
foreach(CNode* pnode, vNodesCopy)
{
if (pnode->fDisconnect ||
(pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
{
// remove from vNodes
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
// close socket and cleanup
pnode->CloseSocketDisconnect();
pnode->Cleanup();
// hold in disconnected pool until all refs are released
pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
if (pnode->fNetworkNode || pnode->fInbound)
pnode->Release();
vNodesDisconnected.push_back(pnode);
}
}
// Delete disconnected nodes
list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
foreach(CNode* pnode, vNodesDisconnectedCopy)
{
// wait until threads are done using it
if (pnode->GetRefCount() <= 0)
{
bool fDelete = false;
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
TRY_CRITICAL_BLOCK(pnode->cs_inventory)
fDelete = true;
if (fDelete)
{
vNodesDisconnected.remove(pnode);
delete pnode;
}
}
}
}
if (vNodes.size() != nPrevNodeCount)
{
nPrevNodeCount = vNodes.size();
MainFrameRepaint();
}
//
// Find which sockets have data to receive
//
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50000; // frequency to poll pnode->vSend
fd_set fdsetRecv;
fd_set fdsetSend;
fd_set fdsetError;
FD_ZERO(&fdsetRecv);
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
SOCKET hSocketMax = 0;
FD_SET(hListenSocket, &fdsetRecv);
hSocketMax = max(hSocketMax, hListenSocket);
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodes)
{
if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)
continue;
FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError);
hSocketMax = max(hSocketMax, pnode->hSocket);
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
if (!pnode->vSend.empty())
FD_SET(pnode->hSocket, &fdsetSend);
}
}
vnThreadsRunning[0]--;
int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
vnThreadsRunning[0]++;
if (fShutdown)
return;
if (nSelect == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
printf("socket select error %d\n", nErr);
for (int i = 0; i <= hSocketMax; i++)
FD_SET(i, &fdsetRecv);
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
Sleep(timeout.tv_usec/1000);
}
//
// Accept new connections
//
if (FD_ISSET(hListenSocket, &fdsetRecv))
{
struct sockaddr_in sockaddr;
socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
CAddress addr(sockaddr);
if (hSocket == INVALID_SOCKET)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
printf("socket error accept failed: %d\n", WSAGetLastError());
}
else
{
printf("accepted connection %s\n", addr.ToStringLog().c_str());
CNode* pnode = new CNode(hSocket, addr, true);
pnode->AddRef();
CRITICAL_BLOCK(cs_vNodes)
vNodes.push_back(pnode);
}
}
//
// Service each socket
//
vector<CNode*> vNodesCopy;
CRITICAL_BLOCK(cs_vNodes)
{
vNodesCopy = vNodes;
foreach(CNode* pnode, vNodesCopy)
pnode->AddRef();
}
foreach(CNode* pnode, vNodesCopy)
{
if (fShutdown)
return;
//
// Receive
//
if (pnode->hSocket == INVALID_SOCKET)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
{
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
{
CDataStream& vRecv = pnode->vRecv;
unsigned int nPos = vRecv.size();
// typical socket buffer is 8K-64K
char pchBuf[0x10000];
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
if (nBytes > 0)
{
vRecv.resize(nPos + nBytes);
memcpy(&vRecv[nPos], pchBuf, nBytes);
pnode->nLastRecv = GetTime();
}
else if (nBytes == 0)
{
// socket closed gracefully
if (!pnode->fDisconnect)
printf("socket closed\n");
pnode->CloseSocketDisconnect();
}
else if (nBytes < 0)
{
// error
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
if (!pnode->fDisconnect)
printf("socket recv error %d\n", nErr);
pnode->CloseSocketDisconnect();
}
}
}
}
//
// Send
//
if (pnode->hSocket == INVALID_SOCKET)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetSend))
{
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
{
CDataStream& vSend = pnode->vSend;
if (!vSend.empty())
{
int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
if (nBytes > 0)
{
vSend.erase(vSend.begin(), vSend.begin() + nBytes);
pnode->nLastSend = GetTime();
}
else if (nBytes < 0)
{
// error
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
printf("socket send error %d\n", nErr);
pnode->CloseSocketDisconnect();
}
}
}
}
}
//
// Inactivity checking
//
if (pnode->vSend.empty())
pnode->nLastSendEmpty = GetTime();
if (GetTime() - pnode->nTimeConnected > 60)
{
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
{
printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
pnode->fDisconnect = true;
}
else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
{
printf("socket not sending\n");
pnode->fDisconnect = true;
}
else if (GetTime() - pnode->nLastRecv > 90*60)
{
printf("socket inactivity timeout\n");
pnode->fDisconnect = true;
}
}
}
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodesCopy)
pnode->Release();
}
nThreadSocketHandlerHeartbeat = GetTime();
Sleep(10);
}
}
unsigned int pnSeed[] =
{
0x35218252, 0x9c9c9618, 0xda6bacad, 0xb9aca862, 0x97c235c6,
0x146f9562, 0xb67b9e4b, 0x87cf4bc0, 0xb83945d0, 0x984333ad,
0xbbeec555, 0x6f0eb440, 0xe0005318, 0x7797e460, 0xddc60fcc,
0xb3bbd24a, 0x1ac85746, 0x641846a6, 0x85ee1155, 0xbb2e7a4c,
0x9cb8514b, 0xfc342648, 0x62958fae, 0xd0a8c87a, 0xa800795b,
0xda8c814e, 0x256a0c80, 0x3f23ec63, 0xd565df43, 0x997d9044,
0xaa121448, 0xbed8688e, 0x59d09a5e, 0xb2931243, 0x3730ba18,
0xdd3462d0, 0x4e4d1448, 0x171df645, 0x84ee1155,
0x248ac445, 0x0e634444, 0x0ded1b63, 0x30c01e60,
0xa2b9a094, 0x29e4fd43, 0x9ce61b4c, 0xdae09744,
};
void ThreadOpenConnections(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
try
{
vnThreadsRunning[1]++;
ThreadOpenConnections2(parg);
vnThreadsRunning[1]--;
}
catch (std::exception& e) {
vnThreadsRunning[1]--;
PrintException(&e, "ThreadOpenConnections()");
} catch (...) {
vnThreadsRunning[1]--;
PrintException(NULL, "ThreadOpenConnections()");
}
printf("ThreadOpenConnections exiting\n");
}
void ThreadOpenConnections2(void* parg)
{
printf("ThreadOpenConnections started\n");
// Connect to specific addresses
if (mapArgs.count("-connect"))
{
for (int64 nLoop = 0;; nLoop++)
{
foreach(string strAddr, mapMultiArgs["-connect"])
{
CAddress addr(strAddr, NODE_NETWORK);
if (addr.IsValid())
OpenNetworkConnection(addr);
for (int i = 0; i < 10 && i < nLoop; i++)
{
Sleep(500);
if (fShutdown)
return;
}
}
}
}
// Connect to manually added nodes first
if (mapArgs.count("-addnode"))
{
foreach(string strAddr, mapMultiArgs["-addnode"])
{
CAddress addr(strAddr, NODE_NETWORK);
if (addr.IsValid())
{
OpenNetworkConnection(addr);
Sleep(500);
if (fShutdown)
return;
}
}
}
// Initiate network connections
int64 nStart = GetTime();
loop
{
// Wait
vnThreadsRunning[1]--;
Sleep(500);
const int nMaxConnections = 15;
while (vNodes.size() >= nMaxConnections)
{
Sleep(2000);
if (fShutdown)
return;
}
vnThreadsRunning[1]++;
if (fShutdown)
return;
CRITICAL_BLOCK(cs_mapAddresses)
{
// Add seed nodes if IRC isn't working
static bool fSeedUsed;
bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR))
{
for (int i = 0; i < ARRAYLEN(pnSeed); i++)
{
// It'll only connect to one or two seed nodes because once it connects,
// it'll get a pile of addresses with newer timestamps.
CAddress addr;
addr.ip = pnSeed[i];
addr.nTime = 0;
AddAddress(addr);
}
fSeedUsed = true;
}
if (fSeedUsed && mapAddresses.size() > ARRAYLEN(pnSeed) + 100)
{
// Disconnect seed nodes
set<unsigned int> setSeed(pnSeed, pnSeed + ARRAYLEN(pnSeed));
static int64 nSeedDisconnected;
if (nSeedDisconnected == 0)
{
nSeedDisconnected = GetTime();
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
if (setSeed.count(pnode->addr.ip))
pnode->fDisconnect = true;
}
// Keep setting timestamps to 0 so they won't reconnect
if (GetTime() - nSeedDisconnected < 60 * 60)
{
foreach(PAIRTYPE(const vector<unsigned char>, CAddress)& item, mapAddresses)
{
if (setSeed.count(item.second.ip))
{
item.second.nTime = 0;
CAddrDB().WriteAddress(item.second);
}
}
}
}
}
//
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect;
int64 nBest = INT64_MIN;
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect
set<unsigned int> setConnected;
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
setConnected.insert(pnode->addr.ip);
CRITICAL_BLOCK(cs_mapAddresses)
{
foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
const CAddress& addr = item.second;
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip))
continue;
int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
// Randomize the order in a deterministic way, putting the standard port first
int64 nRandomizer = (uint64)(nStart + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
if (addr.port != DEFAULT_PORT)
nRandomizer += 2 * 60 * 60;
// Last seen Base retry frequency
// <1 hour 10 min
// 1 hour 1 hour
// 4 hours 2 hours
// 24 hours 5 hours
// 48 hours 7 hours
// 7 days 13 hours
// 30 days 27 hours
// 90 days 46 hours
// 365 days 93 hours
int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
// Fast reconnect for one hour after last seen
if (nSinceLastSeen < 60 * 60)
nDelay = 10 * 60;
// Limit retry frequency
if (nSinceLastTry < nDelay)
continue;
// If we have IRC, we'll be notified when they first come online,
// and again every 24 hours by the refresh broadcast.
if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
continue;
// Only try the old stuff if we don't have enough connections
if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
continue;
// If multiple addresses are ready, prioritize by time since
// last seen and time since last tried.
int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
if (nScore > nBest)
{
nBest = nScore;
addrConnect = addr;
}
}
}
if (addrConnect.IsValid())
OpenNetworkConnection(addrConnect);
}
}
bool OpenNetworkConnection(const CAddress& addrConnect)
{
//
// Initiate outbound network connection
//
if (fShutdown)
return false;
if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
return false;
vnThreadsRunning[1]--;
CNode* pnode = ConnectNode(addrConnect);
vnThreadsRunning[1]++;
if (fShutdown)
return false;
if (!pnode)
return false;
pnode->fNetworkNode = true;
if (addrLocalHost.IsRoutable() && !fUseProxy)
{
// Advertise our address
vector<CAddress> vAddr;
vAddr.push_back(addrLocalHost);
pnode->PushMessage("addr", vAddr);
}
// Get as many addresses as we can
pnode->PushMessage("getaddr");
pnode->fGetAddr = true; // don't relay the results of the getaddr
////// should the one on the receiving end do this too?
// Subscribe our local subscription list
const unsigned int nHops = 0;
for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++)
if (pnodeLocalHost->vfSubscribe[nChannel])
pnode->PushMessage("subscribe", nChannel, nHops);
return true;
}
void ThreadMessageHandler(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
try
{
vnThreadsRunning[2]++;
ThreadMessageHandler2(parg);
vnThreadsRunning[2]--;
}
catch (std::exception& e) {
vnThreadsRunning[2]--;
PrintException(&e, "ThreadMessageHandler()");
} catch (...) {
vnThreadsRunning[2]--;
PrintException(NULL, "ThreadMessageHandler()");
}
printf("ThreadMessageHandler exiting\n");
}
void ThreadMessageHandler2(void* parg)
{
printf("ThreadMessageHandler started\n");
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
while (!fShutdown)
{
vector<CNode*> vNodesCopy;
CRITICAL_BLOCK(cs_vNodes)
{
vNodesCopy = vNodes;
foreach(CNode* pnode, vNodesCopy)
pnode->AddRef();
}
// Poll the connected nodes for messages
CNode* pnodeTrickle = NULL;
if (!vNodesCopy.empty())
pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
foreach(CNode* pnode, vNodesCopy)
{
// Receive messages
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
ProcessMessages(pnode);
if (fShutdown)
return;
// Send messages
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
SendMessages(pnode, pnode == pnodeTrickle);
if (fShutdown)
return;
}
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodesCopy)
pnode->Release();
}
// Wait and allow messages to bunch up
vnThreadsRunning[2]--;
Sleep(100);
vnThreadsRunning[2]++;
if (fShutdown)
return;
}
}
bool BindListenPort(string& strError)
{
strError = "";
int nOne = 1;
#ifdef __WXMSW__
// Initialize Windows Sockets
WSADATA wsadata;
int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
if (ret != NO_ERROR)
{
strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
printf("%s\n", strError.c_str());
return false;
}
#endif
// Create socket for listening for incoming connections
hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hListenSocket == INVALID_SOCKET)
{
strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
printf("%s\n", strError.c_str());
return false;
}
#if defined(__BSD__) || defined(__WXOSX__)
// Different way of disabling SIGPIPE on BSD
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
#ifndef __WXMSW__
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted. Not an issue on windows.
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
#endif
#ifdef __WXMSW__
// Set to nonblocking, incoming connections will also inherit this
if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
#else
if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
#endif
{
strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
printf("%s\n", strError.c_str());
return false;
}
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
sockaddr.sin_port = DEFAULT_PORT;
if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
strError = strprintf("Unable to bind to port %d on this computer. Bitcoin is probably already running.", ntohs(sockaddr.sin_port));
else
strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
printf("%s\n", strError.c_str());
return false;
}
printf("Bound to port %d\n", ntohs(sockaddr.sin_port));
// Listen for incoming connections
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
{
strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
printf("%s\n", strError.c_str());
return false;
}
return true;
}
void StartNode(void* parg)
{
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));
#ifdef __WXMSW__
// Get local host ip
char pszHostName[1000] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
{
struct hostent* phostent = gethostbyname(pszHostName);
if (phostent)
{
// Take the first IP that isn't loopback 127.x.x.x
for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());
for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
{
CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);
if (addr.IsValid() && addr.GetByte(3) != 127)
{
addrLocalHost = addr;
break;
}
}
}
}
#else
// Get local host ip
struct ifaddrs* myaddrs;
if (getifaddrs(&myaddrs) == 0)
{
for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL) continue;
if ((ifa->ifa_flags & IFF_UP) == 0) continue;
if (strcmp(ifa->ifa_name, "lo") == 0) continue;
if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
char pszIP[100];
if (ifa->ifa_addr->sa_family == AF_INET)
{
struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
// Take the first IP that isn't loopback 127.x.x.x
CAddress addr(*(unsigned int*)&s4->sin_addr, DEFAULT_PORT, nLocalServices);
if (addr.IsValid() && addr.GetByte(3) != 127)
{
addrLocalHost = addr;
break;
}
}
else if (ifa->ifa_addr->sa_family == AF_INET6)
{
struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
}
}
freeifaddrs(myaddrs);
}
#endif
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
// Get our external IP address for incoming connections
if (fUseProxy)
{
// Proxies can't take incoming connections
addrLocalHost.ip = CAddress("0.0.0.0").ip;
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
}
else
{
if (addrIncoming.IsValid())
addrLocalHost.ip = addrIncoming.ip;
if (GetMyExternalIP(addrLocalHost.ip))
{
addrIncoming = addrLocalHost;
CWalletDB().WriteSetting("addrIncoming", addrIncoming);
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
}
}
//
// Start threads
//
// Get addresses from IRC and advertise ours
if (!CreateThread(ThreadIRCSeed, NULL))
printf("Error: CreateThread(ThreadIRCSeed) failed\n");
// Send and receive from sockets, accept connections
pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
// Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL))
printf("Error: CreateThread(ThreadOpenConnections) failed\n");
// Process messages
if (!CreateThread(ThreadMessageHandler, NULL))
printf("Error: CreateThread(ThreadMessageHandler) failed\n");
// Generate coins in the background
GenerateBitcoins(fGenerateBitcoins);
//
// Thread monitoring
// Not really needed anymore, the cause of the hanging was fixed
//
loop
{
Sleep(1000);
if (fShutdown)
return;
if (GetTime() - nThreadSocketHandlerHeartbeat > 15 * 60)
{
// First see if closing sockets will free it
printf("*** ThreadSocketHandler is stopped ***\n");
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodes)
{
bool fGot = false;
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
fGot = true;
if (!fGot)
{
printf("*** closing socket\n");
pnode->CloseSocketDisconnect();
}
}
}
Sleep(10000);
if (fShutdown)
return;
if (GetTime() - nThreadSocketHandlerHeartbeat < 60)
continue;
// Hopefully it never comes to this.
// We know it'll always be hung in the recv or send call.
// cs_vRecv or cs_vSend may be left permanently unreleased,
// but we always only use TRY_CRITICAL_SECTION on them.
printf("*** Restarting ThreadSocketHandler ***\n");
TerminateThread(hThreadSocketHandler, 0);
#ifdef __WXMSW__
CloseHandle(hThreadSocketHandler);
#endif
vnThreadsRunning[0] = 0;
// Restart
hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
nThreadSocketHandlerHeartbeat = GetTime();
}
}
}
bool StopNode()
{
printf("StopNode()\n");
fShutdown = true;
nTransactionsUpdated++;
int64 nStart = GetTime();
while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0)
{
if (GetTime() - nStart > 20)
break;
Sleep(20);
}
if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
Sleep(20);
Sleep(50);
return true;
}
class CNetCleanup
{
public:
CNetCleanup()
{
}
~CNetCleanup()
{
// Close sockets
foreach(CNode* pnode, vNodes)
if (pnode->hSocket != INVALID_SOCKET)
closesocket(pnode->hSocket);
if (hListenSocket != INVALID_SOCKET)
if (closesocket(hListenSocket) == SOCKET_ERROR)
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
#ifdef __WXMSW__
// Shutdown Windows Sockets
WSACleanup();
#endif
}
}
instance_of_cnetcleanup;
"%file: ./rc/addressbook16.bmp"
BM66(ÿÿÿÿÿ÷ÿ÷÷ÿ÷ï÷ïæ÷ææ÷æÎïÞÞïÞÖæÞÖ÷ÞÎïÞÎ÷ï÷ÞÅïÖÎÎÖÖæÖÅ÷Ö½ïÖ½ÎÎÖæνæŽÞŵ1Ö½Þ½­½µµÖµ¥ÿÿεœÖ­œÖ¥”Ö¥ŒÎ¥ŒÅ¥ŒÅœ„Öœ{Μ{ν1֜k÷­”„µ”{֔k„œk­Œ{­ŒsŌcBνŒcœ„{œ„s¥„k¥{{œ„kBŒ{ńZk­)JJ÷¥„cńR¥{cœ{c{cœZ{k”scœsR„sZ”kR”kBŒcR{kBŒZZ{JRsRBkc!”cRksB:kB1c1RkB)c:)c:!c:c1Z1c)!Z1R)3Ìÿ3ÿ33ÿf3ÿ™3ÿÌ3ÿÿff3fff™fÌfÿf3f33f3ff3™f3Ìf3ÿffff3fffff™ffÌf™f™3f™ff™™f™Ìf™ÿfÌfÌ3f̙fÌÌfÌÿfÿfÿ3fÿ™fÿÌÌÿÿ̙™™3™™™™Ì™™33™f™3̙ÿ™f™f3™3f™f™™f̙3ÿ™™3™™f™™™™™Ì™™ÿ™Ì™Ì3fÌf™Ì™™Ì̙Ìÿ™ÿ™ÿ3™Ìf™ÿ™™ÿ̙ÿÿ̙3Ìf̙Ì̙3Ì33Ì3fÌ3™Ì3ÌÌ3ÿÌfÌf3™ffÌf™Ìf̙fÿ̙̙3̙f̙™Ì™Ì̙ÿÌÌÌÌ3ÌÌfÌ̙ÌÌÌÌÌÿÌÿÌÿ3™ÿfÌÿ™ÌÿÌÌÿÿÌ3ÿfÿ™Ì3ÿ33ÿ3fÿ3™ÿ3Ìÿ3ÿÿfÿf3Ìffÿf™ÿfÌÌfÿÿ™ÿ™3ÿ™fÿ™™ÿ™Ìÿ™ÿÿÌÿÌ3ÿÌfÿ̙ÿÌÌÿÌÿÿÿ3Ìÿfÿÿ™ÿÿÌffÿfÿffÿÿÿffÿfÿÿÿf!¥___www†††–––ËË˲²²×××ÝÝÝãããêêêñññøøøðûÿ¤  €€€ÿÿÿÿÿÿÿÿÿÿÿÿGGGGGGGVMGGGGGG4)SN! 44 RWUPE."IQQR%D4 1&<K4 175+B4 1 *= 64 1&=?4 17#58F4 1 "* ='L4 1*=/J4 1"7#3>H410:9O441-,344AAA<(@CAA
"%file: ./rc/addressbook16mask.bmp"
BM~>(@ÿÿÿÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþÿþ>ø
"%file: ./rc/addressbook20.bmp"
BMÆ6(ÿÿÿÿÿ÷ÿ÷÷ÿ÷ï÷÷ïÿïæ÷ïæÿïÞ÷æÞïæÞ÷æÖÿÿæÞÞæÞÖÞÖÖæÖÎÎÖÖæÖÅæÎÅïεÅÅÅ1ÞÅÞŵÅŽïÅ­Îŵ½½½Î½µÞ½­Ö½­Rεŵ­ÿÿŵ¥ÎµœÞµ”Ö­œµ­¥Þ­”Ö­”½­œÞ­Œ¥œ½½¥œµ¥œæÖ)Î¥ŒÎœ„Å¥kޜsÿ֜sΔ{­”„Δsµ”{„µJµŒ„Δk֔cΔc­Œ{Ōk­Œsµ”Rńk¥„sœ„s”„sJJÿBJÿŒ{s­{c½{R”scRscŒkZœkRŒccJsZœkJckR¥„„cR{cRZkJkcRŒZR{ZRccB{ZJŒZB”kŒZ:„Z:J{kc!cBc{R:„JB„R1„R)kJ:{BBsBB„J)s::„BcJk:!k11Z1!c!!Z)R!Rf™Ìf™ÿfÌfÌ3f̙fÌÌfÌÿfÿfÿ3fÿ™fÿÌÌÿÿ̙™™3™™™™Ì™™33™f™3̙ÿ™f™f3™3f™f™™f̙3ÿ™™3™™f™™™™™Ì™™ÿ™Ì™Ì3fÌf™Ì™™Ì̙Ìÿ™ÿ™ÿ3™Ìf™ÿ™™ÿ̙ÿÿ̙3Ìf̙Ì̙3Ì33Ì3fÌ3™Ì3ÌÌ3ÿÌfÌf3™ffÌf™Ìf̙fÿ̙̙3̙f̙™Ì™Ì̙ÿÌÌÌÌ3ÌÌfÌ̙ÌÌÌÌÌÿÌÿÌÿ3™ÿfÌÿ™ÌÿÌÌÿÿÌ3ÿfÿ™Ì3ÿ33ÿ3fÿ3™ÿ3Ìÿ3ÿÿfÿf3Ìffÿf™ÿfÌÌfÿÿ™ÿ™3ÿ™fÿ™™ÿ™Ìÿ™ÿÿÌÿÌ3ÿÌfÿ̙ÿÌÌÿÌÿÿÿ3Ìÿfÿÿ™ÿÿÌffÿfÿffÿÿÿffÿfÿÿÿf!¥___www†††–––ËË˲²²×××ÝÝÝãããêêêñññøøøðûÿ¤  €€€ÿÿÿÿÿÿÿÿÿÿÿÿggggggggjsgggggggpN"7TqT7"NN
+TTXfrd<moZTT?0WN
C5(!#3+R kN
C )3\-iN
C'I3YVN
C.$#3O KN
C #3UQN
C6<&`8bN
C/4A63/4/_2lN
C #3_2lN
C 6<e@cN
C/4>:3)44/aEnN9C &MaEnJH,=S*Gd[[P=%L[[bD
"%file: ./rc/addressbook20mask.bmp"
BMŽ>(P  ÿÿÿÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀÿÿÀ?¿
"%file: ./rc/bitcoin.ico"
hf ¨Î00¨v h  ¨†!00 ¨%.2( @/|D–¹I£ÇJ Â6…¦1~žI¬ÔhÏ÷s×ýpÔûiÍ÷iÍö[¼æ'‚¨0„§bÅîqÖýaÆíH­×:¢ÌE¦ÎjÂç€ÖùxÕøD¡Â Zz'x˜hÊðrÕúI¬Õ9œÆ6™Ä6™ÃLªÎtÃæyÅä‘êû’ðþ7“³b¸ÕŒáþK¨Ñ1¹.·.·7˜ÀM¦ÇuÀÝ{ÇákÃàŽé÷vÛóc†'v•‘äö‡Öñ‚Æà£ã÷˜Øí˜ÚïFœ¾]­ÊÝòŸÞóh»Ø~åÿ3’´Ut@’¯šîÿ|Ëë…Éâ­ëþXŸºm´Í¦åù›ÛðJ¿J£ÅX°ÕyÛûM¯ÕWwQ¤ÀšòÿxÌí‡ËãÏä£âöW ºÆÞ^»ß]¾ça¼èrÐ÷W¹áXxK ¾ŒèÿlÁä„Éáj¯È{¾Õ¬êýˆÌãiÅã^¼åS­ÙtÏöW·ßVw7‰©àþjÂã‚Çßo³Ër¸Ð—Øí©çûk¹Ôkº×P¥ÊqÐúD£ÌVuiÉîsÏðb®Êt¹Òy½Öz¿×yÂÜt¿Úw¿Ø~ÄÜl¶ÑI¦ÏhÊ÷"}¥DžÂsÑô]·×XªËnºÛ‚Ìë‡ÑïxÅå`³×F¢Ê:œÈdÆôY·ãZ}Z·ÜvÓõlÂãm¾ßzÆäzÄá€Éé{Åè|Æå‹Ú÷ÕöušUu+x˜kÁàŸìþ“ßúˆÔïÕï˜Ûóªëú½úþ¨íô3‡¤UtS¢»{Ëèãü—èÿéþ“ÞòeµÍk Xwp‘%yšp’hˆ^}ÿÿÿ¼½¾¿À³´µ¶·¸¹º»§¨©ª«¬­®¯°±²š›œžŸ ¡¢£¤¥¦ŒŽ‘’“”•–—˜™~€‚ƒ„…†‡ˆ‰Š‹DpqrsIwXu[wwXz{|}bcdeIfIgwijklmnoTUVWIIXZw[\]^_`aEFGHwJIKwMNOPQRS6789wwX=>wwXABCD()*+,-./012345 !"#$%&'
üÿÿðÿÿÀÿÿÀÿÿ€ÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿ€ÿÿÀÿÿàÿÿø?ÿÿ( @€ % )6 4E <P D\IdMjOmPoPpQqQqQqRrRrRrRsSsTtUvUwVxVxWyWyWyWyWxXx Xx
Xw Xw Xw Xw XwYxZy[{\|^_aƒd†e‰gŒhijl’o”p–q—r˜s™t™ušv› wœ$y({,|ž.~Ÿ1 3¡5‚¢5„¤6…¥6…¦5…¦3…§0…¨.…©-…ª-‡¬.‰®.Š¯/‹°/‹°0Œ±3±7°;°=°?°>‘²=’´;“¶8”¹7•¼6—¾7—¿6—À5˜Á6˜Â7™Ã7šÃ8›Ä:œÅ;Æ;Æ<Ç<žÇ=ŸÈ=ŸÉ? Ê@¡ÊB¢ÉE¢ÈG¢ÆJ¡ÄK¡ÂM¢ÃO¢ÃQ£ÂR£ÁU£ÀW¤ÁX¤ÁZ¥Á[¥Á\¦Â]§Ã^¨Ã^¨Ã^©Å]ªÆ]ªÇ^«Èa¬Éb­Éb®Êb¯Ì^®ÍZ®ÏX®ÑV¯ÔV°ÖU±ØV²ÙW²ÙW³ÚW´ÛXµÝY·ß[¹à[»â]¼ã^½ä`¾äa½äe¾ãf¿âh½ßi¼Ýl¼Ün»Üp¼Ûr½Út¾ÛwÁÝyÂß{Äà~ÇãÈä€ÊæƒÌè„Íê†Ðì‡Òî†ÒïƒÒð€Òð~ÑðzÐðwÎïrÍïoËïmÊðkÊñkÊòjËôjÌõkÍ÷nÏ÷pÐ÷qÑørÒøsÔútÕütÖüvÖûw×üx×üzÚü|Üý~Þý€ßýàý„áüˆáû‹áúàø‘ßö’Þõ•Þô˜ßô›áõœâõä÷›æù›èû›ëý›ìý›îþœïþœîþ£îþ©ëý«ëý¬ëý­ëý­ëý­ìý°ðý±òýÿÿÿFGE69FFFOQVjtuseUJ6.A\d›Àäåîîïï羏TD+?\b»ûõîîïððõõõüýë‘N3,]sÅýõîîîèèéëöýýýýýÅX5(C]uÛáäåæÁ»½ÀÃÃÆÅìýýýýîc5([lÌØÛÛ´¶´¾½¼ÁÄÆÆÄÂÅïîçÉW3,fÏÕÖÍ¢£¶¼¿Â¾¼»¸©¥¥¤¥ÖÝجM+;a¤ÕƠ̈› ·½ÁÄÄþ¹ª£Œ…~†ÑÔÔ~D(l××Û¢‹‹› ºÁèèÅÁ·¢‹shh†ÑѱR.<nªÜÞϋ™–˜™žŸ“ Åސ »» ‹f®ÑÑ{6(fÙàᤒùùùøøùøº šÂøùùøøù ‡ÒѬJ(@wââÝ£’ùùùqºùùö_¾ùùøº‹‹¹ ÖÖÔU.?\¢ãäˤ“ùùù˜ùùùpöùùʹ£‰£ÍÝÙj1@`®äåË«–ùùùpŸùùöùùùž´Ì´«¦¦ÎßÙ|5/o´òóɵœùùùêöùö˜–ùùù‘¶³®¬©¬ÏÝق5,`µóóÇ´ùùù¿ëùÄp–ùùù«±°±³²ÎÝـ5?^¶óó䳝ùùùpŸùùêpùùùšŽ±¯®°°ÕÞÚv5@Yœòò継ùùùp™ùùöYíùùÅ`›ˆs¦ÞßÚe0?sññ突ùùù–Äùùêdøùø¿Ž’ĸ£âàÔR+mÄòð¾ùùùùùøëstuœêøùùùø¸ÍâàªH.\¢òð梋srnnmdkw‰• ºº ›¤ðãàk5@lÇåã±{zyxyxux‚‡¢¼ÅèÆÉËóóä±M.\‚ßÞÚ¬}}|}}zy~ˆ«´ÁÅÅÞóóóãh5Ac¦ÙàÜ°‡€€}{{{‚©´¾¹¸æóóò‰G?d§ØÚÞש†~||z|‰¥¼ÁÇãää¤L:d¤ÓØÙÞ×°¦†††¥±ØáÛÕֈM;c{±ÓÚÚÚÚØÓÑÑÓÓÖÕ°kIF^f†±Ó×ÜÝØÓÓÓÓ°ƒRG_dt‡§®Ï´¬‡gTY_p``o`[ÿøÿÿÀÿÿü?øðààÀÀ€€€€€€ÀÀàðøü?þÿÿ€ÿÿðÿÿÿÿÿ(0`€
+8NJgOoPpPpQqQrRsRsTtUuVwWxWxXzY|Z}[~\€\€\€\€\
\~\|\{]|^}`b€c‚e„g‡h‰h‹ijlm‘n’o“p”r•s˜t™u™vš"x›"y!zŸ |¢!~¤"¦#€¦$§&ƒ©'„ª)„©+„¨+ƒ§,ƒ§-ƒ¦/‚¥2‚£6 8€ž;€ž<ž=ƒŸ?„¡?…¢@†¤A‡¥Bˆ¦CŠ§EªF­G”²H—¶G˜·F˜¸E—·C”µ@±>Ž®<Œ­:‹«9Š«7‰ª6ˆª4‰«1‰¬/‰­/Š®/Š¯.‹².Œ´/Ž¶/Ž·0¸1‘º2“¼3•¾3—À4˜Â4˜Â4™Ã5™Ã7šÃ8šÃ8šÄ8›Ä:œÅ<žÆ>žÆ?ŸÇ@ ÈA¢ÊC£ËE¤ËF£ÉH¤ÉJ¤ÉM¤ÇO¤ÅQ¥ÅT¥ÄY¥ÃZ¦ÄZ¨ÇWªËWªÍU«ÐV­ÒW®ÔX¯ÔZ°Õ\±Õ^²ÕgµÔj·Ôk¸Ôi·Õd·Ø[·ÞZ¶ßY·á[¹â\ºä_¼äa½åb¾æc¿æcÀçcÂêdÃëcÅíeÅîgÇîiÈîmÇëpÆèpÃäoÀáo¿ào¿àqÀátÁávÂàwÃáyÄâzÄà|Åâ~Çã€ÈäƒÊæ†Íç‰Ïé‰Ïé‰Ðë‰Òï‡Óð‚Óò{ÓñxÒòsÐóoÎôkÍöjÍ÷jÍønÏùoÑúpÒûrÕütÖüt×ývØþwÙþxÚýzÛý|Ûý}Ýýßý€ßý„ßü‰ßû‹Þù‹àûŒâûäü’åý’æþ“æþ•èþ–êþ—ìþ˜îþ™îþšîþœëýžéü¡çú£åø¤ä÷¥åø¦åø§æùªèü¬êý¬êý¬êý¬êý¬êý¬êý¬ëý¬ìý¬íý­îý±òý³ôýµöþ·øþ¸ùþ¹øþÿÿÿ()+%(*)4(-.000/-"*953=Bjxƒ†‡‡[jA;0!N;=g†¯ÁÜÞÞÞßßßàÙ¶f:-SA^˜ÙßÝÝÞßàààæççæ÷øè´]9"(OE`¶þýñßßßààææææö÷øøùùùø´f1$QE[Ùýýûçßßàææçæøøøùùúûýþþüê‰9SD…ØÚßáàßßÝÀº·µ·¹º¾Àêúýýýýýýý˜<SC…ÔÖÓ×ÛÝÙ¯¯²µ¸»¾¾¾¿¿¿êùýýýýýý¶=$PBÍÍÍÒÓ׬š¯®³µ³³¸¾À¿ÀÀÀ¿¿Àøùåçæàš;%LBqÄÄÄÃÃĔ•š¯­µ¹·²¯´¹¹¹·´²±¯˜ÁÙ××ÁÁ„3EiªÄÄÄ숎”š¯²µº»·³³²¯˜•””‘¡ÍÍËÊÄl-TAœÄÄÄ놈Ž•™¯³¸º»»º¹´¯š•…ƒ€~|ÉËËË¢=EqÄÄÄÃ戍Ž•˜¯·º¿ÀÀÀ¿º¸³¯¯š‚|vrrÈÈÈɀ1VB¡ÄÄÃ͐Z[ZZ‰ŒŽ–˜³»ÀÙÙÀ¿¹¯•†\jjjkp¥ÇÈÈ¥?EqÎÎÑÓ¬[bL:;LKJSUXŠ²¿ÙÙ»˜‡__YYXd97A€ÈÇÆÇ|/%MC›ÐÑÔ֏^êëêêêêëë꿗Y˜¿½Y˜êïñõññí½‰j¥ÈÆƞ7VCÍÔÔ×Èdëõõõõõõõõõñ½Y—Œ‹êõõõõõõõõõºBÈÇÇÈD fxÕÖÖפdëõõõõ—XíõõõñŒWZìõõõõ옉Š¶í»g€ËÊÊɀ.$EÖÖ×כŽdëõõõõ‹4¸õõõõ¸8»õõõõíYZ’[Z˜qƒÅ͢6$C¡Ö×ÛÁ›cëõõõõŒ:¶õõõõ½:îõõõõ˜[­Ä«Ÿƒ…«ÓÏͦ<%OCÅ×ÞÞ ”aëõõõõ‹4¶õõõõ¶YõõõõñX’ÄÄ«¡œ£ÓÏÏÉ>$UDÂÞááÁ£š_ëõõõõŠ9êõõõñŠ—õõõõíašÄ«¦žœ‘‘ ÓÏÍÌASh×âããÁ¬š^ëõõõõññõõõñ¶:¶õõõõêe•ª¤ŸœŸÓÏÌÌCShÛãååÙį]ëõõõõõõõõîŠ4:·õõõõêJ’¦¤ŸŸ¢   ¢ÓÏÍÌCRh×ãååÛį]ëõõõõ—Wîõõñ¸5˜õõõõìJ¦¤¤¥¨¨¦¢¦ÔÏÍËA$NgÂäååÝ«¯]ëõõõõ‹0½õõõñX‹õõõõñc† ¡   ¡£ ªÔÏÌÆ>$g®äååᬖ^ëõõõõ‹4¸õõõõŒUñõõõõ‹b‘››„…“ÅÕÑΧ<$f“ãåæ嬕`ëõõõõŠ+¼õõõõ—:¾õõõõêK_Z[ea–}“ÒÕÔМ6b[âåææÁ•bëõõõõ‹Ríõõõñ‰E\ìõõõõ¿YJ`–ê»_œÖÕÕҀ/UhÛåææە_ëõõõõññõõõõ¿Fp]ˆêõõõõñññõõ»^¬ÖÕÕÔg!$f™åææá¯Zìññññññññë³Fgzƒ[X¶êñõõõõñ쳈ÜÖÕÕ¤<b\äåæáٍZ^edfEGGH=>Cpz‡‰‰‰Œ—˜˜–‰Z‡Ãâ×ÕÒ}/Ph²áßÝÚ¢}ponmmmmmmnpx{†Ž¯¸º·³®¯®­ÃåãáÕª@&e\ÚØ×Óˏzyywvvywsqq{}~…”¯»ÙéÝÚ×ÓÓååãâÖ~0ND“ÓÓÐÍɂzzzwwzzyrrw{}š¯µ¾ÀÙÙ×Óåååãâ©=dC©ÑÐÑÑɂ|~{{{yvsrvz{ ­µ´µ´µÂååããã×j-$ElÆËÓÕÏʟ‚~|{ywuuvwz‚“ ¬µ¯–¯ßããââÜ~3MDo©ËÐÐÐÐǐ€€{yuuurs}ƒ‘¯­¯ºØ×ÜÞÞ܅7PBo¨ÉËÎÐÏٜ€{uuusr{}…›ÂÜØÓÃÍÔՅ<QDk¢ÆÊËËÐÕÏ˧ž“œŸªÄÍÓÒÍÅÆÆx;NECÆÇÈÌÐÐÐÐÎËÇÆÆÆÆÇÇÉÊËËǝi6&dApŸÆÈÌÌÎÐÒÐÌÈÆÆÆÇÇÇÇʨ{>/UEAqœÆÇÈËÏÐÍÌÊÉÈÇÇǟ}A6"+UE@C{‘£ÆÈÌÒÔÏ©k>3.,UcEAAACkpogA>;9MMVWVVVVWUMÿÿðÿÿÿÿÿÿ€ÿÿÿÿüÿÿÿÿðÿÿÿÿàÿÿÿÿ€ÿÿÿÿÿÿþ?ÿÿüÿÿøÿÿðÿÿðÿÿàÿÿàÿÿÀÿÿÀÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿ€ÿÿ€ÿÿ€ÿÿÀÿÿÀÿÿÀÿÿàÿÿàÿÿðÿÿøÿÿø?ÿÿüÿÿþÿÿÿÿÿÿÿÿÀÿÿÿÿàÿÿÿÿø?ÿÿÿÿþÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿ(  @x¥Ã6žl(yš¿'{œïp‘üiŠèc‚°.oˆRÿÿÿXš¶mX§Àï{Ëèÿãüÿ—èÿÿéþÿ“ÞòÿeµÍÿkÿYx¾Gz™G’²™kÁàÿŸìþÿ“ßúÿˆÔïÿÕïÿ˜Ûóÿªëúÿ½úþÿ¨íôÿ3‡¤ÿVtÚ7yG‘°rZ·ÜÿvÓõÿlÂãÿm¾ßÿzÆäÿzÄáÿ€Ééÿ{Åèÿ|Æåÿ‹Ú÷ÿÕöÿušÿ Vv·›ÇÒG ÅôsÑôÿ]·×ÿXªËÿnºÛÿ‚Ìëÿ‡ÑïÿxÅåÿ`³×ÿF¢Êÿ:œÈÿdÆôÿY·ãÿZ}þ!eƒDJ”´xiÉîÿsÏðÿb®Êÿt¹Òÿy½Öÿz¿×ÿyÂÜÿt¿Úÿw¿Øÿ~ÄÜÿl¶ÑÿI¦ÏÿhÊ÷ÿ"}¥ÿ Wv¤Hœ¼½àþÿjÂãÿ‚Çßÿ­ëþÿ­ëþÿˆÌãÿr¸ÐÿÆÞÿ©çûÿ­ëþÿˆÌãÿP¥ÊÿqÐúÿD£Ìÿ VvàUªÇáŒèÿÿlÁäÿ„Éáÿ­ëþÿj¯Èÿ­ëþÿ{¾Õÿ­ëþÿˆÌãÿiÅãÿ^¼åÿS­ÙÿtÏöÿW·ßÿUwúY®ÉäšòÿÿxÌíÿ‡Ëãÿ­ëþÿ­ëþÿˆÌãÿW ºÿ­ëþÿÆÞÿ^»ßÿ]¾çÿa¼èÿrÐ÷ÿW¹áÿXxöQ£¿Éšîÿÿ|Ëëÿ…Éâÿ­ëþÿXŸºÿ­ëþÿm´Íÿ­ëþÿ›ÛðÿJ¿ÿJ£ÅÿX°ÕÿyÛûÿM¯Õÿ XxÐE“²Œ‘äöÿ‡Öñÿ‚Æàÿ­ëþÿ­ëþÿˆÌãÿFœ¾ÿ]­Êÿ­ëþÿ­ëþÿˆÌãÿh»Øÿ~åÿÿ3’´ÿYw‰y­Å,b¹ÔýŒáþÿK¨Ñÿ1¹ÿ.·ÿ.·ÿ7˜ÀÿM¦ÇÿuÀÝÿ{ÇáÿkÃàÿŽé÷ÿvÛóÿc†ø<xŽ"?°œhÊðÿrÕúÿI¬Õÿ9œÆÿ6™Äÿ6™ÃÿLªÎÿtÃæÿyÅäÿ‘êûÿ’ðþÿ7“³ÿ[{~jª¿ <‘µÉbÅîÿqÖýÿaÆíÿH­×ÿ:¢ÌÿE¦ÎÿjÂçÿ€ÖùÿxÕøÿD¡Âÿ_ wª»I”µªI«ÓþhÏ÷ÿs×ýÿpÔûÿiÍ÷ÿiÍöÿ[¼æÿ)„¬î)qnÿÿÿf ¼AI”µ£NŸÃÞK¤ÇúO¥ÈíF•¸¿AŠ¨mUˆªðÿÿàÿÿÀÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿ€ÿÿÀÿÿðÿÿ( @ €¥¿F‚œb"k‹£i‰Ò_€ðXzüXxùa€å!f‚À0q‹‰W‹Ÿ@ÿÿÿÿÿh µI5€Ÿ«s—ø{ ÿ/Œ°ÿ<˜ºÿ@›¼ÿ<•¸ÿ,†ªÿv›ÿhÿZ}ÿStÿZxÞ<xn¿¿±ÃEAŒ«Ï+„§ÿWªÊÿtÈæÿ‰àúÿŽæÿÿ‘æÿÿ”æÿÿ™çÿÿ™èþÿ“áöÿ{ÊàÿN£Àÿušÿ]ÿRsÿXvÛQ‡šBŸ¿ßd¡º™3ˆ©þt¾Ðÿ¬ï÷ÿ¡çÿÿ•äÿÿ–æÿÿ—èÿÿ›éÿÿŸëÿÿ¢ìÿÿ¥ìÿÿ§îÿÿ«ðÿÿ®óÿÿœáñÿT¦Âÿn’ÿVxÿQqü<x‘{¸ÆE­Æ9’¶ÿ†Öíÿªôÿÿ¨óÿÿœæÿÿšåÿÿ™åýÿ’Þ÷ÿ’Ûôÿ–Ýóÿœáõÿ§éúÿ³ôþÿ·øÿÿºúÿÿ¼øÿÿ¹ùþÿ‰Óâÿ& ÿY|ÿQqþ!f‚‘‰°ÄC®Ë9—¼ÿ{Ö÷ÿƒÛýÿŠàþÿ‘ãþÿ‰Úöÿ|Ëéÿs¿àÿxÁáÿÆæÿ‡ÌêÿˆÍëÿŒÏïÿ‘Òòÿ£âöÿºöüÿÂþÿÿ¾þÿÿ·ûÿÿ›æïÿ/‡§ÿY|ÿQqþ!e‚{J‘®¯3¶ÿpÍòÿuÔöÿyÕ÷ÿ}ÖøÿlÁáÿh¼ÞÿoÀâÿwÄãÿyÃáÿwÁÞÿ€ÉåÿˆÐíÿ‡ÐïÿˆÏòÿ†ÌíÿƒÈêÿÕíÿ èýÿ•ãþÿ‘àþÿ}Ïïÿ"|¡ÿVyÿQqü>y‘A^ž·d*‡­ÿgÅëÿsÐôÿtÑòÿoÊëÿU¬Îÿ\¯Ñÿg¸ÙÿsÀâÿzÇçÿÌéÿyÄâÿvÁàÿt¿àÿn¼ßÿc³Ùÿ`°×ÿ\®ÖÿW¬ÔÿZ°ØÿvÏøÿyÒüÿyÒúÿ]·ßÿm’ÿRsÿ Wuۑ¶¶¿ßß9‹¬ìP¯ÕÿqÐóÿsÑóÿqÍîÿQªÊÿT©Éÿ`°Ñÿk¹ÚÿvÂâÿ€Ëêÿ†Ðîÿ†Ðîÿ„ÍìÿyÅæÿo¼àÿc´ØÿX®ÔÿL§Ðÿ@ Ëÿ:šÇÿ@¢ÐÿhÊ÷ÿnÏûÿoÍûÿ>›Åÿ^‚ÿQqÿ"fnj¦½|1µÿsÒõÿuÓôÿxÕöÿS­ÎÿFœ¼ÿJ›¼ÿS¡Ãÿ]ªËÿg³Òÿs½Ûÿ‚Êçÿ×òÿØôÿ‰Óðÿ}Êéÿk¼ÜÿY­ÎÿH Áÿ6‘¶ÿ*Š³ÿ(Š·ÿ>¤ÑÿeÈ÷ÿhÊøÿbÂðÿt›ÿStÿ XvÞÿÿÿÿÿB°áUµÛÿwÙýÿ{ÚüÿkÆèÿNŸ¿ÿbªÅÿ_§Áÿa¨ÃÿdªÅÿf­Çÿh®ÈÿZ£½ÿi³ÎÿŽÖðÿ‰Óîÿ`­ÊÿV¢¾ÿl´Íÿx¾Öÿy¾×ÿi±ËÿLš¹ÿ,†®ÿWºéÿhÊöÿiÊöÿ:™Äÿ[~ÿQqÿ1s‹>­Ã8+†¬ÿuÕøÿ}ÝÿÿƒßþÿY±ÔÿX¥Âÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ¬êýÿ­ëþÿ¬êýÿs¸Ñÿe±Ìÿ]ªÆÿ‡Ëáÿ¬êýÿ­ëþÿ­ëþÿ¬êýÿ¬êýÿ­ëþÿe°ÌÿC¢ÍÿjÌùÿjË÷ÿW¸äÿhŽÿQqÿ_}ˆc¢»y;š¾ÿ€àÿÿƒàÿÿ}×öÿV­ÐÿX¤Áÿ­ëþÿ­ëþÿ­ëþÿN–±ÿx»Óÿ­ëþÿ­ëþÿ©çúÿ;ˆ¥ÿÃÚÿ­ëþÿ­ëþÿ¬êýÿrºÓÿJ»ÿLŸ¾ÿq»Öÿg³Ñÿ@œÆÿrÐúÿpÑüÿmÎúÿvÿStÿZy¿P˜·§M­Îÿƒâÿÿ‡âÿÿvÍîÿ[°ÔÿZ¥Âÿ­ëþÿ­ëþÿ­ëþÿSšµÿb¨Âÿ­ëþÿ­ëþÿ­ëþÿDŽ©ÿªèûÿ­ëþÿ­ëþÿ‡ËâÿN¥ÃÿoËêÿfÂäÿO«ÒÿG ÊÿN§ÑÿpËñÿxÖþÿtÒþÿ.‹´ÿUxÿZxåN˜¶Ä\»Ùÿ‰çÿÿŽèÿÿvÌíÿbµÛÿ\§Åÿ­ëþÿ­ëþÿ­ëþÿG«ÿk°Èÿ­ëþÿ­ëþÿ©çûÿU·ÿ­ëþÿ­ëþÿ­ëþÿb­Çÿd¿ÜÿrÐîÿgÄéÿWµáÿR®ÛÿU­ØÿmÆíÿ|ÙÿÿtÕþÿ:šÂÿWzÿTsøL–µÐeÃÜÿ’îÿÿ—ðÿÿ|Òñÿj½ãÿ`ªÈÿ­ëþÿ­ëþÿ­ëþÿžÝòÿªèüÿ­ëþÿ§åùÿa©Âÿ_§Áÿ­ëþÿ­ëþÿ­ëþÿW¤¿ÿb¼ÝÿeÄçÿ[»äÿV¶äÿV³áÿZ²áÿiÂíÿyÖþÿrÕþÿ>žÇÿY|ÿRqûH”´ÌhÄÜÿ˜òÿÿõÿÿƒØõÿoÁèÿb¬Êÿ­ëþÿ­ëþÿ­ëþÿ…ÇÝÿ¢áõÿ­ëþÿŽÐåÿ@Œ¨ÿ_§Áÿ­ëþÿ­ëþÿ­ëþÿT¡½ÿ[µÙÿaÂçÿ\¿æÿbÁêÿdÀëÿb¼éÿmÈðÿy×ÿÿrÕþÿ=ÅÿX{ÿ WvïN˜µ¸a»ÕÿšðÿÿžóÿÿˆÛõÿn¾åÿa«Éÿ­ëþÿ­ëþÿ­ëþÿJ“¯ÿj¯Èÿ­ëþÿ­ëþÿ™ÙîÿH“®ÿ­ëþÿ­ëþÿ­ëþÿbªÆÿQ§Ëÿa¿ãÿ\½âÿ\»áÿ_¼äÿ^½çÿpÐóÿyÚÿÿrÖþÿ6–½ÿWyÿZyÐN–³’P«Èÿ™íÿÿ›îÿÿß÷ÿi·Þÿ^§Æÿ­ëþÿ­ëþÿ­ëþÿJ“¯ÿcªÄÿ­ëþÿ­ëþÿªèüÿ-}œÿ¥äøÿ­ëþÿ­ëþÿ’Óéÿ8ˆ©ÿSªËÿK¥Èÿ<“·ÿR¦ÈÿT±ØÿxÚùÿ{ÝÿÿsØþÿ&…«ÿTvÿ]{¡g¢»[:”´ÿ™ìþÿ›ìÿÿ˜èýÿe³Úÿ\¥Äÿ­ëþÿ­ëþÿ­ëþÿa§ÀÿÐåÿ­ëþÿ­ëþÿšÛðÿ+‚§ÿ`¬Èÿ¬êýÿ­ëþÿ¬êýÿƒÆÝÿQœ¸ÿY¤ÀÿŽÐæÿm¶ÐÿR¬Ñÿ€äþÿ}âÿÿnÑôÿs™ÿRrÿ"f€_ªÎÚ6Œ¬û…Ùìÿ›íÿÿ›ëÿÿvÅåÿb¬Êÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ àôÿF˜·ÿ5“¹ÿ@™¼ÿ`«ÇÿžÞóÿ¬êýÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿm·ÒÿoÉæÿ€æÿÿ|äÿÿWºÚÿ e‰ÿRr÷x¥´K•³³Y±Ëÿšíÿÿ™éÿÿßúÿV¨ÍÿJ›¾ÿ@“¶ÿ=‘´ÿ;³ÿ:Ž²ÿ7°ÿ%§ÿ+Œ³ÿ8™¿ÿF¢ÄÿS¦ÇÿZ¦Åÿk´ÎÿsºÓÿs¼ÔÿhµÏÿVªÇÿ\µÓÿêýÿƒèÿÿzäþÿ.²ÿWyÿ^{Ÿ{«Ã@3Š¬þƒÙòÿâÿÿ„ÝÿÿbÀéÿ9™Äÿ6—Âÿ5–Áÿ4–Àÿ5•Áÿ4–Àÿ1”½ÿ4—Àÿ>žÄÿB ÁÿW«ÌÿtÀàÿŽÖñÿÙòÿ†Öðÿ|ÔñÿvÒïÿ•ðúÿ˜óÿÿˆêÿÿ`Æâÿl‘ÿRrùY‰ž%J’±µAžÃÿ|ÛþÿyÚÿÿsÖþÿV¸âÿ9›Åÿ9›Åÿ7›Ãÿ8›Åÿ8›Åÿ4˜Âÿ3—Áÿ:œÃÿC¢Åÿ_¶ÙÿpÀâÿ€ËêÿŒÔðÿˆ×óÿÚ÷ÿ–ðüÿ›ùÿÿ—ôÿÿ…åùÿ)Š­ÿWzÿa~…¯Ç 4‡ªïO±ØÿsÕýÿ|ÞÿÿvØýÿ[¾çÿC¦Ïÿ;Çÿ:Çÿ8šÆÿ4™Åÿ3™Äÿ7™Äÿ<ŸÆÿY³×ÿoÁæÿwÅæÿq»Ûÿn»Ûÿçøÿ™ôÿÿïÿÿ’îþÿH¦Åÿ b‡ÿYwȪªj¡»O,…ªüP²ÛÿqÓûÿtØþÿuÚÿÿoÓøÿP³Ýÿ?£Îÿ:œÇÿ5šÆÿ2šÅÿ3˜Âÿ7šÁÿD ÆÿZ¯ÖÿpÁåÿ}Êéÿ„Õ÷ÿ„Üüÿ‡äþÿ‡æþÿT²Ðÿjÿ
XxÜ[Ž£m¥¼d,„ªüK«ÕÿjÍ÷ÿoÓüÿoÕýÿuÚÿÿnÓùÿZ¾çÿI¯Ùÿ<¥Ðÿ:¢Ìÿ?¥ÌÿN®×ÿc¾åÿ{Ôùÿ‚ÚþÿyÕûÿpÎöÿrÑøÿH¦Ëÿl’ÿ ZyÔWŒžr¨½U3ˆ«ó9™Ãÿ`ÅîÿfÍ÷ÿp×ýÿsÚÿÿtÚÿÿsÙþÿkÓûÿhÎöÿfËõÿgËõÿiÍöÿlÎöÿoÑúÿpÐüÿ]¿éÿ-µÿ f‹þ#i†§£¶Œ¸Å(K“°Ä)†­ÿ?£Íÿ_ÄîÿgÎùÿnÒûÿwÙþÿxÙÿÿqÓüÿkÎøÿkÍ÷ÿiÎöÿiÍöÿ]¿èÿ?žÈÿuÿhŠÔH„›Mÿÿÿ|®ÃVL”±Ë+‚¨þ1¹ÿB£ÍÿP²ÛÿZ»åÿeÇëÿfÇèÿV·ÞÿC¤Íÿ*‰²ÿušü<…¤´GˆŸKÿÿ’¸Î/cŸ¸{Xš·µL“²Ý;‰«ö8‰«ü@­òG‘°ÖQ”±ª\—±lžÁÓÿàÿÿþ?øðààÀ€€€€ÀÀàðøüþÿÿÀÿÿÿÿÿ(0` €%ªÆÆ \¢E1rŒ%j‡±)n‰Õ^}îTvúTsû Wwô dß,mˆ¿0pŠ“P…›\‰¦ºÿÿÿQŒ¦EBƒ¥c…ò cˆÿhÿkÿl’ÿl’ÿjÿ gŒÿ b‡ÿ[ÿWzÿTuÿQqÿQrü.n‰ÅO…›gœÄÄ£ÁÖ`š³%u—áp•þ{¡ÿ&ƒ¨ÿ.‹°ÿ<™¼ÿG£ÄÿM¨ÈÿO¨ÈÿL¥ÅÿB›½ÿ2±ÿ'‚§ÿyžÿl‘ÿ_„ÿWzÿRsÿQqÿYwí@z”œ°Ä¥ÌØs¨½'z÷"|¢ÿ/‰¬ÿK£Ãÿh¿ÜÿÖñÿ‹äþÿŒæÿÿŽæÿÿæÿÿ“æÿÿ–æÿÿ—æÿÿ—çþÿŽÝôÿxÈàÿX¬Èÿ1Š­ÿxœÿ eŠÿY|ÿRsÿQqÿYwåUˆ V¹Ì_?‹©ì'¥ÿ<“²ÿp½Õÿ–Üöÿ–äÿÿ’äÿÿ’åÿÿ’æÿÿ“çÿÿ•çÿÿ˜èÿÿ™èÿÿœéÿÿžêÿÿŸêÿÿ¡ìÿÿ¥íÿÿ¨ðÿÿ¢ëùÿwÅÛÿ=”´ÿwœÿ b‡ÿVxÿQqÿQqþ)l†¥œ°ÄªÔÔ _œ·¨/ƒ§þ6­ÿzÁÑÿ¹÷ùÿµùÿÿ¤êÿÿ™äÿÿ–äÿÿ–æÿÿ—çÿÿ˜èÿÿœêÿÿžëÿÿ¡ëÿÿ¢ìÿÿ¥ìÿÿ§íÿÿ©îÿÿªïÿÿ­òÿÿ¯óÿÿ±óÿÿ®ïüÿwÄÙÿ2‹¬ÿm’ÿZ~ÿRrÿQqÿ\yÒb”¤¼ÆJ¯Ð,…©ÿ@˜¹ÿ’Þîÿ´úÿÿ¶üÿÿ­öÿÿ¡éÿÿšäÿÿ™åÿÿšçÿÿ›èÿÿœéÿÿ êþÿ¢ìþÿ¦îþÿªðþÿ­ðÿÿ¯ñÿÿ±óÿÿ³õÿÿµ÷ÿÿ·ùÿÿ¹øÿÿºøÿÿ¶÷ÿÿ¤êôÿR¦Àÿvšÿ]ÿSsÿQqÿYwâ`¥%™»ÌG­Ü)…ªÿI¤Åÿ‡ÛúÿŽàÿÿ”åÿÿ™éÿÿ™çÿÿ—äÿÿ™åÿÿ™äüÿŒ×òÿ‚Ìéÿ|ÅäÿzÂãÿ}ÄãÿÆäÿƒÈæÿŠÎëÿ–×òÿ£äöÿ´óüÿ½ýÿÿ¿þÿÿÀûÿÿÀûÿÿ¿üÿÿ½ýÿÿ¶úýÿo¾Ðÿ"|Ÿÿ^ƒÿStÿQqÿYwái•§“»ÉM‘¯×'ƒªÿI§ËÿÜýÿ€Üýÿ‚Ûþÿ‡ÞþÿŒáÿÿ‘ãÿÿ‹Ýùÿ{Ìëÿp¿áÿq¿àÿuÁàÿzÃãÿÇæÿ…Ëéÿ‰Îìÿ‰ÎìÿŠÏíÿŽÐñÿÑòÿ’ÒòÿŸÝôÿ¶ñûÿÅþþÿÁþÿÿ¾þÿÿºýÿÿµûÿÿ²ùþÿxÈØÿ$} ÿ^‚ÿRsÿQqÿ[xϋ¹¹ ¿¿ÿS”±¾&‚¨ÿB ÆÿuÓ÷ÿvÕ÷ÿxÖ÷ÿ{×ùÿÚüÿ†ÜûÿrÇçÿg»Ýÿl¿áÿnÀâÿuÂâÿyÄáÿxÂàÿxÁßÿ~Çãÿ‡ÐìÿŒÓðÿ‹ÒðÿÓóÿÓõÿÓôÿÑðÿŒÎïÿ”Öðÿ«ïûÿ­òÿÿ¢íÿÿèÿÿ›çÿÿšèÿÿd¸Öÿyžÿ\€ÿQqÿQqÿ ežbž·(‚¨ÿ7•»ÿrÏôÿtÒôÿtÒóÿuÒóÿwÔõÿtÍïÿ\²Ôÿ_³Ôÿf¹Ûÿm¾àÿsÃäÿyÆæÿ|Èæÿ|ÆãÿuÀÝÿs¾ÛÿyÃáÿ~Èæÿ~Èçÿ|Èêÿ{ÅéÿxÂçÿuÁäÿs¾âÿnºßÿm¸ÜÿƒÐïÿ‹Üþÿ…ØþÿƒÖýÿÕûÿ€ÔùÿH Çÿp–ÿX|ÿQqÿQqþK‚™NŒ¶Ê11…©ú*ˆ¯ÿiÈîÿrÐôÿrÐóÿsÑóÿuÒòÿjÅæÿP¨ÊÿV«Íÿ]°Òÿeµ×ÿm¼ÝÿsÁâÿyÆåÿËéÿ‚Íêÿ{ÆäÿwÂàÿvÁàÿt¿àÿp½ßÿj¹Ýÿa±Øÿ]®Öÿ\­ÕÿY¬ÔÿV«ÔÿT©ÒÿP¦Ðÿc»åÿxÒüÿxÒüÿxÒûÿxÑúÿtÌõÿ1Žµÿ gŒÿTvÿQqÿYxߍªÆ ÿÿÿU™´Ä$‚©ÿU³ÚÿqÐôÿqÐóÿrÑóÿuÒóÿlÇçÿM¦ÆÿQ§ÈÿX¬Íÿ`°Òÿh¶×ÿn»ÜÿuÂâÿ|ÇèÿÌìÿ„ÎíÿƒÍëÿ‚Ìêÿ~ÉéÿxÃäÿq¾àÿh·Üÿ^¯ÕÿUªÐÿP§ÏÿL¦ÏÿF£ÎÿA Ëÿ?Éÿ=œÉÿU¶ãÿnÏûÿqÑýÿrÑýÿqÏûÿa¾éÿ |¤ÿ]‚ÿQqÿQqÿ+mˆt–ÀÑN+ƒ§þ6•»ÿrÑôÿrÑóÿtÒóÿvÓõÿsÏðÿO©ÉÿP¦ÇÿT¨Éÿ[¬Íÿc²Ôÿk¸Úÿs¿àÿzÅæÿÌëÿ‡ÑïÿŠÔñÿŒÕòÿŒÕóÿˆÑðÿÌëÿ{ÇçÿuÂãÿo¾àÿi»Þÿ`¶ÚÿS­ÓÿF¤Ëÿ=Æÿ5˜Äÿ1–Äÿ1–ÅÿS¸çÿfÊøÿiËùÿjÌùÿmÌûÿA Ëÿm“ÿVxÿQqÿYx瑶¶]œ·Å%ƒ©ÿa¿äÿtÓõÿtÓôÿwÕõÿyÖ÷ÿU¯ÑÿGž¿ÿFšºÿH™ºÿNœ½ÿT¡ÂÿZ§Èÿa¬Íÿg³ÒÿoºØÿyÂßÿ„ÍéÿŽ×òÿ’ÚõÿØôÿŠÔñÿ†Ñîÿ|Éèÿo¿Þÿa´ÔÿUªËÿK¡Âÿ?—¹ÿ3²ÿ+‰±ÿ'ˆ²ÿ(Š·ÿ/“Áÿ[ÁðÿfÉ÷ÿhÊøÿiÊøÿcÂñÿ!§ÿ^‚ÿQqÿQqÿ1qŠ\ªÉÙ0-ƒ¨þ6•¼ÿv×üÿv×úÿxØùÿ}ÚüÿkÆèÿD›½ÿ7Š«ÿ-~žÿ+zšÿ-|œÿ1~žÿ4¡ÿ7„£ÿ;‡¦ÿ@‹©ÿG“°ÿ[¥Áÿt¾ØÿŠÓíÿ’Ûõÿ’ÛõÿƒÎêÿj¸ÕÿPŸ½ÿ=Ž¬ÿ>Ž¬ÿI–³ÿNš¶ÿG”²ÿ5‡¦ÿ v™ÿt›ÿ#«ÿ?¡ÏÿeÇøÿhÊ÷ÿiÊöÿiÊ÷ÿ=œÈÿiÿTvÿQqÿaºl¥¼‹'„«ÿW·ÝÿwÙþÿyÚþÿ}ÜþÿÝýÿU­Ðÿ>‘³ÿ àõÿ¥äøÿ¥ä÷ÿ¥ä÷ÿ¥ä÷ÿ¥ä÷ÿ¥äøÿ¥äøÿ¤ã÷ÿ—Øìÿo´ÍÿL˜³ÿo¹Óÿ‹ÔíÿƒÏéÿa¯ËÿK˜´ÿs¹ÒÿÝñÿ«éýÿ¬êýÿ­ëþÿ¬êþÿ¬êýÿ§æúÿÏæÿS¡Àÿ*ˆ±ÿ]ÀïÿhÊøÿiÊöÿiÊöÿX¹çÿvÿY}ÿQqÿRrùª¸N–³Ù(‡®ÿuÕ÷ÿ|Ýÿÿ~ÝÿÿƒßÿÿwÑñÿP§Ëÿ6ˆ©ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ‘ÒèÿL˜´ÿk·Ñÿ^¬Èÿ]§Áÿ£âöÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ†Êâÿ'‚©ÿM¬ØÿkÍúÿiË÷ÿjÌ÷ÿkÌùÿ)‡°ÿ_„ÿQqÿQqÿ1o‹R²ÌÝ1†©þ;š¾ÿßÿÿ€ßÿÿ‚ßÿÿ†áÿÿhÁãÿR¨Ìÿ5‡¨ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿr¶ÍÿO–±ÿ§æùÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿf­ÇÿD‘®ÿQœ·ÿ¦åùÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¦åùÿq¸ÑÿT¡½ÿX¥Áÿ{ÁÚÿ§æúÿˆÌäÿ-‡®ÿC ÊÿrÑûÿoÐûÿnÐúÿoÏüÿA ÊÿhÿSuÿQqÿ!eŠŠµÇS+†«ÿP¯Ñÿáÿÿ‚áÿÿ…áÿÿ†àýÿ^¶ÛÿUªÍÿ6ˆ©ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿb¨Áÿ%qÿ…ÇÝÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ„ÆÝÿ&t“ÿ‹Íãÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ§æùÿLš¶ÿG½ÿW°ÐÿR¬ÌÿAš¼ÿG›¼ÿoº×ÿ<”¾ÿG£ÎÿoËóÿwÔýÿrÒýÿqÑýÿS³Þÿq˜ÿVxÿQqÿ_|¸m§¾~(‡¬ÿaÁàÿ‚âÿÿ„âÿÿ‡âÿÿÙ÷ÿ`¶ÜÿX¬Ðÿ8‰ªÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿf«Åÿ.z˜ÿ|À×ÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿŽÏåÿ/{˜ÿ«éüÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿq¸ÑÿE›ºÿiÄâÿrÏîÿkÇèÿ]ºßÿN©ÑÿEŸÉÿJ¤ÍÿP©ÓÿjÄêÿ|ØÿÿwÕþÿtÓþÿdÂîÿx ÿX{ÿQqÿ_|Ùd¢º(‡¬ÿoÏëÿ†åÿÿ‰æÿÿŒæÿÿ}Ôóÿdºàÿ\¯Ôÿ;‹¬ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿa§Áÿ"nŽÿÄÛÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿÄÚÿT›µÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿG–³ÿX±ÏÿtÑïÿsÐïÿlÈëÿa½æÿU³ßÿP¬ØÿQ«ÕÿU­Öÿf¿æÿÛÿÿ{ØÿÿvÖÿÿoÏùÿ}¤ÿZ~ÿQqÿZxði¥¾±)ˆ¬ÿ{Úòÿ‹éÿÿêÿÿ’ëÿÿ~Õòÿj¿æÿa´Ùÿ>Ž°ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ`¥¾ÿ+v”ÿ¢áõÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿY ºÿn³Ëÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¨æúÿ9Œªÿ_¹×ÿrÐîÿmËëÿfÄéÿ[¹åÿT³âÿU°ßÿU®ÜÿW®Ûÿ`¸äÿÙÿÿz×ÿÿtÕþÿqÔüÿ#‚©ÿ\€ÿQqÿRrúY›·¹+Š¬ÿƒàõÿ‘íÿÿ•ïÿÿ˜ðÿÿƒÙôÿpÄìÿg¹ÞÿA‘³ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ¬êýÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ~ÂÙÿ(x–ÿ}ÁØÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¢áõÿ5‰¨ÿ]¶ÖÿjÈéÿcÂæÿ\¼äÿV·äÿU¶äÿU³áÿW²áÿY±àÿ^·äÿ|ØÿÿwÖþÿsÕþÿqÔýÿ%„¬ÿ]‚ÿQqÿQrú[œ¸¸,Š¬ÿ†âõÿ–ñÿÿšóÿÿôÿÿ‡Ý÷ÿuÈðÿk¼âÿC“µÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿªèûÿ_¥¾ÿ pŽÿ)z™ÿÅÛÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¡áõÿ2…¥ÿX±ÓÿeÃèÿ^ÀæÿZ½åÿ[½çÿ^¾çÿ_¼æÿ`ºçÿ`¸æÿb»çÿ}ÙÿÿxÖþÿtÖþÿqÔýÿ%„¬ÿ]‚ÿQqÿXwò\ž¸®,Š¬ÿ„Þñÿ˜ñÿÿœôÿÿŸöÿÿŒáøÿvÉñÿl¼ãÿD“µÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿk°ÉÿI’­ÿ©çûÿ­ëþÿ­ëþÿ¬êýÿ‚ÆÜÿ#s’ÿw»Óÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¦åùÿ1‚£ÿT«ÏÿeÃèÿ`Áæÿ]ÀæÿaÃéÿfÄìÿgÄîÿfÂíÿb½éÿeÂëÿ~Üÿÿw×ÿÿsÖþÿpÓüÿ"¨ÿ\€ÿQqÿ]{Ýe¢»—,‰¬ÿ{Ôéÿ™ïÿÿœòÿÿŸôÿÿ’åùÿuÇîÿkºàÿB‘´ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿa§ÁÿlÿŽÐåÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿH“¯ÿa¨Âÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ<‰©ÿKŸÃÿb¼áÿa¿âÿ]¾âÿ]¾âÿ^¼ãÿ_½åÿb¿èÿ]¼çÿhÈîÿ~ÞÿÿwØÿÿrÖþÿkÎöÿ~¥ÿZ~ÿQqÿ`|¼o¥½u-ˆ¬ÿlÅÞÿ™îÿÿ›ïÿÿðÿÿ™êüÿrÂéÿgµÜÿ@Ž²ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿb¨Âÿ#q‘ÿ„ÇÞÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿf­Æÿ=Š§ÿ¬êýÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿb©Äÿ9Š¬ÿY®Ñÿ_ºÜÿX·ÙÿO¬ÐÿH£ÈÿL¥ÊÿW±×ÿX·àÿoÐòÿ~ßÿÿyÚÿÿs×þÿ`Åëÿz¡ÿX{ÿQqÿc{­ÂH0ˆ¬ÿY²Îÿ˜íÿÿšíÿÿ›ìÿÿíþÿuÃéÿb°×ÿ=‹¯ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ^¤¾ÿg‡ÿŒÎãÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿj±Ëÿ$w™ÿ’Ôêÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ ßóÿ3 ÿ<Ž¯ÿHž¿ÿBš¼ÿ4‹­ÿ9‹¬ÿiµÑÿGžÂÿS°ØÿzÝúÿáÿÿ{ÝÿÿuÙÿÿS¶Ûÿs™ÿUxÿQqÿ-o‰YÆÔâ8‹«ûA›ºÿ™ìþÿšìÿÿ›ìÿÿ›ëÿÿ€Ïïÿ_¬Ôÿ;‰¬ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿc©Âÿ<†£ÿ©çúÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿT ¾ÿ-…©ÿF–¶ÿ¦åùÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ˜ØíÿM—³ÿ5„¢ÿ>Œªÿg¯Éÿ¢áõÿŠÍäÿ:Ž³ÿX´Úÿäþÿ~ãÿÿ}áÿÿyÜÿÿA¢ÇÿjÿStÿQrüª´U˜µÉ0‹­ÿáóÿ›íÿÿ›ìÿÿ›ëÿÿ‘áùÿ_­Óÿ>‹¯ÿ¥äøÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ¬êýÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ•×íÿ)¥ÿ7”ºÿ:’¶ÿQŸ¼ÿ¡áõÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ¬êýÿ¬êýÿ­ëþÿ­ëþÿ‰Íäÿ=’´ÿpËêÿ‚æÿÿ|äÿÿ~ãÿÿ{Þüÿ)‰®ÿ`…ÿQqÿ`|Äh£»x1Š¬ÿiÀ×ÿœïÿÿ›ìÿÿ›ëÿÿšêÿÿo¾áÿI˜¼ÿ¦åùÿ¬êýÿ¬êýÿ¬êýÿ¬êýÿ¬êýÿ¬êýÿ¬êýÿ¬êýÿ¥åøÿyÀØÿ+‚¥ÿ*ˆ®ÿ:›¿ÿF¡ÄÿD™¼ÿG•µÿ{ÀØÿ¤ã÷ÿ¬êýÿ­ëþÿ­ëþÿ­ëþÿ­ëþÿ¬êýÿ¦åùÿv¿ØÿP¦Èÿˆäüÿ‚èÿÿ{äÿÿ|åÿÿcÇäÿz ÿX{ÿQqÿ/oˆg¯ÊÛ9‹«û>™·ÿ™íýÿšíÿÿšëÿÿšéÿÿ‹Û÷ÿT¦ÌÿJœÀÿ=²ÿ6‰¬ÿ3‡ªÿ1†©ÿ0„¨ÿ.ƒ§ÿ.ƒ§ÿ-ƒ¦ÿ#|¡ÿ ~£ÿ'ˆ®ÿ2“»ÿ:›¿ÿC¡ÃÿO¦ÈÿU¥ÇÿV£ÃÿV¡¾ÿb«Åÿl³Íÿq¸Ñÿp¹Ñÿf±ËÿU¥ÁÿGœ»ÿO§ÇÿyÒìÿ‘ìÿÿ†éÿÿ|æÿÿzäþÿ>¡ÃÿjÿSuÿ Vuîuœ°]¶¬/Š¬ÿrÉáÿ–éÿÿ”æÿÿ’äÿÿ‹àÿÿe¾åÿ@›Æÿ6“½ÿ2ºÿ0ºÿ/Ž¹ÿ/¸ÿ/¸ÿ/¸ÿ.¸ÿ-¸ÿ-¸ÿ1“½ÿ9™Âÿ=œÂÿA ÁÿK¤Äÿ\¬ÍÿnºÛÿ~Çäÿ‚Ëäÿ|ÆàÿuÂÜÿnÀÛÿi¿ÜÿgÁßÿhÄâÿvÑëÿšôþÿ•ðÿÿ‰êÿÿ~çÿÿjÒîÿ €¥ÿ\ÿQqÿ(i†ƒ–¾Í36‰«ý;–¸ÿŠáüÿ‰àÿÿ„Þÿÿ}ÚÿÿqÒûÿIªÕÿ9›Æÿ8šÅÿ8šÅÿ7šÄÿ6™Ãÿ6™Ãÿ8™Åÿ7™Äÿ5˜Âÿ2–¾ÿ3–¿ÿ:œÅÿ>ŸÄÿ? ÁÿJ¥Æÿ\®Ðÿn¼ÜÿƒÍìÿ•Üöÿ™áùÿ–áúÿŽàùÿ†ÞúÿÚøÿ|Ùõÿùýÿùÿÿ—òÿÿìÿÿèþÿ?¢Âÿl’ÿUvÿ
Vv鯿]œµ¦*†«ÿT±Õÿ}Ûÿÿ|ÜÿÿxÙÿÿsÖþÿmÐùÿE¨Ñÿ9›Åÿ9›Åÿ8›Äÿ7›Ãÿ7šÃÿ8›Åÿ8›Æÿ8šÅÿ4—Áÿ2—¿ÿ7™Äÿ;Ãÿ>ŸÂÿQ¬Îÿc¸Úÿm¾àÿwÅçÿ…ÏíÿÖòÿÙôÿŠÚõÿƒÛøÿÛøÿœöýÿûÿÿšøÿÿ—óÿÿŽìÿÿeÈãÿ}£ÿ\€ÿQqþ7t`œÄÍ>‹¬î'†­ÿfÈíÿxÚÿÿwÙÿÿxÚÿÿyÚþÿlÏ÷ÿE¨Ñÿ<žÈÿ=ŸÉÿ8œÅÿ9œÆÿ9œÆÿ8šÆÿ6™Åÿ2˜Ãÿ2—Âÿ6™Äÿ9›Ãÿ;ÃÿO®Òÿe¼àÿpÂæÿuÄæÿxÃäÿzÃãÿxÂáÿxÇæÿ|Óïÿœõüÿùÿÿ•ôÿÿ•óÿÿ–ñÿÿƒáöÿ.Ž±ÿ fŒÿStÿ_|²u¨¾[.„¨þ.Ž¶ÿhËôÿqÓüÿ{Üÿÿ}àÿÿvØþÿnÑúÿX»ãÿD¦Ðÿ=ŸÉÿ<žÉÿ:Çÿ9šÆÿ7šÆÿ4™Åÿ3™Åÿ6™Åÿ7™Äÿ8›ÄÿE¥ÊÿX°Öÿi¼ãÿvÆêÿxÅæÿp»Ûÿe°Ñÿp¾ßÿ“çüÿ˜òÿÿ“ðÿÿìÿÿŽìÿÿêüÿAŸ¿ÿp–ÿVyÿXwÞx¡®`›¶—)„©ÿ0‘¹ÿeÈòÿpÓüÿuÙþÿuÙÿÿuÙÿÿwÜÿÿjÎôÿI­×ÿ?¢Íÿ>¡Ìÿ:œÇÿ8šÆÿ4šÆÿ2šÆÿ3™Åÿ3—Áÿ6˜Àÿ>žÄÿG¡ÇÿX®Ôÿk¾äÿtÃæÿs¿àÿ~Ììÿ‡Øúÿ‡Üüÿ‰äþÿ‰çÿÿˆçÿÿ‡æýÿJ©ÈÿwÿZ~ÿ
Wuí^Ž¦+™ÌÌY˜³¶(ƒ¨ÿ1’ºÿeÆñÿlÏúÿnÓüÿr×þÿtÙÿÿsØÿÿr×þÿgËòÿQµßÿ?¢Ìÿ9œÆÿ4šÆÿ1šÅÿ1™Äÿ1˜Áÿ2˜¿ÿ<œÃÿAÅÿK£Èÿa¸Þÿ}Ðòÿáþÿ‰Ýþÿ~×úÿwÒ÷ÿyÖúÿ~ÜþÿÞüÿI¨ÈÿzŸÿ\€ÿ
VuîX‹¢7²ÌÌ
Y˜³º)ƒ¨ÿ-µÿ]¾êÿiËöÿmÐûÿnÒûÿmÓýÿsÙÿÿ{ßÿÿrØþÿoÓûÿbÆðÿR¹ãÿF°ÚÿB­ÖÿCªÔÿF­ÔÿN²Üÿ\½æÿlÊñÿtÑ÷ÿyÕûÿ|×þÿz×ýÿuÓúÿnÎöÿnÍöÿlÊòÿ:™Àÿxžÿ]ÿXxãUŠŸ0¶¶Ú_¶¥.„¨þ&…­ÿL­ØÿgËõÿgÍöÿgÎøÿoÖýÿwÞÿÿrÙÿÿtÙÿÿtÛÿÿp×þÿiÒûÿgÏ÷ÿgÌõÿfËõÿfËõÿgËöÿiÍöÿjÎöÿnÏ÷ÿpÑúÿqÒüÿpÐûÿkÍ÷ÿU·àÿ(ˆ°ÿq˜ÿ[ÿb€¿„£·ÿÿÿu¨¾s9‰ªø$‚©ÿ1”¼ÿS¼æÿcËõÿiÐùÿkÕýÿmÕýÿr×þÿvÜÿÿzÝÿÿwÚÿÿrÕýÿkÏøÿhÌöÿgËöÿhÌöÿhÍöÿiÎöÿiÎöÿkÎ÷ÿoÐûÿeÅñÿ<œÅÿ}¥ÿiÿ \}óI‚™sªªÿ’½Î/U—²È.…©ÿ!ªÿ3–¿ÿRµßÿeÊõÿfÌ÷ÿjÎøÿpÓüÿvØþÿxÙÿÿuÖÿÿqÔüÿnÑúÿmÎùÿlÎøÿjÎöÿiÎöÿhÍõÿY¼åÿ>žÇÿ#ªÿq™ÿ
b†ù9x”œ£¶ÿÿÿ‰¶Æ[Q•°×/ƒ§þ#€¨ÿ'‡°ÿ:œÆÿM®Ùÿ]¿éÿhÊôÿlÎøÿqÔýÿzÜÿÿ}ÞþÿvØýÿgÉòÿV·áÿC£Íÿ,‹´ÿ}¥ÿp—ÿkèA‚…ƒ¯¸ÿÿÿ¸ÉLn¥¼­?‹ªõ.„¨ÿ'¨ÿ#¨ÿ"‚ªÿ'‡¯ÿ-µÿ2“·ÿ1’´ÿ)‰®ÿ#‚ªÿ}¤ÿxžÿ#wšúP©¼u§½]¿¿ß¿ÔÔ †³ÄJxª¿…k¤¼´\œµ×J‘­ïC‹«úCŒªûI‘­òY™³ÜfŸ¹»q¥¼Ž·ÉU²ÌØÿÿÀÿÿÿÿÿþÿÿÿÿøÿÿÿÿàÿÿÿÿÀÿÿÿÿÿÿþ?ÿÿüÿÿøÿÿðÿÿðÿÿàÿÿÀÿÿÀÿÿÀÿÿ€ÿÿ€ÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿ€ÿÿ€ÿÿÀÿÿÀÿÿàÿÿàÿÿðÿÿøÿÿø?ÿÿüÿÿþÿÿÿÿÿÿÿÿÀÿÿÿÿàÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
"%file: ./rc/check.ico"
 è( @€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ"¢ *ª ª*"¢*¢ ¢ ª *"*¢¢ "ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿøÿÿðÿÿà?ÿÿà?ÿÿæÿÿþÿÿÿÿÿÿÿÿÿ‡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
"%file: ./rc/send16.bmp"
BM66(­÷­œÿœÎÖ֭ﭔÿ”ÎÎ֌ÿŒÎÎÎÅÎ΄ÿ„ÅÅÎsÿsÅÅÅkÿks÷s½½Åk÷k½½½c÷cµµµR÷RBÿB:ÿ:­­­¥­­JïJ)ÿ)¥¥¥BæBœ¥œ:æ:ÿÿ”œ”ÿ÷Œ”ŒïæÞæÞÅÎŌ„™f™™™Ì™ÿÌÌ3Ìf̙ÌÌÌÿÿfÿ™ÿÌ3333f3™3Ì3ÿ3333333f33™33Ì33ÿ3f3f33ff3f™3fÌ3fÿ3™3™33™f3™™3™Ì3™ÿ3Ì3Ì33Ìf3̙3ÌÌ3Ìÿ3ÿ33ÿf3ÿ™3ÿÌ3ÿÿff3fff™fÌfÿf3f33f3ff3™f3Ìf3ÿffff3fffff™ffÌf™f™3f™ff™™f™Ìf™ÿfÌfÌ3f̙fÌÌfÌÿfÿfÿ3fÿ™fÿÌÌÿÿ̙™™3™™™™Ì™™33™f™3̙ÿ™f™f3™3f™f™™f̙3ÿ™™3™™f™™™™™Ì™™ÿ™Ì™Ì3fÌf™Ì™™Ì̙Ìÿ™ÿ™ÿ3™Ìf™ÿ™™ÿ̙ÿÿ̙3Ìf̙Ì̙3Ì33Ì3fÌ3™Ì3ÌÌ3ÿÌfÌf3™ffÌf™Ìf̙fÿ̙̙3̙f̙™Ì™Ì̙ÿÌÌÌÌ3ÌÌfÌ̙ÌÌÌÌÌÿÌÿÌÿ3™ÿfÌÿ™ÌÿÌÌÿÿÌ3ÿfÿ™Ì3ÿ33ÿ3fÿ3™ÿ3Ìÿ3ÿÿfÿf3Ìffÿf™ÿfÌÌfÿÿ™ÿ™3ÿ™fÿ™™ÿ™Ìÿ™ÿÿÌÿÌ3ÿÌfÿ̙ÿÌÌÿÌÿÿÿ3Ìÿfÿÿ™ÿÿÌffÿfÿffÿÿÿffÿfÿÿÿf!¥___www†††–––ËË˲²²×××ÝÝÝãããêêêñññøøøðûÿ¤  €€€ÿÿÿÿÿÿÿÿÿÿÿÿ ---,--,- -*,-
.-------',,- .&)3,-!. #%&&&&&)),-$. #%&),-. ,-
. ,-.------- ,-¼- ,--,--,---
"%file: ./rc/send16mask.bmp"
BM~>(@ÿÿÿÀàðøüÿþÿÿÿÿÿÿÿþÿüÿøðàÀ€
"%file: ./rc/send16masknoshadow.bmp"
BM~>(@ÿÿÿ€ÀàðÿøÿüÿþÿÿÿþÿüÿøðàÀ€
"%file: ./rc/send20.bmp"
BMÆ6(Îÿνÿ½Å÷ŵÿµ­ÿ­¥ÿ¥œÿœÎÖ֔ÿ”ÎÎ֌ÿŒÅÎ΄ÿ„”ï”{ÿ{ÅÅÎsÿsÅÅŽÅÅkÿkµÅ½cÿck÷k½½½µ½½ZÿZc÷cµ½µ­½µRÿRµµ½Z÷Zµµµ­µµR÷RBÿBRïR­­­¥­­JïJ1ÿ1)ÿ)¥¥¥!ÿ!ZÖZBæB”­”JÞJ:æ:ZÎZÿœœœ1æ1ÿ”œ”„¥„ÿ:Ö:RÅR÷Œ”Œ„”„ïsœsæJµJ1Å1æs”sÞZ”ckŒkÖB¥BcŒcÎ!µ!ZŒZÅRŒR:œ:JŒJ½1”1!œ!1Œ1:„:!”!)Œ)1„1!Œ!Œ!Œ!„!){)„!{!„{fÌfÿf3f33f3ff3™f3Ìf3ÿffff3fffff™ffÌf™f™3f™ff™™f™Ìf™ÿfÌfÌ3f̙fÌÌfÌÿfÿfÿ3fÿ™fÿÌÌÿÿ̙™™3™™™™Ì™™33™f™3̙ÿ™f™f3™3f™f™™f̙3ÿ™™3™™f™™™™™Ì™™ÿ™Ì™Ì3fÌf™Ì™™Ì̙Ìÿ™ÿ™ÿ3™Ìf™ÿ™™ÿ̙ÿÿ̙3Ìf̙Ì̙3Ì33Ì3fÌ3™Ì3ÌÌ3ÿÌfÌf3™ffÌf™Ìf̙fÿ̙̙3̙f̙™Ì™Ì̙ÿÌÌÌÌ3ÌÌfÌ̙ÌÌÌÌÌÿÌÿÌÿ3™ÿfÌÿ™ÌÿÌÌÿÿÌ3ÿfÿ™Ì3ÿ33ÿ3fÿ3™ÿ3Ìÿ3ÿÿfÿf3Ìffÿf™ÿfÌÌfÿÿ™ÿ™3ÿ™fÿ™™ÿ™Ìÿ™ÿÿÌÿÌ3ÿÌfÿ̙ÿÌÌÿÌÿÿÿ3Ìÿfÿÿ™ÿÿÌffÿfÿffÿÿÿffÿfÿÿÿf!¥___www†††–––ËË˲²²×××ÝÝÝãããêêêñññøøøðûÿ¤  €€€ÿÿÿÿÿÿÿÿÿÿÿÿbO*[LV3ZB^6Z$$9`<  ]$R$/_=! ]X]]]XXWHN'$_D% U 
EEK-\G* U 5;@@@@@@@EH0TM*U 2555;;>>@@@E4TJU )22555555;@@,]!U #+22255521YU (2+:VUUUUUUUUAOZ
IFXÂP? XS7 ]U. U 
"%file: ./rc/send20mask.bmp"
BMŽ>(P  ÿÿÿÀàðøü?þÿÿÿÿ€ÿÿÀÿÿàÿÿÀÿÿ€ÿÿÿþüðàÀ€
"
"%file: ./rpc.h"
// Copyright (c) 2010 Satoshi Nakamoto
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
void ThreadRPCServer(void* parg);
int CommandLineRPC(int argc, char *argv[]);
"%file: ./rpc.cpp"
// Copyright (c) 2010 Satoshi Nakamoto
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
#undef printf
#include <boost/asio.hpp>
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"
#define printf OutputDebugStringF
// MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
// precompiled in headers.h. The problem might be when the pch file goes over
// a certain size around 145MB. If we need access to json_spirit outside this
// file, we could use the compiled json_spirit option.
using boost::asio::ip::tcp;
using namespace json_spirit;
void ThreadRPCServer2(void* parg);
typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable;
///
/// Note: This interface may still be subject to change.
///
Value help(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"help\n"
"List commands.");
string strRet;
for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
{
try
{
Array params;
(*(*mi).second)(params, true);
}
catch (std::exception& e)
{
// Help text is returned in an exception
string strHelp = string(e.what());
if (strHelp.find('\n') != -1)
strHelp = strHelp.substr(0, strHelp.find('\n'));
strRet += strHelp + "\n";
}
}
strRet = strRet.substr(0,strRet.size()-1);
return strRet;
}
Value stop(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"stop\n"
"Stop bitcoin server.");
// Shutdown will take long enough that the response should get back
CreateThread(Shutdown, NULL);
return "bitcoin server stopping";
}
Value getblockcount(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblockcount\n"
"Returns the number of blocks in the longest block chain.");
return nBestHeight + 1;
}
Value getblocknumber(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblocknumber\n"
"Returns the block number of the latest block in the longest block chain.");
return nBestHeight;
}
Value getconnectioncount(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getconnectioncount\n"
"Returns the number of connections to other nodes.");
return (int)vNodes.size();
}
double GetDifficulty()
{
// Floating point number that is a multiple of the minimum difficulty,
// minimum difficulty = 1.0.
if (pindexBest == NULL)
return 1.0;
int nShift = 256 - 32 - 31; // to fit in a uint
double dMinimum = (CBigNum().SetCompact(bnProofOfWorkLimit.GetCompact()) >> nShift).getuint();
double dCurrently = (CBigNum().SetCompact(pindexBest->nBits) >> nShift).getuint();
return dMinimum / dCurrently;
}
Value getdifficulty(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getdifficulty\n"
"Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
return GetDifficulty();
}
Value getbalance(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getbalance\n"
"Returns the server's available balance.");
return ((double)GetBalance() / (double)COIN);
}
Value getgenerate(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getgenerate\n"
"Returns true or false.");
return (bool)fGenerateBitcoins;
}
Value setgenerate(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"setgenerate <generate> [genproclimit]\n"
"<generate> is true or false to turn generation on or off.\n"
"Generation is limited to [genproclimit] processors, -1 is unlimited.");
bool fGenerate = true;
if (params.size() > 0)
fGenerate = params[0].get_bool();
if (params.size() > 1)
{
int nGenProcLimit = params[1].get_int();
fLimitProcessors = (nGenProcLimit != -1);
CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors);
if (nGenProcLimit != -1)
CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
}
GenerateBitcoins(fGenerate);
return Value::null;
}
Value getinfo(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getinfo");
Object obj;
obj.push_back(Pair("balance", (double)GetBalance() / (double)COIN));
obj.push_back(Pair("blocks", (int)nBestHeight + 1));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
return obj;
}
Value getnewaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"getnewaddress [label]\n"
"Returns a new bitcoin address for receiving payments. "
"If [label] is specified (recommended), it is added to the address book "
"so payments received with the address will be labeled.");
// Parse the label first so we don't generate a key if there's an error
string strLabel;
if (params.size() > 0)
strLabel = params[0].get_str();
// Generate a new key that is added to wallet
string strAddress = PubKeyToAddress(GenerateNewKey());
SetAddressBookName(strAddress, strLabel);
return strAddress;
}
Value setlabel(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"setlabel <bitcoinaddress> <label>\n"
"Sets the label associated with the given address.");
string strAddress = params[0].get_str();
string strLabel;
if (params.size() > 1)
strLabel = params[1].get_str();
SetAddressBookName(strAddress, strLabel);
return Value::null;
}
Value getlabel(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getlabel <bitcoinaddress>\n"
"Returns the label associated with the given address.");
string strAddress = params[0].get_str();
string strLabel;
CRITICAL_BLOCK(cs_mapAddressBook)
{
map<string, string>::iterator mi = mapAddressBook.find(strAddress);
if (mi != mapAddressBook.end() && !(*mi).second.empty())
strLabel = (*mi).second;
}
return strLabel;
}
Value getaddressesbylabel(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getaddressesbylabel <label>\n"
"Returns the list of addresses with the given label.");
string strLabel = params[0].get_str();
// Find all addresses that have the given label
Array ret;
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
const string& strAddress = item.first;
const string& strName = item.second;
if (strName == strLabel)
{
// We're only adding valid bitcoin addresses and not ip addresses
CScript scriptPubKey;
if (scriptPubKey.SetBitcoinAddress(strAddress))
ret.push_back(strAddress);
}
}
}
return ret;
}
Value sendtoaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 4)
throw runtime_error(
"sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.01");
string strAddress = params[0].get_str();
// Amount
if (params[1].get_real() <= 0.0 || params[1].get_real() > 21000000.0)
throw runtime_error("Invalid amount");
int64 nAmount = roundint64(params[1].get_real() * 100.00) * CENT;
// Wallet comments
CWalletTx wtx;
if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
wtx.mapValue["message"] = params[2].get_str();
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str();
string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
if (strError != "")
throw runtime_error(strError);
return "sent";
}
Value listtransactions(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
"listtransactions [count=10] [includegenerated=false]\n"
"Returns up to [count] most recent transactions.");
int64 nCount = 10;
if (params.size() > 0)
nCount = params[0].get_int64();
bool fGenerated = false;
if (params.size() > 1)
fGenerated = params[1].get_bool();
Array ret;
//// not finished
ret.push_back("not implemented yet");
return ret;
}
Value getreceivedbyaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
"Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
// Bitcoin address
string strAddress = params[0].get_str();
CScript scriptPubKey;
if (!scriptPubKey.SetBitcoinAddress(strAddress))
throw runtime_error("Invalid bitcoin address");
if (!IsMine(scriptPubKey))
return (double)0.0;
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 1)
nMinDepth = params[1].get_int();
// Tally
int64 nAmount = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
foreach(const CTxOut& txout, wtx.vout)
if (txout.scriptPubKey == scriptPubKey)
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
}
}
return (double)nAmount / (double)COIN;
}
Value getreceivedbylabel(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getreceivedbylabel <label> [minconf=1]\n"
"Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.");
// Get the set of pub keys that have the label
string strLabel = params[0].get_str();
set<CScript> setPubKey;
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
const string& strAddress = item.first;
const string& strName = item.second;
if (strName == strLabel)
{
// We're only counting our own valid bitcoin addresses and not ip addresses
CScript scriptPubKey;
if (scriptPubKey.SetBitcoinAddress(strAddress))
if (IsMine(scriptPubKey))
setPubKey.insert(scriptPubKey);
}
}
}
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 1)
nMinDepth = params[1].get_int();
// Tally
int64 nAmount = 0;
CRITICAL_BLOCK(cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
foreach(const CTxOut& txout, wtx.vout)
if (setPubKey.count(txout.scriptPubKey))
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
}
}
return (double)nAmount / (double)COIN;
}
struct tallyitem
{
int64 nAmount;
int nConf;
tallyitem()
{
nAmount = 0;
nConf = INT_MAX;
}
};
Value ListReceived(const Array& params, bool fByLabels)
{
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
// Whether to include empty accounts
bool fIncludeEmpty = false;
if (params.size() > 1)
fIncludeEmpty = params[1].get_bool();
// Tally
map<uint160, tallyitem> mapTally;
CRITICAL_BLOCK(cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < nMinDepth)
continue;
foreach(const CTxOut& txout, wtx.vout)
{
// Only counting our own bitcoin addresses and not ip addresses
uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160();
if (hash160 == 0 || !mapPubKeys.count(hash160)) // IsMine
continue;
tallyitem& item = mapTally[hash160];
item.nAmount += txout.nValue;
item.nConf = min(item.nConf, nDepth);
}
}
}
// Reply
Array ret;
map<string, tallyitem> mapLabelTally;
CRITICAL_BLOCK(cs_mapAddressBook)
{
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
const string& strAddress = item.first;
const string& strLabel = item.second;
uint160 hash160;
if (!AddressToHash160(strAddress, hash160))
continue;
map<uint160, tallyitem>::iterator it = mapTally.find(hash160);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
int64 nAmount = 0;
int nConf = INT_MAX;
if (it != mapTally.end())
{
nAmount = (*it).second.nAmount;
nConf = (*it).second.nConf;
}
if (fByLabels)
{
tallyitem& item = mapLabelTally[strLabel];
item.nAmount += nAmount;
item.nConf = min(item.nConf, nConf);
}
else
{
Object obj;
obj.push_back(Pair("address", strAddress));
obj.push_back(Pair("label", strLabel));
obj.push_back(Pair("amount", (double)nAmount / (double)COIN));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj);
}
}
}
if (fByLabels)
{
for (map<string, tallyitem>::iterator it = mapLabelTally.begin(); it != mapLabelTally.end(); ++it)
{
int64 nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
Object obj;
obj.push_back(Pair("label", (*it).first));
obj.push_back(Pair("amount", (double)nAmount / (double)COIN));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj);
}
}
return ret;
}
Value listreceivedbyaddress(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
"listreceivedbyaddress [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include addresses that haven't received any payments.\n"
"Returns an array of objects containing:\n"
" \"address\" : receiving address\n"
" \"label\" : the label of the receiving address\n"
" \"amount\" : total amount received by the address\n"
" \"confirmations\" : number of confirmations of the most recent transaction included");
return ListReceived(params, false);
}
Value listreceivedbylabel(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
"listreceivedbylabel [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include labels that haven't received any payments.\n"
"Returns an array of objects containing:\n"
" \"label\" : the label of the receiving addresses\n"
" \"amount\" : total amount received by addresses with this label\n"
" \"confirmations\" : number of confirmations of the most recent transaction included");
return ListReceived(params, true);
}
//
// Call Table
//
pair<string, rpcfn_type> pCallTable[] =
{
make_pair("help", &help),
make_pair("stop", &stop),
make_pair("getblockcount", &getblockcount),
make_pair("getblocknumber", &getblocknumber),
make_pair("getconnectioncount", &getconnectioncount),
make_pair("getdifficulty", &getdifficulty),
make_pair("getbalance", &getbalance),
make_pair("getgenerate", &getgenerate),
make_pair("setgenerate", &setgenerate),
make_pair("getinfo", &getinfo),
make_pair("getnewaddress", &getnewaddress),
make_pair("setlabel", &setlabel),
make_pair("getlabel", &getlabel),
make_pair("getaddressesbylabel", &getaddressesbylabel),
make_pair("sendtoaddress", &sendtoaddress),
make_pair("listtransactions", &listtransactions),
make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
make_pair("getreceivedbyaddress", &getreceivedbyaddress),
make_pair("getreceivedbylabel", &getreceivedbylabel),
make_pair("listreceivedbyaddress", &listreceivedbyaddress),
make_pair("listreceivedbylabel", &listreceivedbylabel),
};
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
//
// HTTP protocol
//
// This ain't Apache. We're just using HTTP header for the length field
// and to be compatible with other JSON-RPC implementations.
//
string HTTPPost(const string& strMsg)
{
return strprintf(
"POST / HTTP/1.1\r\n"
"User-Agent: json-rpc/1.0\r\n"
"Host: 127.0.0.1\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"Accept: application/json\r\n"
"\r\n"
"%s",
strMsg.size(),
strMsg.c_str());
}
string HTTPReply(const string& strMsg, int nStatus=200)
{
string strStatus;
if (nStatus == 200) strStatus = "OK";
if (nStatus == 500) strStatus = "Internal Server Error";
return strprintf(
"HTTP/1.1 %d %s\r\n"
"Connection: close\r\n"
"Content-Length: %d\r\n"
"Content-Type: application/json\r\n"
"Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n"
"Server: json-rpc/1.0\r\n"
"\r\n"
"%s",
nStatus,
strStatus.c_str(),
strMsg.size(),
strMsg.c_str());
}
int ReadHTTPHeader(tcp::iostream& stream)
{
int nLen = 0;
loop
{
string str;
std::getline(stream, str);
if (str.empty() || str == "\r")
break;
if (str.substr(0,15) == "Content-Length:")
nLen = atoi(str.substr(15));
}
return nLen;
}
inline string ReadHTTP(tcp::iostream& stream)
{
// Read header
int nLen = ReadHTTPHeader(stream);
if (nLen <= 0)
return string();
// Read message
vector<char> vch(nLen);
stream.read(&vch[0], nLen);
return string(vch.begin(), vch.end());
}
//
// JSON-RPC protocol
//
// http://json-rpc.org/wiki/specification
// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
//
string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
{
Object request;
request.push_back(Pair("method", strMethod));
request.push_back(Pair("params", params));
request.push_back(Pair("id", id));
return write_string(Value(request), false) + "\n";
}
string JSONRPCReply(const Value& result, const Value& error, const Value& id)
{
Object reply;
if (error.type() != null_type)
reply.push_back(Pair("result", Value::null));
else
reply.push_back(Pair("result", result));
reply.push_back(Pair("error", error));
reply.push_back(Pair("id", id));
return write_string(Value(reply), false) + "\n";
}
void ThreadRPCServer(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
try
{
vnThreadsRunning[4]++;
ThreadRPCServer2(parg);
vnThreadsRunning[4]--;
}
catch (std::exception& e) {
vnThreadsRunning[4]--;
PrintException(&e, "ThreadRPCServer()");
} catch (...) {
vnThreadsRunning[4]--;
PrintException(NULL, "ThreadRPCServer()");
}
printf("ThreadRPCServer exiting\n");
}
void ThreadRPCServer2(void* parg)
{
printf("ThreadRPCServer started\n");
// Bind to loopback 127.0.0.1 so the socket can only be accessed locally
boost::asio::io_service io_service;
tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 8332);
tcp::acceptor acceptor(io_service, endpoint);
loop
{
// Accept connection
tcp::iostream stream;
tcp::endpoint peer;
vnThreadsRunning[4]--;
acceptor.accept(*stream.rdbuf(), peer);
vnThreadsRunning[4]++;
if (fShutdown)
return;
// Shouldn't be possible for anyone else to connect, but just in case
if (peer.address().to_string() != "127.0.0.1")
continue;
// Receive request
string strRequest = ReadHTTP(stream);
printf("ThreadRPCServer request=%s", strRequest.c_str());
// Handle multiple invocations per request
string::iterator begin = strRequest.begin();
while (skipspaces(begin), begin != strRequest.end())
{
string::iterator prev = begin;
Value id;
try
{
// Parse request
Value valRequest;
if (!read_range(begin, strRequest.end(), valRequest))
throw runtime_error("Parse error.");
const Object& request = valRequest.get_obj();
if (find_value(request, "method").type() != str_type ||
find_value(request, "params").type() != array_type)
throw runtime_error("Invalid request.");
string strMethod = find_value(request, "method").get_str();
const Array& params = find_value(request, "params").get_array();
id = find_value(request, "id");
// Execute
map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
if (mi == mapCallTable.end())
throw runtime_error("Method not found.");
Value result = (*(*mi).second)(params, false);
// Send reply
string strReply = JSONRPCReply(result, Value::null, id);
stream << HTTPReply(strReply, 200) << std::flush;
}
catch (std::exception& e)
{
// Send error reply
string strReply = JSONRPCReply(Value::null, e.what(), id);
stream << HTTPReply(strReply, 500) << std::flush;
}
if (begin == prev)
break;
}
}
}
Value CallRPC(const string& strMethod, const Array& params)
{
// Connect to localhost
tcp::iostream stream("127.0.0.1", "8332");
if (stream.fail())
throw runtime_error("couldn't connect to server");
// Send request
string strRequest = JSONRPCRequest(strMethod, params, 1);
stream << HTTPPost(strRequest) << std::flush;
// Receive reply
string strReply = ReadHTTP(stream);
if (strReply.empty())
throw runtime_error("no response from server");
// Parse reply
Value valReply;
if (!read_string(strReply, valReply))
throw runtime_error("couldn't parse reply from server");
const Object& reply = valReply.get_obj();
if (reply.empty())
throw runtime_error("expected reply to have result, error and id properties");
const Value& result = find_value(reply, "result");
const Value& error = find_value(reply, "error");
const Value& id = find_value(reply, "id");
if (error.type() == str_type)
throw runtime_error(error.get_str());
else if (error.type() != null_type)
throw runtime_error(write_string(error, false));
return result;
}
template<typename T>
void ConvertTo(Value& value)
{
if (value.type() == str_type)
{
// reinterpret string as unquoted json value
Value value2;
if (!read_string(value.get_str(), value2))
throw runtime_error("type mismatch");
value = value2.get_value<T>();
}
else
{
value = value.get_value<T>();
}
}
int CommandLineRPC(int argc, char *argv[])
{
try
{
// Check that method exists
if (argc < 2)
throw runtime_error("too few parameters");
string strMethod = argv[1];
if (!mapCallTable.count(strMethod))
throw runtime_error(strprintf("unknown command: %s", strMethod.c_str()));
Value result;
if (argc == 3 && strcmp(argv[2], "-?") == 0)
{
// Call help locally, help text is returned in an exception
try
{
map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
Array params;
(*(*mi).second)(params, true);
}
catch (std::exception& e)
{
result = e.what();
}
}
else
{
// Parameters default to strings
Array params;
for (int i = 2; i < argc; i++)
params.push_back(argv[i]);
int n = params.size();
//
// Special case non-string parameter types
//
if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
if (strMethod == "listtransactions" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listtransactions" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]);
// Execute
result = CallRPC(strMethod, params);
}
// Print result
string strResult = (result.type() == str_type ? result.get_str() : write_string(result, true));
if (result.type() != null_type)
{
if (fWindows && fGUI)
// Windows GUI apps can't print to command line,
// so settle for a message box yuck
MyMessageBox(strResult.c_str(), "Bitcoin", wxOK);
else
fprintf(stdout, "%s\n", strResult.c_str());
}
return 0;
}
catch (std::exception& e) {
if (fWindows && fGUI)
MyMessageBox(strprintf("error: %s\n", e.what()).c_str(), "Bitcoin", wxOK);
else
fprintf(stderr, "error: %s\n", e.what());
} catch (...) {
PrintException(NULL, "CommandLineRPC()");
}
return 1;
}
#ifdef TEST
int main(int argc, char *argv[])
{
#ifdef _MSC_VER
// Turn off microsoft heap dump noise
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
#endif
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
try
{
if (argc >= 2 && string(argv[1]) == "-server")
{
printf("server ready\n");
ThreadRPCServer(NULL);
}
else
{
return CommandLineRPC(argc, argv);
}
}
catch (std::exception& e) {
PrintException(&e, "main()");
} catch (...) {
PrintException(NULL, "main()");
}
return 0;
}
#endif
"%file: ./script.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;
enum
{
SIGHASH_ALL = 1,
SIGHASH_NONE = 2,
SIGHASH_SINGLE = 3,
SIGHASH_ANYONECANPAY = 0x80,
};
enum opcodetype
{
// push value
OP_0=0,
OP_FALSE=OP_0,
OP_PUSHDATA1=76,
OP_PUSHDATA2,
OP_PUSHDATA4,
OP_1NEGATE,
OP_RESERVED,
OP_1,
OP_TRUE=OP_1,
OP_2,
OP_3,
OP_4,
OP_5,
OP_6,
OP_7,
OP_8,
OP_9,
OP_10,
OP_11,
OP_12,
OP_13,
OP_14,
OP_15,
OP_16,
// control
OP_NOP,
OP_VER,
OP_IF,
OP_NOTIF,
OP_VERIF,
OP_VERNOTIF,
OP_ELSE,
OP_ENDIF,
OP_VERIFY,
OP_RETURN,
// stack ops
OP_TOALTSTACK,
OP_FROMALTSTACK,
OP_2DROP,
OP_2DUP,
OP_3DUP,
OP_2OVER,
OP_2ROT,
OP_2SWAP,
OP_IFDUP,
OP_DEPTH,
OP_DROP,
OP_DUP,
OP_NIP,
OP_OVER,
OP_PICK,
OP_ROLL,
OP_ROT,
OP_SWAP,
OP_TUCK,
// splice ops
OP_CAT,
OP_SUBSTR,
OP_LEFT,
OP_RIGHT,
OP_SIZE,
// bit logic
OP_INVERT,
OP_AND,
OP_OR,
OP_XOR,
OP_EQUAL,
OP_EQUALVERIFY,
OP_RESERVED1,
OP_RESERVED2,
// numeric
OP_1ADD,
OP_1SUB,
OP_2MUL,
OP_2DIV,
OP_NEGATE,
OP_ABS,
OP_NOT,
OP_0NOTEQUAL,
OP_ADD,
OP_SUB,
OP_MUL,
OP_DIV,
OP_MOD,
OP_LSHIFT,
OP_RSHIFT,
OP_BOOLAND,
OP_BOOLOR,
OP_NUMEQUAL,
OP_NUMEQUALVERIFY,
OP_NUMNOTEQUAL,
OP_LESSTHAN,
OP_GREATERTHAN,
OP_LESSTHANOREQUAL,
OP_GREATERTHANOREQUAL,
OP_MIN,
OP_MAX,
OP_WITHIN,
// crypto
OP_RIPEMD160,
OP_SHA1,
OP_SHA256,
OP_HASH160,
OP_HASH256,
OP_CODESEPARATOR,
OP_CHECKSIG,
OP_CHECKSIGVERIFY,
OP_CHECKMULTISIG,
OP_CHECKMULTISIGVERIFY,
// multi-byte opcodes
OP_SINGLEBYTE_END = 0xF0,
OP_DOUBLEBYTE_BEGIN = 0xF000,
// template matching params
OP_PUBKEY,
OP_PUBKEYHASH,
OP_INVALIDOPCODE = 0xFFFF,
};
inline const char* GetOpName(opcodetype opcode)
{
switch (opcode)
{
// push value
case OP_0 : return "0";
case OP_PUSHDATA1 : return "OP_PUSHDATA1";
case OP_PUSHDATA2 : return "OP_PUSHDATA2";
case OP_PUSHDATA4 : return "OP_PUSHDATA4";
case OP_1NEGATE : return "-1";
case OP_RESERVED : return "OP_RESERVED";
case OP_1 : return "1";
case OP_2 : return "2";
case OP_3 : return "3";
case OP_4 : return "4";
case OP_5 : return "5";
case OP_6 : return "6";
case OP_7 : return "7";
case OP_8 : return "8";
case OP_9 : return "9";
case OP_10 : return "10";
case OP_11 : return "11";
case OP_12 : return "12";
case OP_13 : return "13";
case OP_14 : return "14";
case OP_15 : return "15";
case OP_16 : return "16";
// control
case OP_NOP : return "OP_NOP";
case OP_VER : return "OP_VER";
case OP_IF : return "OP_IF";
case OP_NOTIF : return "OP_NOTIF";
case OP_VERIF : return "OP_VERIF";
case OP_VERNOTIF : return "OP_VERNOTIF";
case OP_ELSE : return "OP_ELSE";
case OP_ENDIF : return "OP_ENDIF";
case OP_VERIFY : return "OP_VERIFY";
case OP_RETURN : return "OP_RETURN";
// stack ops
case OP_TOALTSTACK : return "OP_TOALTSTACK";
case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
case OP_2DROP : return "OP_2DROP";
case OP_2DUP : return "OP_2DUP";
case OP_3DUP : return "OP_3DUP";
case OP_2OVER : return "OP_2OVER";
case OP_2ROT : return "OP_2ROT";
case OP_2SWAP : return "OP_2SWAP";
case OP_IFDUP : return "OP_IFDUP";
case OP_DEPTH : return "OP_DEPTH";
case OP_DROP : return "OP_DROP";
case OP_DUP : return "OP_DUP";
case OP_NIP : return "OP_NIP";
case OP_OVER : return "OP_OVER";
case OP_PICK : return "OP_PICK";
case OP_ROLL : return "OP_ROLL";
case OP_ROT : return "OP_ROT";
case OP_SWAP : return "OP_SWAP";
case OP_TUCK : return "OP_TUCK";
// splice ops
case OP_CAT : return "OP_CAT";
case OP_SUBSTR : return "OP_SUBSTR";
case OP_LEFT : return "OP_LEFT";
case OP_RIGHT : return "OP_RIGHT";
case OP_SIZE : return "OP_SIZE";
// bit logic
case OP_INVERT : return "OP_INVERT";
case OP_AND : return "OP_AND";
case OP_OR : return "OP_OR";
case OP_XOR : return "OP_XOR";
case OP_EQUAL : return "OP_EQUAL";
case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
case OP_RESERVED1 : return "OP_RESERVED1";
case OP_RESERVED2 : return "OP_RESERVED2";
// numeric
case OP_1ADD : return "OP_1ADD";
case OP_1SUB : return "OP_1SUB";
case OP_2MUL : return "OP_2MUL";
case OP_2DIV : return "OP_2DIV";
case OP_NEGATE : return "OP_NEGATE";
case OP_ABS : return "OP_ABS";
case OP_NOT : return "OP_NOT";
case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
case OP_ADD : return "OP_ADD";
case OP_SUB : return "OP_SUB";
case OP_MUL : return "OP_MUL";
case OP_DIV : return "OP_DIV";
case OP_MOD : return "OP_MOD";
case OP_LSHIFT : return "OP_LSHIFT";
case OP_RSHIFT : return "OP_RSHIFT";
case OP_BOOLAND : return "OP_BOOLAND";
case OP_BOOLOR : return "OP_BOOLOR";
case OP_NUMEQUAL : return "OP_NUMEQUAL";
case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
case OP_LESSTHAN : return "OP_LESSTHAN";
case OP_GREATERTHAN : return "OP_GREATERTHAN";
case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
case OP_MIN : return "OP_MIN";
case OP_MAX : return "OP_MAX";
case OP_WITHIN : return "OP_WITHIN";
// crypto
case OP_RIPEMD160 : return "OP_RIPEMD160";
case OP_SHA1 : return "OP_SHA1";
case OP_SHA256 : return "OP_SHA256";
case OP_HASH160 : return "OP_HASH160";
case OP_HASH256 : return "OP_HASH256";
case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
case OP_CHECKSIG : return "OP_CHECKSIG";
case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
// multi-byte opcodes
case OP_SINGLEBYTE_END : return "OP_SINGLEBYTE_END";
case OP_DOUBLEBYTE_BEGIN : return "OP_DOUBLEBYTE_BEGIN";
case OP_PUBKEY : return "OP_PUBKEY";
case OP_PUBKEYHASH : return "OP_PUBKEYHASH";
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
default:
return "UNKNOWN_OPCODE";
}
};
inline string ValueString(const vector<unsigned char>& vch)
{
if (vch.size() <= 4)
return strprintf("%d", CBigNum(vch).getint());
else
return HexNumStr(vch.begin(), vch.end());
//return string("(") + HexStr(vch.begin(), vch.end()) + string(")");
}
inline string StackString(const vector<vector<unsigned char> >& vStack)
{
string str;
foreach(const vector<unsigned char>& vch, vStack)
{
if (!str.empty())
str += " ";
str += ValueString(vch);
}
return str;
}
class CScript : public vector<unsigned char>
{
protected:
CScript& push_int64(int64 n)
{
if (n == -1 || (n >= 1 && n <= 16))
{
push_back(n + (OP_1 - 1));
}
else
{
CBigNum bn(n);
*this << bn.getvch();
}
return (*this);
}
CScript& push_uint64(uint64 n)
{
if (n == -1 || (n >= 1 && n <= 16))
{
push_back(n + (OP_1 - 1));
}
else
{
CBigNum bn(n);
*this << bn.getvch();
}
return (*this);
}
public:
CScript() { }
CScript(const CScript& b) : vector<unsigned char>(b.begin(), b.end()) { }
CScript(const_iterator pbegin, const_iterator pend) : vector<unsigned char>(pbegin, pend) { }
#ifndef _MSC_VER
CScript(const unsigned char* pbegin, const unsigned char* pend) : vector<unsigned char>(pbegin, pend) { }
#endif
CScript& operator+=(const CScript& b)
{
insert(end(), b.begin(), b.end());
return *this;
}
friend CScript operator+(const CScript& a, const CScript& b)
{
CScript ret = a;
ret += b;
return (ret);
}
explicit CScript(char b) { operator<<(b); }
explicit CScript(short b) { operator<<(b); }
explicit CScript(int b) { operator<<(b); }
explicit CScript(long b) { operator<<(b); }
explicit CScript(int64 b) { operator<<(b); }
explicit CScript(unsigned char b) { operator<<(b); }
explicit CScript(unsigned int b) { operator<<(b); }
explicit CScript(unsigned short b) { operator<<(b); }
explicit CScript(unsigned long b) { operator<<(b); }
explicit CScript(uint64 b) { operator<<(b); }
explicit CScript(opcodetype b) { operator<<(b); }
explicit CScript(const uint256& b) { operator<<(b); }
explicit CScript(const CBigNum& b) { operator<<(b); }
explicit CScript(const vector<unsigned char>& b) { operator<<(b); }
CScript& operator<<(char b) { return (push_int64(b)); }
CScript& operator<<(short b) { return (push_int64(b)); }
CScript& operator<<(int b) { return (push_int64(b)); }
CScript& operator<<(long b) { return (push_int64(b)); }
CScript& operator<<(int64 b) { return (push_int64(b)); }
CScript& operator<<(unsigned char b) { return (push_uint64(b)); }
CScript& operator<<(unsigned int b) { return (push_uint64(b)); }
CScript& operator<<(unsigned short b) { return (push_uint64(b)); }
CScript& operator<<(unsigned long b) { return (push_uint64(b)); }
CScript& operator<<(uint64 b) { return (push_uint64(b)); }
CScript& operator<<(opcodetype opcode)
{
if (opcode <= OP_SINGLEBYTE_END)
{
insert(end(), (unsigned char)opcode);
}
else
{
assert(opcode >= OP_DOUBLEBYTE_BEGIN);
insert(end(), (unsigned char)(opcode >> 8));
insert(end(), (unsigned char)(opcode & 0xFF));
}
return (*this);
}
CScript& operator<<(const uint160& b)
{
insert(end(), sizeof(b));
insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b));
return (*this);
}
CScript& operator<<(const uint256& b)
{
insert(end(), sizeof(b));
insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b));
return (*this);
}
CScript& operator<<(const CBigNum& b)
{
*this << b.getvch();
return (*this);
}
CScript& operator<<(const vector<unsigned char>& b)
{
if (b.size() < OP_PUSHDATA1)
{
insert(end(), (unsigned char)b.size());
}
else if (b.size() <= 0xff)
{
insert(end(), OP_PUSHDATA1);
insert(end(), (unsigned char)b.size());
}
else
{
insert(end(), OP_PUSHDATA2);
unsigned short nSize = b.size();
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
}
insert(end(), b.begin(), b.end());
return (*this);
}
CScript& operator<<(const CScript& b)
{
// I'm not sure if this should push the script or concatenate scripts.
// If there's ever a use for pushing a script onto a script, delete this member fn
assert(("warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate", false));
return (*this);
}
bool GetOp(iterator& pc, opcodetype& opcodeRet, vector<unsigned char>& vchRet)
{
// Wrapper so it can be called with either iterator or const_iterator
const_iterator pc2 = pc;
bool fRet = GetOp(pc2, opcodeRet, vchRet);
pc = begin() + (pc2 - begin());
return fRet;
}
bool GetOp(const_iterator& pc, opcodetype& opcodeRet, vector<unsigned char>& vchRet) const
{
opcodeRet = OP_INVALIDOPCODE;
vchRet.clear();
if (pc >= end())
return false;
// Read instruction
unsigned int opcode = *pc++;
if (opcode >= OP_SINGLEBYTE_END)
{
if (pc + 1 > end())
return false;
opcode <<= 8;
opcode |= *pc++;
}
// Immediate operand
if (opcode <= OP_PUSHDATA4)
{
unsigned int nSize = opcode;
if (opcode == OP_PUSHDATA1)
{
if (pc + 1 > end())
return false;
nSize = *pc++;
}
else if (opcode == OP_PUSHDATA2)
{
if (pc + 2 > end())
return false;
nSize = 0;
memcpy(&nSize, &pc[0], 2);
pc += 2;
}
else if (opcode == OP_PUSHDATA4)
{
if (pc + 4 > end())
return false;
memcpy(&nSize, &pc[0], 4);
pc += 4;
}
if (pc + nSize > end())
return false;
vchRet.assign(pc, pc + nSize);
pc += nSize;
}
opcodeRet = (opcodetype)opcode;
return true;
}
void FindAndDelete(const CScript& b)
{
iterator pc = begin();
opcodetype opcode;
vector<unsigned char> vchPushValue;
int count = 0;
do
{
while (end() - pc >= b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
{
erase(pc, pc + b.size());
count++;
}
}
while (GetOp(pc, opcode, vchPushValue));
//printf("FindAndDeleted deleted %d items\n", count); /// debug
}
uint160 GetBitcoinAddressHash160() const
{
opcodetype opcode;
vector<unsigned char> vch;
CScript::const_iterator pc = begin();
if (!GetOp(pc, opcode, vch) || opcode != OP_DUP) return 0;
if (!GetOp(pc, opcode, vch) || opcode != OP_HASH160) return 0;
if (!GetOp(pc, opcode, vch) || vch.size() != sizeof(uint160)) return 0;
uint160 hash160 = uint160(vch);
if (!GetOp(pc, opcode, vch) || opcode != OP_EQUALVERIFY) return 0;
if (!GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG) return 0;
if (pc != end()) return 0;
return hash160;
}
string GetBitcoinAddress() const
{
uint160 hash160 = GetBitcoinAddressHash160();
if (hash160 == 0)
return "";
return Hash160ToAddress(hash160);
}
void SetBitcoinAddress(const uint160& hash160)
{
this->clear();
*this << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
}
void SetBitcoinAddress(const vector<unsigned char>& vchPubKey)
{
SetBitcoinAddress(Hash160(vchPubKey));
}
bool SetBitcoinAddress(const string& strAddress)
{
this->clear();
uint160 hash160;
if (!AddressToHash160(strAddress, hash160))
return false;
SetBitcoinAddress(hash160);
return true;
}
void PrintHex() const
{
printf("CScript(%s)\n", HexStr(begin(), end()).c_str());
}
string ToString() const
{
string str;
opcodetype opcode;
vector<unsigned char> vch;
const_iterator it = begin();
while (GetOp(it, opcode, vch))
{
if (!str.empty())
str += " ";
if (opcode <= OP_PUSHDATA4)
str += ValueString(vch);
else
str += GetOpName(opcode);
}
return str;
}
void print() const
{
printf("%s\n", ToString().c_str());
}
};
bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType=0,
vector<vector<unsigned char> >* pvStackRet=NULL);
uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
bool IsMine(const CScript& scriptPubKey);
bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned char>& vchPubKeyRet);
bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret);
bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript());
bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType=0);
"%file: ./script.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"
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
typedef vector<unsigned char> valtype;
static const valtype vchFalse(0);
static const valtype vchZero(0);
static const valtype vchTrue(1, 1);
static const CBigNum bnZero(0);
static const CBigNum bnOne(1);
static const CBigNum bnFalse(0);
static const CBigNum bnTrue(1);
bool CastToBool(const valtype& vch)
{
return (CBigNum(vch) != bnZero);
}
void MakeSameSize(valtype& vch1, valtype& vch2)
{
// Lengthen the shorter one
if (vch1.size() < vch2.size())
vch1.resize(vch2.size(), 0);
if (vch2.size() < vch1.size())
vch2.resize(vch1.size(), 0);
}
//
// Script is a stack machine (like Forth) that evaluates a predicate
// returning a bool indicating valid or not. There are no loops.
//
#define stacktop(i) (stack.at(stack.size()+(i)))
#define altstacktop(i) (altstack.at(altstack.size()+(i)))
bool EvalScript(const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType,
vector<vector<unsigned char> >* pvStackRet)
{
CAutoBN_CTX pctx;
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
CScript::const_iterator pbegincodehash = script.begin();
vector<bool> vfExec;
vector<valtype> stack;
vector<valtype> altstack;
if (pvStackRet)
pvStackRet->clear();
while (pc < pend)
{
bool fExec = !count(vfExec.begin(), vfExec.end(), false);
//
// Read instruction
//
opcodetype opcode;
valtype vchPushValue;
if (!script.GetOp(pc, opcode, vchPushValue))
return false;
if (fExec && opcode <= OP_PUSHDATA4)
stack.push_back(vchPushValue);
else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
switch (opcode)
{
//
// Push value
//
case OP_1NEGATE:
case OP_1:
case OP_2:
case OP_3:
case OP_4:
case OP_5:
case OP_6:
case OP_7:
case OP_8:
case OP_9:
case OP_10:
case OP_11:
case OP_12:
case OP_13:
case OP_14:
case OP_15:
case OP_16:
{
// ( -- value)
CBigNum bn((int)opcode - (int)(OP_1 - 1));
stack.push_back(bn.getvch());
}
break;
//
// Control
//
case OP_NOP:
break;
case OP_VER:
{
CBigNum bn(VERSION);
stack.push_back(bn.getvch());
}
break;
case OP_IF:
case OP_NOTIF:
case OP_VERIF:
case OP_VERNOTIF:
{
// <expression> if [statements] [else [statements]] endif
bool fValue = false;
if (fExec)
{
if (stack.size() < 1)
return false;
valtype& vch = stacktop(-1);
if (opcode == OP_VERIF || opcode == OP_VERNOTIF)
fValue = (CBigNum(VERSION) >= CBigNum(vch));
else
fValue = CastToBool(vch);
if (opcode == OP_NOTIF || opcode == OP_VERNOTIF)
fValue = !fValue;
stack.pop_back();
}
vfExec.push_back(fValue);
}
break;
case OP_ELSE:
{
if (vfExec.empty())
return false;
vfExec.back() = !vfExec.back();
}
break;
case OP_ENDIF:
{
if (vfExec.empty())
return false;
vfExec.pop_back();
}
break;
case OP_VERIFY:
{
// (true -- ) or
// (false -- false) and return
if (stack.size() < 1)
return false;
bool fValue = CastToBool(stacktop(-1));
if (fValue)
stack.pop_back();
else
pc = pend;
}
break;
case OP_RETURN:
{
pc = pend;
}
break;
//
// Stack ops
//
case OP_TOALTSTACK:
{
if (stack.size() < 1)
return false;
altstack.push_back(stacktop(-1));
stack.pop_back();
}
break;
case OP_FROMALTSTACK:
{
if (altstack.size() < 1)
return false;
stack.push_back(altstacktop(-1));
altstack.pop_back();
}
break;
case OP_2DROP:
{
// (x1 x2 -- )
stack.pop_back();
stack.pop_back();
}
break;
case OP_2DUP:
{
// (x1 x2 -- x1 x2 x1 x2)
if (stack.size() < 2)
return false;
valtype vch1 = stacktop(-2);
valtype vch2 = stacktop(-1);
stack.push_back(vch1);
stack.push_back(vch2);
}
break;
case OP_3DUP:
{
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
if (stack.size() < 3)
return false;
valtype vch1 = stacktop(-3);
valtype vch2 = stacktop(-2);
valtype vch3 = stacktop(-1);
stack.push_back(vch1);
stack.push_back(vch2);
stack.push_back(vch3);
}
break;
case OP_2OVER:
{
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
if (stack.size() < 4)
return false;
valtype vch1 = stacktop(-4);
valtype vch2 = stacktop(-3);
stack.push_back(vch1);
stack.push_back(vch2);
}
break;
case OP_2ROT:
{
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
if (stack.size() < 6)
return false;
valtype vch1 = stacktop(-6);
valtype vch2 = stacktop(-5);
stack.erase(stack.end()-6, stack.end()-4);
stack.push_back(vch1);
stack.push_back(vch2);
}
break;
case OP_2SWAP:
{
// (x1 x2 x3 x4 -- x3 x4 x1 x2)
if (stack.size() < 4)
return false;
swap(stacktop(-4), stacktop(-2));
swap(stacktop(-3), stacktop(-1));
}
break;
case OP_IFDUP:
{
// (x - 0 | x x)
if (stack.size() < 1)
return false;
valtype vch = stacktop(-1);
if (CastToBool(vch))
stack.push_back(vch);
}
break;
case OP_DEPTH:
{
// -- stacksize
CBigNum bn(stack.size());
stack.push_back(bn.getvch());
}
break;
case OP_DROP:
{
// (x -- )
if (stack.size() < 1)
return false;
stack.pop_back();
}
break;
case OP_DUP:
{
// (x -- x x)
if (stack.size() < 1)
return false;
valtype vch = stacktop(-1);
stack.push_back(vch);
}
break;
case OP_NIP:
{
// (x1 x2 -- x2)
if (stack.size() < 2)
return false;
stack.erase(stack.end() - 2);
}
break;
case OP_OVER:
{
// (x1 x2 -- x1 x2 x1)
if (stack.size() < 2)
return false;
valtype vch = stacktop(-2);
stack.push_back(vch);
}
break;
case OP_PICK:
case OP_ROLL:
{
// (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
if (stack.size() < 2)
return false;
int n = CBigNum(stacktop(-1)).getint();
stack.pop_back();
if (n < 0 || n >= stack.size())
return false;
valtype vch = stacktop(-n-1);
if (opcode == OP_ROLL)
stack.erase(stack.end()-n-1);
stack.push_back(vch);
}
break;
case OP_ROT:
{
// (x1 x2 x3 -- x2 x3 x1)
// x2 x1 x3 after first swap
// x2 x3 x1 after second swap
if (stack.size() < 3)
return false;
swap(stacktop(-3), stacktop(-2));
swap(stacktop(-2), stacktop(-1));
}
break;
case OP_SWAP:
{
// (x1 x2 -- x2 x1)
if (stack.size() < 2)
return false;
swap(stacktop(-2), stacktop(-1));
}
break;
case OP_TUCK:
{
// (x1 x2 -- x2 x1 x2)
if (stack.size() < 2)
return false;
valtype vch = stacktop(-1);
stack.insert(stack.end()-2, vch);
}
break;
//
// Splice ops
//
case OP_CAT:
{
// (x1 x2 -- out)
if (stack.size() < 2)
return false;
valtype& vch1 = stacktop(-2);
valtype& vch2 = stacktop(-1);
vch1.insert(vch1.end(), vch2.begin(), vch2.end());
stack.pop_back();
}
break;
case OP_SUBSTR:
{
// (in begin size -- out)
if (stack.size() < 3)
return false;
valtype& vch = stacktop(-3);
int nBegin = CBigNum(stacktop(-2)).getint();
int nEnd = nBegin + CBigNum(stacktop(-1)).getint();
if (nBegin < 0 || nEnd < nBegin)
return false;
if (nBegin > vch.size())
nBegin = vch.size();
if (nEnd > vch.size())
nEnd = vch.size();
vch.erase(vch.begin() + nEnd, vch.end());
vch.erase(vch.begin(), vch.begin() + nBegin);
stack.pop_back();
stack.pop_back();
}
break;
case OP_LEFT:
case OP_RIGHT:
{
// (in size -- out)
if (stack.size() < 2)
return false;
valtype& vch = stacktop(-2);
int nSize = CBigNum(stacktop(-1)).getint();
if (nSize < 0)
return false;
if (nSize > vch.size())
nSize = vch.size();
if (opcode == OP_LEFT)
vch.erase(vch.begin() + nSize, vch.end());
else
vch.erase(vch.begin(), vch.end() - nSize);
stack.pop_back();
}
break;
case OP_SIZE:
{
// (in -- in size)
if (stack.size() < 1)
return false;
CBigNum bn(stacktop(-1).size());
stack.push_back(bn.getvch());
}
break;
//
// Bitwise logic
//
case OP_INVERT:
{
// (in - out)
if (stack.size() < 1)
return false;
valtype& vch = stacktop(-1);
for (int i = 0; i < vch.size(); i++)
vch[i] = ~vch[i];
}
break;
case OP_AND:
case OP_OR:
case OP_XOR:
{
// (x1 x2 - out)
if (stack.size() < 2)
return false;
valtype& vch1 = stacktop(-2);
valtype& vch2 = stacktop(-1);
MakeSameSize(vch1, vch2);
if (opcode == OP_AND)
{
for (int i = 0; i < vch1.size(); i++)
vch1[i] &= vch2[i];
}
else if (opcode == OP_OR)
{
for (int i = 0; i < vch1.size(); i++)
vch1[i] |= vch2[i];
}
else if (opcode == OP_XOR)
{
for (int i = 0; i < vch1.size(); i++)
vch1[i] ^= vch2[i];
}
stack.pop_back();
}
break;
case OP_EQUAL:
case OP_EQUALVERIFY:
//case OP_NOTEQUAL: // use OP_NUMNOTEQUAL
{
// (x1 x2 - bool)
if (stack.size() < 2)
return false;
valtype& vch1 = stacktop(-2);
valtype& vch2 = stacktop(-1);
bool fEqual = (vch1 == vch2);
// OP_NOTEQUAL is disabled because it would be too easy to say
// something like n != 1 and have some wiseguy pass in 1 with extra
// zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
//if (opcode == OP_NOTEQUAL)
// fEqual = !fEqual;
stack.pop_back();
stack.pop_back();
stack.push_back(fEqual ? vchTrue : vchFalse);
if (opcode == OP_EQUALVERIFY)
{
if (fEqual)
stack.pop_back();
else
pc = pend;
}
}
break;
//
// Numeric
//
case OP_1ADD:
case OP_1SUB:
case OP_2MUL:
case OP_2DIV:
case OP_NEGATE:
case OP_ABS:
case OP_NOT:
case OP_0NOTEQUAL:
{
// (in -- out)
if (stack.size() < 1)
return false;
CBigNum bn(stacktop(-1));
switch (opcode)
{
case OP_1ADD: bn += bnOne; break;
case OP_1SUB: bn -= bnOne; break;
case OP_2MUL: bn <<= 1; break;
case OP_2DIV: bn >>= 1; break;
case OP_NEGATE: bn = -bn; break;
case OP_ABS: if (bn < bnZero) bn = -bn; break;
case OP_NOT: bn = (bn == bnZero); break;
case OP_0NOTEQUAL: bn = (bn != bnZero); break;
}
stack.pop_back();
stack.push_back(bn.getvch());
}
break;
case OP_ADD:
case OP_SUB:
case OP_MUL:
case OP_DIV:
case OP_MOD:
case OP_LSHIFT:
case OP_RSHIFT:
case OP_BOOLAND:
case OP_BOOLOR:
case OP_NUMEQUAL:
case OP_NUMEQUALVERIFY:
case OP_NUMNOTEQUAL:
case OP_LESSTHAN:
case OP_GREATERTHAN:
case OP_LESSTHANOREQUAL:
case OP_GREATERTHANOREQUAL:
case OP_MIN:
case OP_MAX:
{
// (x1 x2 -- out)
if (stack.size() < 2)
return false;
CBigNum bn1(stacktop(-2));
CBigNum bn2(stacktop(-1));
CBigNum bn;
switch (opcode)
{
case OP_ADD:
bn = bn1 + bn2;
break;
case OP_SUB:
bn = bn1 - bn2;
break;
case OP_MUL:
if (!BN_mul(&bn, &bn1, &bn2, pctx))
return false;
break;
case OP_DIV:
if (!BN_div(&bn, NULL, &bn1, &bn2, pctx))
return false;
break;
case OP_MOD:
if (!BN_mod(&bn, &bn1, &bn2, pctx))
return false;
break;
case OP_LSHIFT:
if (bn2 < bnZero)
return false;
bn = bn1 << bn2.getulong();
break;
case OP_RSHIFT:
if (bn2 < bnZero)
return false;
bn = bn1 >> bn2.getulong();
break;
case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break;
case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break;
case OP_NUMEQUAL: bn = (bn1 == bn2); break;
case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break;
case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break;
case OP_LESSTHAN: bn = (bn1 < bn2); break;
case OP_GREATERTHAN: bn = (bn1 > bn2); break;
case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break;
case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;
case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;
}
stack.pop_back();
stack.pop_back();
stack.push_back(bn.getvch());
if (opcode == OP_NUMEQUALVERIFY)
{
if (CastToBool(stacktop(-1)))
stack.pop_back();
else
pc = pend;
}
}
break;
case OP_WITHIN:
{
// (x min max -- out)
if (stack.size() < 3)
return false;
CBigNum bn1(stacktop(-3));
CBigNum bn2(stacktop(-2));
CBigNum bn3(stacktop(-1));
bool fValue = (bn2 <= bn1 && bn1 < bn3);
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(fValue ? vchTrue : vchFalse);
}
break;
//
// Crypto
//
case OP_RIPEMD160:
case OP_SHA1:
case OP_SHA256:
case OP_HASH160:
case OP_HASH256:
{
// (in -- hash)
if (stack.size() < 1)
return false;
valtype& vch = stacktop(-1);
valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
if (opcode == OP_RIPEMD160)
RIPEMD160(&vch[0], vch.size(), &vchHash[0]);
else if (opcode == OP_SHA1)
SHA1(&vch[0], vch.size(), &vchHash[0]);
else if (opcode == OP_SHA256)
SHA256(&vch[0], vch.size(), &vchHash[0]);
else if (opcode == OP_HASH160)
{
uint160 hash160 = Hash160(vch);
memcpy(&vchHash[0], &hash160, sizeof(hash160));
}
else if (opcode == OP_HASH256)
{
uint256 hash = Hash(vch.begin(), vch.end());
memcpy(&vchHash[0], &hash, sizeof(hash));
}
stack.pop_back();
stack.push_back(vchHash);
}
break;
case OP_CODESEPARATOR:
{
// Hash starts after the code separator
pbegincodehash = pc;
}
break;
case OP_CHECKSIG:
case OP_CHECKSIGVERIFY:
{
// (sig pubkey -- bool)
if (stack.size() < 2)
return false;
valtype& vchSig = stacktop(-2);
valtype& vchPubKey = stacktop(-1);
////// debug print
//PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n");
//PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n");
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
// Drop the signature, since there's no way for a signature to sign itself
scriptCode.FindAndDelete(CScript(vchSig));
bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType);
stack.pop_back();
stack.pop_back();
stack.push_back(fSuccess ? vchTrue : vchFalse);
if (opcode == OP_CHECKSIGVERIFY)
{
if (fSuccess)
stack.pop_back();
else
pc = pend;
}
}
break;
case OP_CHECKMULTISIG:
case OP_CHECKMULTISIGVERIFY:
{
// ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
int i = 1;
if (stack.size() < i)
return false;
int nKeysCount = CBigNum(stacktop(-i)).getint();
if (nKeysCount < 0)
return false;
int ikey = ++i;
i += nKeysCount;
if (stack.size() < i)
return false;
int nSigsCount = CBigNum(stacktop(-i)).getint();
if (nSigsCount < 0 || nSigsCount > nKeysCount)
return false;
int isig = ++i;
i += nSigsCount;
if (stack.size() < i)
return false;
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
// Drop the signatures, since there's no way for a signature to sign itself
for (int k = 0; k < nSigsCount; k++)
{
valtype& vchSig = stacktop(-isig-k);
scriptCode.FindAndDelete(CScript(vchSig));
}
bool fSuccess = true;
while (fSuccess && nSigsCount > 0)
{
valtype& vchSig = stacktop(-isig);
valtype& vchPubKey = stacktop(-ikey);
// Check signature
if (CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType))
{
isig++;
nSigsCount--;
}
ikey++;
nKeysCount--;
// If there are more signatures left than keys left,
// then too many signatures have failed
if (nSigsCount > nKeysCount)
fSuccess = false;
}
while (i-- > 0)
stack.pop_back();
stack.push_back(fSuccess ? vchTrue : vchFalse);
if (opcode == OP_CHECKMULTISIGVERIFY)
{
if (fSuccess)
stack.pop_back();
else
pc = pend;
}
}
break;
default:
return false;
}
}
if (pvStackRet)
*pvStackRet = stack;
return (stack.empty() ? false : CastToBool(stack.back()));
}
#undef top
uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
{
if (nIn >= txTo.vin.size())
{
printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
return 1;
}
CTransaction txTmp(txTo);
// In case concatenating two scripts ends up with two codeseparators,
// or an extra one at the end, this prevents all those possible incompatibilities.
scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
// Blank out other inputs' signatures
for (int i = 0; i < txTmp.vin.size(); i++)
txTmp.vin[i].scriptSig = CScript();
txTmp.vin[nIn].scriptSig = scriptCode;
// Blank out some of the outputs
if ((nHashType & 0x1f) == SIGHASH_NONE)
{
// Wildcard payee
txTmp.vout.clear();
// Let the others update at will
for (int i = 0; i < txTmp.vin.size(); i++)
if (i != nIn)
txTmp.vin[i].nSequence = 0;
}
else if ((nHashType & 0x1f) == SIGHASH_SINGLE)
{
// Only lockin the txout payee at same index as txin
unsigned int nOut = nIn;
if (nOut >= txTmp.vout.size())
{
printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut);
return 1;
}
txTmp.vout.resize(nOut+1);
for (int i = 0; i < nOut; i++)
txTmp.vout[i].SetNull();
// Let the others update at will
for (int i = 0; i < txTmp.vin.size(); i++)
if (i != nIn)
txTmp.vin[i].nSequence = 0;
}
// Blank out other inputs completely, not recommended for open transactions
if (nHashType & SIGHASH_ANYONECANPAY)
{
txTmp.vin[0] = txTmp.vin[nIn];
txTmp.vin.resize(1);
}
// Serialize and hash
CDataStream ss(SER_GETHASH);
ss.reserve(10000);
ss << txTmp << nHashType;
return Hash(ss.begin(), ss.end());
}
bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode,
const CTransaction& txTo, unsigned int nIn, int nHashType)
{
CKey key;
if (!key.SetPubKey(vchPubKey))
return false;
// Hash type is one byte tacked on to the end of the signature
if (vchSig.empty())
return false;
if (nHashType == 0)
nHashType = vchSig.back();
else if (nHashType != vchSig.back())
return false;
vchSig.pop_back();
if (key.Verify(SignatureHash(scriptCode, txTo, nIn, nHashType), vchSig))
return true;
return false;
}
bool Solver(const CScript& scriptPubKey, vector<pair<opcodetype, valtype> >& vSolutionRet)
{
// Templates
static vector<CScript> vTemplates;
if (vTemplates.empty())
{
// Standard tx, sender provides pubkey, receiver adds signature
vTemplates.push_back(CScript() << OP_PUBKEY << OP_CHECKSIG);
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
vTemplates.push_back(CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG);
}
// Scan templates
const CScript& script1 = scriptPubKey;
foreach(const CScript& script2, vTemplates)
{
vSolutionRet.clear();
opcodetype opcode1, opcode2;
vector<unsigned char> vch1, vch2;
// Compare
CScript::const_iterator pc1 = script1.begin();
CScript::const_iterator pc2 = script2.begin();
loop
{
bool f1 = script1.GetOp(pc1, opcode1, vch1);
bool f2 = script2.GetOp(pc2, opcode2, vch2);
if (!f1 && !f2)
{
// Success
reverse(vSolutionRet.begin(), vSolutionRet.end());
return true;
}
else if (f1 != f2)
{
break;
}
else if (opcode2 == OP_PUBKEY)
{
if (vch1.size() <= sizeof(uint256))
break;
vSolutionRet.push_back(make_pair(opcode2, vch1));
}
else if (opcode2 == OP_PUBKEYHASH)
{
if (vch1.size() != sizeof(uint160))
break;
vSolutionRet.push_back(make_pair(opcode2, vch1));
}
else if (opcode1 != opcode2)
{
break;
}
}
}
vSolutionRet.clear();
return false;
}
bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet)
{
scriptSigRet.clear();
vector<pair<opcodetype, valtype> > vSolution;
if (!Solver(scriptPubKey, vSolution))
return false;
// Compile solution
CRITICAL_BLOCK(cs_mapKeys)
{
foreach(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
if (item.first == OP_PUBKEY)
{
// Sign
const valtype& vchPubKey = item.second;
if (!mapKeys.count(vchPubKey))
return false;
if (hash != 0)
{
vector<unsigned char> vchSig;
if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig;
}
}
else if (item.first == OP_PUBKEYHASH)
{
// Sign and give pubkey
map<uint160, valtype>::iterator mi = mapPubKeys.find(uint160(item.second));
if (mi == mapPubKeys.end())
return false;
const vector<unsigned char>& vchPubKey = (*mi).second;
if (!mapKeys.count(vchPubKey))
return false;
if (hash != 0)
{
vector<unsigned char> vchSig;
if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig << vchPubKey;
}
}
}
}
return true;
}
bool IsMine(const CScript& scriptPubKey)
{
CScript scriptSig;
return Solver(scriptPubKey, 0, 0, scriptSig);
}
bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned char>& vchPubKeyRet)
{
vchPubKeyRet.clear();
vector<pair<opcodetype, valtype> > vSolution;
if (!Solver(scriptPubKey, vSolution))
return false;
CRITICAL_BLOCK(cs_mapKeys)
{
foreach(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
valtype vchPubKey;
if (item.first == OP_PUBKEY)
{
vchPubKey = item.second;
}
else if (item.first == OP_PUBKEYHASH)
{
map<uint160, valtype>::iterator mi = mapPubKeys.find(uint160(item.second));
if (mi == mapPubKeys.end())
continue;
vchPubKey = (*mi).second;
}
if (!fMineOnly || mapKeys.count(vchPubKey))
{
vchPubKeyRet = vchPubKey;
return true;
}
}
}
return false;
}
bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret)
{
hash160Ret = 0;
vector<pair<opcodetype, valtype> > vSolution;
if (!Solver(scriptPubKey, vSolution))
return false;
foreach(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
if (item.first == OP_PUBKEYHASH)
{
hash160Ret = uint160(item.second);
return true;
}
}
return false;
}
bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq)
{
assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn];
assert(txin.prevout.n < txFrom.vout.size());
const CTxOut& txout = txFrom.vout[txin.prevout.n];
// Leave out the signature from the hash, since a signature can't sign itself.
// The checksig op will also drop the signatures from its hash.
uint256 hash = SignatureHash(scriptPrereq + txout.scriptPubKey, txTo, nIn, nHashType);
if (!Solver(txout.scriptPubKey, hash, nHashType, txin.scriptSig))
return false;
txin.scriptSig = scriptPrereq + txin.scriptSig;
// Test solution
if (scriptPrereq.empty())
if (!EvalScript(txin.scriptSig + CScript(OP_CODESEPARATOR) + txout.scriptPubKey, txTo, nIn))
return false;
return true;
}
bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType)
{
assert(nIn < txTo.vin.size());
const CTxIn& txin = txTo.vin[nIn];
if (txin.prevout.n >= txFrom.vout.size())
return false;
const CTxOut& txout = txFrom.vout[txin.prevout.n];
if (txin.prevout.hash != txFrom.GetHash())
return false;
if (!EvalScript(txin.scriptSig + CScript(OP_CODESEPARATOR) + txout.scriptPubKey, txTo, nIn, nHashType))
return false;
// Anytime a signature is successfully verified, it's proof the outpoint is spent,
// so lets update the wallet spent flag if it doesn't know due to wallet.dat being
// restored from backup or the user making copies of wallet.dat.
WalletUpdateSpent(txin.prevout);
return true;
}
"%file: ./serialize.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 <vector>
#include <map>
#include <boost/type_traits/is_fundamental.hpp>
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 int64;
typedef unsigned __int64 uint64;
#else
typedef long long int64;
typedef unsigned long long uint64;
#endif
#if defined(_MSC_VER) && _MSC_VER < 1300
#define for if (false) ; else for
#endif
class CScript;
class CDataStream;
class CAutoFile;
static const int VERSION = 212;
static const char* pszSubVer = "";
/////////////////////////////////////////////////////////////////
//
// Templates for serializing to anything that looks like a stream,
// i.e. anything that supports .read(char*, int) and .write(char*, int)
//
enum
{
// primary actions
SER_NETWORK = (1 << 0),
SER_DISK = (1 << 1),
SER_GETHASH = (1 << 2),
// modifiers
SER_SKIPSIG = (1 << 16),
SER_BLOCKHEADERONLY = (1 << 17),
};
#define IMPLEMENT_SERIALIZE(statements) \
unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const \
{ \
CSerActionGetSerializeSize ser_action; \
const bool fGetSize = true; \
const bool fWrite = false; \
const bool fRead = false; \
unsigned int nSerSize = 0; \
ser_streamplaceholder s; \
s.nType = nType; \
s.nVersion = nVersion; \
{statements} \
return nSerSize; \
} \
template<typename Stream> \
void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const \
{ \
CSerActionSerialize ser_action; \
const bool fGetSize = false; \
const bool fWrite = true; \
const bool fRead = false; \
unsigned int nSerSize = 0; \
{statements} \
} \
template<typename Stream> \
void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) \
{ \
CSerActionUnserialize ser_action; \
const bool fGetSize = false; \
const bool fWrite = false; \
const bool fRead = true; \
unsigned int nSerSize = 0; \
{statements} \
}
#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))
//
// Basic types
//
#define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj))
#define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj))
inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); }
inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); }
template<typename Stream> inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); }
template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); }
inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); }
template<typename Stream> inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); }
template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; }
//
// Compact size
// size < 253 -- 1 byte
// size <= USHRT_MAX -- 3 bytes (253 + 2 bytes)
// size <= UINT_MAX -- 5 bytes (254 + 4 bytes)
// size > UINT_MAX -- 9 bytes (255 + 8 bytes)
//
inline unsigned int GetSizeOfCompactSize(uint64 nSize)
{
if (nSize < UCHAR_MAX-2) return sizeof(unsigned char);
else if (nSize <= USHRT_MAX) return sizeof(unsigned char) + sizeof(unsigned short);
else if (nSize <= UINT_MAX) return sizeof(unsigned char) + sizeof(unsigned int);
else return sizeof(unsigned char) + sizeof(uint64);
}
template<typename Stream>
void WriteCompactSize(Stream& os, uint64 nSize)
{
if (nSize < UCHAR_MAX-2)
{
unsigned char chSize = nSize;
WRITEDATA(os, chSize);
}
else if (nSize <= USHRT_MAX)
{
unsigned char chSize = UCHAR_MAX-2;
unsigned short xSize = nSize;
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
}
else if (nSize <= UINT_MAX)
{
unsigned char chSize = UCHAR_MAX-1;
unsigned int xSize = nSize;
WRITEDATA(os, chSize);
WRITEDATA(os, xSize);
}
else
{
unsigned char chSize = UCHAR_MAX;
WRITEDATA(os, chSize);
WRITEDATA(os, nSize);
}
return;
}
template<typename Stream>
uint64 ReadCompactSize(Stream& is)
{
unsigned char chSize;
READDATA(is, chSize);
uint64 nSizeRet = 0;
if (chSize < UCHAR_MAX-2)
{
nSizeRet = chSize;
}
else if (chSize == UCHAR_MAX-2)
{
unsigned short nSize;
READDATA(is, nSize);
nSizeRet = nSize;
}
else if (chSize == UCHAR_MAX-1)
{
unsigned int nSize;
READDATA(is, nSize);
nSizeRet = nSize;
}
else
{
uint64 nSize;
READDATA(is, nSize);
nSizeRet = nSize;
}
if (nSizeRet > (uint64)INT_MAX)
throw std::ios_base::failure("ReadCompactSize() : size too large");
return nSizeRet;
}
//
// Wrapper for serializing arrays and POD
// There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it
//
#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
class CFlatData
{
protected:
char* pbegin;
char* pend;
public:
CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { }
char* begin() { return pbegin; }
const char* begin() const { return pbegin; }
char* end() { return pend; }
const char* end() const { return pend; }
unsigned int GetSerializeSize(int, int=0) const
{
return pend - pbegin;
}
template<typename Stream>
void Serialize(Stream& s, int, int=0) const
{
s.write(pbegin, pend - pbegin);
}
template<typename Stream>
void Unserialize(Stream& s, int, int=0)
{
s.read(pbegin, pend - pbegin);
}
};
//
// string stored as a fixed length field
//
template<std::size_t LEN>
class CFixedFieldString
{
protected:
const string* pcstr;
string* pstr;
public:
explicit CFixedFieldString(const string& str) : pcstr(&str), pstr(NULL) { }
explicit CFixedFieldString(string& str) : pcstr(&str), pstr(&str) { }
unsigned int GetSerializeSize(int, int=0) const
{
return LEN;
}
template<typename Stream>
void Serialize(Stream& s, int, int=0) const
{
char pszBuf[LEN];
strncpy(pszBuf, pcstr->c_str(), LEN);
s.write(pszBuf, LEN);
}
template<typename Stream>
void Unserialize(Stream& s, int, int=0)
{
if (pstr == NULL)
throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string");
char pszBuf[LEN+1];
s.read(pszBuf, LEN);
pszBuf[LEN] = '\0';
*pstr = pszBuf;
}
};
//
// Forward declarations
//
// string
template<typename C> unsigned int GetSerializeSize(const basic_string<C>& str, int, int=0);
template<typename Stream, typename C> void Serialize(Stream& os, const basic_string<C>& str, int, int=0);
template<typename Stream, typename C> void Unserialize(Stream& is, basic_string<C>& str, int, int=0);
// vector
template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion=VERSION);
template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion=VERSION);
template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&);
template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&);
template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion=VERSION);
// others derived from vector
extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion=VERSION);
template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion=VERSION);
template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion=VERSION);
// pair
template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion=VERSION);
template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion=VERSION);
template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion=VERSION);
// map
template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion=VERSION);
template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion=VERSION);
template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion=VERSION);
// set
template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion=VERSION);
template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion=VERSION);
template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion=VERSION);
//
// If none of the specialized versions above matched, default to calling member function.
// "int nType" is changed to "long nType" to keep from getting an ambiguous overload error.
// The compiler will only cast int to long if none of the other templates matched.
// Thanks to Boost serialization for this idea.
//
template<typename T>
inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion=VERSION)
{
return a.GetSerializeSize((int)nType, nVersion);
}
template<typename Stream, typename T>
inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION)
{
a.Serialize(os, (int)nType, nVersion);
}
template<typename Stream, typename T>
inline void Unserialize(Stream& is, T& a, long nType, int nVersion=VERSION)
{
a.Unserialize(is, (int)nType, nVersion);
}
//
// string
//
template<typename C>
unsigned int GetSerializeSize(const basic_string<C>& str, int, int)
{
return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]);
}
template<typename Stream, typename C>
void Serialize(Stream& os, const basic_string<C>& str, int, int)
{
WriteCompactSize(os, str.size());
if (!str.empty())
os.write((char*)&str[0], str.size() * sizeof(str[0]));
}
template<typename Stream, typename C>
void Unserialize(Stream& is, basic_string<C>& str, int, int)
{
unsigned int nSize = ReadCompactSize(is);
str.resize(nSize);
if (nSize != 0)
is.read((char*)&str[0], nSize * sizeof(str[0]));
}
//
// vector
//
template<typename T, typename A>
unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
{
return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T));
}
template<typename T, typename A>
unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
{
unsigned int nSize = GetSizeOfCompactSize(v.size());
for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
nSize += GetSerializeSize((*vi), nType, nVersion);
return nSize;
}
template<typename T, typename A>
inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion)
{
return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental<T>());
}
template<typename Stream, typename T, typename A>
void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
{
WriteCompactSize(os, v.size());
if (!v.empty())
os.write((char*)&v[0], v.size() * sizeof(T));
}
template<typename Stream, typename T, typename A>
void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
{
WriteCompactSize(os, v.size());
for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi)
::Serialize(os, (*vi), nType, nVersion);
}
template<typename Stream, typename T, typename A>
inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion)
{
Serialize_impl(os, v, nType, nVersion, boost::is_fundamental<T>());
}
template<typename Stream, typename T, typename A>
void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&)
{
//unsigned int nSize = ReadCompactSize(is);
//v.resize(nSize);
//is.read((char*)&v[0], nSize * sizeof(T));
// Limit size per read so bogus size value won't cause out of memory
v.clear();
unsigned int nSize = ReadCompactSize(is);
unsigned int i = 0;
while (i < nSize)
{
unsigned int blk = min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
v.resize(i + blk);
is.read((char*)&v[i], blk * sizeof(T));
i += blk;
}
}
template<typename Stream, typename T, typename A>
void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&)
{
//unsigned int nSize = ReadCompactSize(is);
//v.resize(nSize);
//for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi)
// Unserialize(is, (*vi), nType, nVersion);
v.clear();
unsigned int nSize = ReadCompactSize(is);
unsigned int i = 0;
unsigned int nMid = 0;
while (nMid < nSize)
{
nMid += 5000000 / sizeof(T);
if (nMid > nSize)
nMid = nSize;
v.resize(nMid);
for (; i < nMid; i++)
Unserialize(is, v[i], nType, nVersion);
}
}
template<typename Stream, typename T, typename A>
inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion)
{
Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental<T>());
}
//
// others derived from vector
//
inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion)
{
return GetSerializeSize((const vector<unsigned char>&)v, nType, nVersion);
}
template<typename Stream>
void Serialize(Stream& os, const CScript& v, int nType, int nVersion)
{
Serialize(os, (const vector<unsigned char>&)v, nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream& is, CScript& v, int nType, int nVersion)
{
Unserialize(is, (vector<unsigned char>&)v, nType, nVersion);
}
//
// pair
//
template<typename K, typename T>
unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion)
{
return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion);
}
template<typename Stream, typename K, typename T>
void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion)
{
Serialize(os, item.first, nType, nVersion);
Serialize(os, item.second, nType, nVersion);
}
template<typename Stream, typename K, typename T>
void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion)
{
Unserialize(is, item.first, nType, nVersion);
Unserialize(is, item.second, nType, nVersion);
}
//
// map
//
template<typename K, typename T, typename Pred, typename A>
unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion)
{
unsigned int nSize = GetSizeOfCompactSize(m.size());
for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
nSize += GetSerializeSize((*mi), nType, nVersion);
return nSize;
}
template<typename Stream, typename K, typename T, typename Pred, typename A>
void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion)
{
WriteCompactSize(os, m.size());
for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
Serialize(os, (*mi), nType, nVersion);
}
template<typename Stream, typename K, typename T, typename Pred, typename A>
void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion)
{
m.clear();
unsigned int nSize = ReadCompactSize(is);
typename std::map<K, T, Pred, A>::iterator mi = m.begin();
for (unsigned int i = 0; i < nSize; i++)
{
pair<K, T> item;
Unserialize(is, item, nType, nVersion);
mi = m.insert(mi, item);
}
}
//
// set
//
template<typename K, typename Pred, typename A>
unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion)
{
unsigned int nSize = GetSizeOfCompactSize(m.size());
for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
nSize += GetSerializeSize((*it), nType, nVersion);
return nSize;
}
template<typename Stream, typename K, typename Pred, typename A>
void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion)
{
WriteCompactSize(os, m.size());
for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it)
Serialize(os, (*it), nType, nVersion);
}
template<typename Stream, typename K, typename Pred, typename A>
void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion)
{
m.clear();
unsigned int nSize = ReadCompactSize(is);
typename std::set<K, Pred, A>::iterator it = m.begin();
for (unsigned int i = 0; i < nSize; i++)
{
K key;
Unserialize(is, key, nType, nVersion);
it = m.insert(it, key);
}
}
//
// Support for IMPLEMENT_SERIALIZE and READWRITE macro
//
class CSerActionGetSerializeSize { };
class CSerActionSerialize { };
class CSerActionUnserialize { };
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action)
{
return ::GetSerializeSize(obj, nType, nVersion);
}
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action)
{
::Serialize(s, obj, nType, nVersion);
return 0;
}
template<typename Stream, typename T>
inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action)
{
::Unserialize(s, obj, nType, nVersion);
return 0;
}
struct ser_streamplaceholder
{
int nType;
int nVersion;
};
//
// Allocator that clears its contents before deletion
//
template<typename T>
struct secure_allocator : public std::allocator<T>
{
// MSVC8 default copy constructor is broken
typedef std::allocator<T> base;
typedef typename base::size_type size_type;
typedef typename base::difference_type difference_type;
typedef typename base::pointer pointer;
typedef typename base::const_pointer const_pointer;
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
secure_allocator() throw() {}
secure_allocator(const secure_allocator& a) throw() : base(a) {}
~secure_allocator() throw() {}
template<typename _Other> struct rebind
{ typedef secure_allocator<_Other> other; };
void deallocate(T* p, std::size_t n)
{
if (p != NULL)
memset(p, 0, sizeof(T) * n);
allocator<T>::deallocate(p, n);
}
};
//
// Double ended buffer combining vector and stream-like interfaces.
// >> and << read and write unformatted data using the above serialization templates.
// Fills with data in linear time; some stringstream implementations take N^2 time.
//
class CDataStream
{
protected:
typedef vector<char, secure_allocator<char> > vector_type;
vector_type vch;
unsigned int nReadPos;
short state;
short exceptmask;
public:
int nType;
int nVersion;
typedef vector_type::allocator_type allocator_type;
typedef vector_type::size_type size_type;
typedef vector_type::difference_type difference_type;
typedef vector_type::reference reference;
typedef vector_type::const_reference const_reference;
typedef vector_type::value_type value_type;
typedef vector_type::iterator iterator;
typedef vector_type::const_iterator const_iterator;
typedef vector_type::reverse_iterator reverse_iterator;
explicit CDataStream(int nTypeIn=0, int nVersionIn=VERSION)
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1300
CDataStream(const char* pbegin, const char* pend, int nTypeIn=0, int nVersionIn=VERSION) : vch(pbegin, pend)
{
Init(nTypeIn, nVersionIn);
}
#endif
CDataStream(const vector_type& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end())
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const vector<char>& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch(vchIn.begin(), vchIn.end())
{
Init(nTypeIn, nVersionIn);
}
CDataStream(const vector<unsigned char>& vchIn, int nTypeIn=0, int nVersionIn=VERSION) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0])
{
Init(nTypeIn, nVersionIn);
}
void Init(int nTypeIn=0, int nVersionIn=VERSION)
{
nReadPos = 0;
nType = nTypeIn;
nVersion = nVersionIn;
state = 0;
exceptmask = ios::badbit | ios::failbit;
}
CDataStream& operator+=(const CDataStream& b)
{
vch.insert(vch.end(), b.begin(), b.end());
return *this;
}
friend CDataStream operator+(const CDataStream& a, const CDataStream& b)
{
CDataStream ret = a;
ret += b;
return (ret);
}
string str() const
{
return (string(begin(), end()));
}
//
// Vector subset
//
const_iterator begin() const { return vch.begin() + nReadPos; }
iterator begin() { return vch.begin() + nReadPos; }
const_iterator end() const { return vch.end(); }
iterator end() { return vch.end(); }
size_type size() const { return vch.size() - nReadPos; }
bool empty() const { return vch.size() == nReadPos; }
void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
void reserve(size_type n) { vch.reserve(n + nReadPos); }
const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
reference operator[](size_type pos) { return vch[pos + nReadPos]; }
void clear() { vch.clear(); nReadPos = 0; }
iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); }
void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); }
void insert(iterator it, const_iterator first, const_iterator last)
{
if (it == vch.begin() + nReadPos && last - first <= nReadPos)
{
// special case for inserting at the front when there's room
nReadPos -= (last - first);
memcpy(&vch[nReadPos], &first[0], last - first);
}
else
vch.insert(it, first, last);
}
void insert(iterator it, vector<char>::const_iterator first, vector<char>::const_iterator last)
{
if (it == vch.begin() + nReadPos && last - first <= nReadPos)
{
// special case for inserting at the front when there's room
nReadPos -= (last - first);
memcpy(&vch[nReadPos], &first[0], last - first);
}
else
vch.insert(it, first, last);
}
#if !defined(_MSC_VER) || _MSC_VER >= 1300
void insert(iterator it, const char* first, const char* last)
{
if (it == vch.begin() + nReadPos && last - first <= nReadPos)
{
// special case for inserting at the front when there's room
nReadPos -= (last - first);
memcpy(&vch[nReadPos], &first[0], last - first);
}
else
vch.insert(it, first, last);
}
#endif
iterator erase(iterator it)
{
if (it == vch.begin() + nReadPos)
{
// special case for erasing from the front
if (++nReadPos >= vch.size())
{
// whenever we reach the end, we take the opportunity to clear the buffer
nReadPos = 0;
return vch.erase(vch.begin(), vch.end());
}
return vch.begin() + nReadPos;
}
else
return vch.erase(it);
}
iterator erase(iterator first, iterator last)
{
if (first == vch.begin() + nReadPos)
{
// special case for erasing from the front
if (last == vch.end())
{
nReadPos = 0;
return vch.erase(vch.begin(), vch.end());
}
else
{
nReadPos = (last - vch.begin());
return last;
}
}
else
return vch.erase(first, last);
}
inline void Compact()
{
vch.erase(vch.begin(), vch.begin() + nReadPos);
nReadPos = 0;
}
bool Rewind(size_type n)
{
// Rewind by n characters if the buffer hasn't been compacted yet
if (n > nReadPos)
return false;
nReadPos -= n;
return true;
}
//
// Stream subset
//
void setstate(short bits, const char* psz)
{
state |= bits;
if (state & exceptmask)
throw std::ios_base::failure(psz);
}
bool eof() const { return size() == 0; }
bool fail() const { return state & (ios::badbit | ios::failbit); }
bool good() const { return !eof() && (state == 0); }
void clear(short n) { state = n; } // name conflict with vector clear()
short exceptions() { return exceptmask; }
short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; }
CDataStream* rdbuf() { return this; }
int in_avail() { return size(); }
void SetType(int n) { nType = n; }
int GetType() { return nType; }
void SetVersion(int n) { nVersion = n; }
int GetVersion() { return nVersion; }
void ReadVersion() { *this >> nVersion; }
void WriteVersion() { *this << nVersion; }
CDataStream& read(char* pch, int nSize)
{
// Read from the beginning of the buffer
assert(nSize >= 0);
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
{
if (nReadPosNext > vch.size())
{
setstate(ios::failbit, "CDataStream::read() : end of data");
memset(pch, 0, nSize);
nSize = vch.size() - nReadPos;
}
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = 0;
vch.clear();
return (*this);
}
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = nReadPosNext;
return (*this);
}
CDataStream& ignore(int nSize)
{
// Ignore from the beginning of the buffer
assert(nSize >= 0);
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
{
if (nReadPosNext > vch.size())
{
setstate(ios::failbit, "CDataStream::ignore() : end of data");
nSize = vch.size() - nReadPos;
}
nReadPos = 0;
vch.clear();
return (*this);
}
nReadPos = nReadPosNext;
return (*this);
}
CDataStream& write(const char* pch, int nSize)
{
// Write to the end of the buffer
assert(nSize >= 0);
vch.insert(vch.end(), pch, pch + nSize);
return (*this);
}
template<typename Stream>
void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
{
// Special case: stream << stream concatenates like stream += stream
if (!vch.empty())
s.write((char*)&vch[0], vch.size() * sizeof(vch[0]));
}
template<typename T>
unsigned int GetSerializeSize(const T& obj)
{
// Tells the size of the object if serialized to this stream
return ::GetSerializeSize(obj, nType, nVersion);
}
template<typename T>
CDataStream& operator<<(const T& obj)
{
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
template<typename T>
CDataStream& operator>>(T& obj)
{
// Unserialize from this stream
::Unserialize(*this, obj, nType, nVersion);
return (*this);
}
};
#ifdef TESTCDATASTREAM
// VC6sp6
// CDataStream:
// n=1000 0 seconds
// n=2000 0 seconds
// n=4000 0 seconds
// n=8000 0 seconds
// n=16000 0 seconds
// n=32000 0 seconds
// n=64000 1 seconds
// n=128000 1 seconds
// n=256000 2 seconds
// n=512000 4 seconds
// n=1024000 8 seconds
// n=2048000 16 seconds
// n=4096000 32 seconds
// stringstream:
// n=1000 1 seconds
// n=2000 1 seconds
// n=4000 13 seconds
// n=8000 87 seconds
// n=16000 400 seconds
// n=32000 1660 seconds
// n=64000 6749 seconds
// n=128000 27241 seconds
// n=256000 109804 seconds
#include <iostream>
int main(int argc, char *argv[])
{
vector<unsigned char> vch(0xcc, 250);
printf("CDataStream:\n");
for (int n = 1000; n <= 4500000; n *= 2)
{
CDataStream ss;
time_t nStart = time(NULL);
for (int i = 0; i < n; i++)
ss.write((char*)&vch[0], vch.size());
printf("n=%-10d %d seconds\n", n, time(NULL) - nStart);
}
printf("stringstream:\n");
for (int n = 1000; n <= 4500000; n *= 2)
{
stringstream ss;
time_t nStart = time(NULL);
for (int i = 0; i < n; i++)
ss.write((char*)&vch[0], vch.size());
printf("n=%-10d %d seconds\n", n, time(NULL) - nStart);
}
}
#endif
//
// Automatic closing wrapper for FILE*
// - Will automatically close the file when it goes out of scope if not null.
// - If you're returning the file pointer, return file.release().
// - If you need to close the file early, use file.fclose() instead of fclose(file).
//
class CAutoFile
{
protected:
FILE* file;
short state;
short exceptmask;
public:
int nType;
int nVersion;
typedef FILE element_type;
CAutoFile(FILE* filenew=NULL, int nTypeIn=SER_DISK, int nVersionIn=VERSION)
{
file = filenew;
nType = nTypeIn;
nVersion = nVersionIn;
state = 0;
exceptmask = ios::badbit | ios::failbit;
}
~CAutoFile()
{
fclose();
}
void fclose()
{
if (file != NULL && file != stdin && file != stdout && file != stderr)
::fclose(file);
file = NULL;
}
FILE* release() { FILE* ret = file; file = NULL; return ret; }
operator FILE*() { return file; }
FILE* operator->() { return file; }
FILE& operator*() { return *file; }
FILE** operator&() { return &file; }
FILE* operator=(FILE* pnew) { return file = pnew; }
bool operator!() { return (file == NULL); }
//
// Stream subset
//
void setstate(short bits, const char* psz)
{
state |= bits;
if (state & exceptmask)
throw std::ios_base::failure(psz);
}
bool fail() const { return state & (ios::badbit | ios::failbit); }
bool good() const { return state == 0; }
void clear(short n = 0) { state = n; }
short exceptions() { return exceptmask; }
short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; }
void SetType(int n) { nType = n; }
int GetType() { return nType; }
void SetVersion(int n) { nVersion = n; }
int GetVersion() { return nVersion; }
void ReadVersion() { *this >> nVersion; }
void WriteVersion() { *this << nVersion; }
CAutoFile& read(char* pch, int nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
if (fread(pch, 1, nSize, file) != nSize)
setstate(ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
return (*this);
}
CAutoFile& write(const char* pch, int nSize)
{
if (!file)
throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
if (fwrite(pch, 1, nSize, file) != nSize)
setstate(ios::failbit, "CAutoFile::write : write failed");
return (*this);
}
template<typename T>
unsigned int GetSerializeSize(const T& obj)
{
// Tells the size of the object if serialized to this stream
return ::GetSerializeSize(obj, nType, nVersion);
}
template<typename T>
CAutoFile& operator<<(const T& obj)
{
// Serialize to this stream
if (!file)
throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL");
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
template<typename T>
CAutoFile& operator>>(T& obj)
{
// Unserialize from this stream
if (!file)
throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL");
::Unserialize(*this, obj, nType, nVersion);
return (*this);
}
};
"%file: ./setup.nsi"
# Auto-generated by EclipseNSIS Script Wizard
# 3.10.2009 19:00:28
Name Bitcoin
RequestExecutionLevel highest
# General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.2.0
!define COMPANY "Bitcoin project"
!define URL http://www.bitcoin.org/
# MUI Symbol Definitions
!define MUI_ICON "src\rc\bitcoin.ico"
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM
!define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY}
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup
!define MUI_STARTMENUPAGE_DEFAULTFOLDER Bitcoin
!define MUI_FINISHPAGE_RUN $INSTDIR\bitcoin.exe
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
# Included files
!include Sections.nsh
!include MUI2.nsh
# Variables
Var StartMenuGroup
# Installer pages
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_STARTMENU Application $StartMenuGroup
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
# Installer languages
!insertmacro MUI_LANGUAGE English
# Installer attributes
OutFile bitcoin-0.2.0-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on
XPStyle on
ShowInstDetails show
VIProductVersion 0.2.0.0
VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"
VIAddVersionKey CompanyWebsite "${URL}"
VIAddVersionKey FileVersion "${VERSION}"
VIAddVersionKey FileDescription ""
VIAddVersionKey LegalCopyright ""
InstallDirRegKey HKCU "${REGKEY}" Path
ShowUninstDetails show
# Installer sections
Section -Main SEC0000
SetOutPath $INSTDIR
SetOverwrite on
File bitcoin.exe
File libeay32.dll
File mingwm10.dll
File license.txt
File readme.txt
SetOutPath $INSTDIR\src
File /r src\*.*
SetOutPath $INSTDIR
WriteRegStr HKCU "${REGKEY}\Components" Main 1
SectionEnd
Section -post SEC0001
WriteRegStr HKCU "${REGKEY}" Path $INSTDIR
SetOutPath $INSTDIR
WriteUninstaller $INSTDIR\uninstall.exe
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
CreateDirectory $SMPROGRAMS\$StartMenuGroup
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Bitcoin.lnk" $INSTDIR\bitcoin.exe
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall Bitcoin.lnk" $INSTDIR\uninstall.exe
!insertmacro MUI_STARTMENU_WRITE_END
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "${COMPANY}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\uninstall.exe
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe
WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1
WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1
SectionEnd
# Macro for selecting uninstaller sections
!macro SELECT_UNSECTION SECTION_NAME UNSECTION_ID
Push $R0
ReadRegStr $R0 HKCU "${REGKEY}\Components" "${SECTION_NAME}"
StrCmp $R0 1 0 next${UNSECTION_ID}
!insertmacro SelectSection "${UNSECTION_ID}"
GoTo done${UNSECTION_ID}
next${UNSECTION_ID}:
!insertmacro UnselectSection "${UNSECTION_ID}"
done${UNSECTION_ID}:
Pop $R0
!macroend
# Uninstaller sections
Section /o -un.Main UNSEC0000
Delete /REBOOTOK $INSTDIR\bitcoin.exe
Delete /REBOOTOK $INSTDIR\libeay32.dll
Delete /REBOOTOK $INSTDIR\mingwm10.dll
Delete /REBOOTOK $INSTDIR\license.txt
Delete /REBOOTOK $INSTDIR\readme.txt
RMDir /r /REBOOTOK $INSTDIR\src
DeleteRegValue HKCU "${REGKEY}\Components" Main
SectionEnd
Section -un.post UNSEC0001
DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall Bitcoin.lnk"
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Bitcoin.lnk"
Delete /REBOOTOK "$SMSTARTUP\Bitcoin.lnk"
Delete /REBOOTOK $INSTDIR\uninstall.exe
Delete /REBOOTOK $INSTDIR\debug.log
Delete /REBOOTOK $INSTDIR\db.log
DeleteRegValue HKCU "${REGKEY}" StartMenuGroup
DeleteRegValue HKCU "${REGKEY}" Path
DeleteRegKey /IfEmpty HKCU "${REGKEY}\Components"
DeleteRegKey /IfEmpty HKCU "${REGKEY}"
RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup
RmDir /REBOOTOK $INSTDIR
Push $R0
StrCpy $R0 $StartMenuGroup 1
StrCmp $R0 ">" no_smgroup
no_smgroup:
Pop $R0
SectionEnd
# Installer functions
Function .onInit
InitPluginsDir
FunctionEnd
# Uninstaller functions
Function un.onInit
ReadRegStr $INSTDIR HKCU "${REGKEY}" Path
!insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup
!insertmacro SELECT_UNSECTION Main ${UNSEC0000}
FunctionEnd
"%file: ./sha.h"
// This file is public domain
// SHA routines extracted as a standalone file from:
// Crypto++: a C++ Class Library of Cryptographic Schemes
// Version 5.5.2 (9/24/2007)
// http://www.cryptopp.com
#ifndef CRYPTOPP_SHA_H
#define CRYPTOPP_SHA_H
#include <stdlib.h>
namespace CryptoPP
{
//
// Dependencies
//
typedef unsigned char byte;
typedef unsigned short word16;
typedef unsigned int word32;
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef unsigned __int64 word64;
#else
typedef unsigned long long word64;
#endif
template <class T> inline T rotlFixed(T x, unsigned int y)
{
assert(y < sizeof(T)*8);
return T((x<<y) | (x>>(sizeof(T)*8-y)));
}
template <class T> inline T rotrFixed(T x, unsigned int y)
{
assert(y < sizeof(T)*8);
return T((x>>y) | (x<<(sizeof(T)*8-y)));
}
// ************** endian reversal ***************
#ifdef _MSC_VER
#if _MSC_VER >= 1400
#define CRYPTOPP_FAST_ROTATE(x) 1
#elif _MSC_VER >= 1300
#define CRYPTOPP_FAST_ROTATE(x) ((x) == 32 | (x) == 64)
#else
#define CRYPTOPP_FAST_ROTATE(x) ((x) == 32)
#endif
#elif (defined(__MWERKS__) && TARGET_CPU_PPC) || \
(defined(__GNUC__) && (defined(_ARCH_PWR2) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_ARCH_COM)))
#define CRYPTOPP_FAST_ROTATE(x) ((x) == 32)
#elif defined(__GNUC__) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86) // depend on GCC's peephole optimization to generate rotate instructions
#define CRYPTOPP_FAST_ROTATE(x) 1
#else
#define CRYPTOPP_FAST_ROTATE(x) 0
#endif
inline byte ByteReverse(byte value)
{
return value;
}
inline word16 ByteReverse(word16 value)
{
#ifdef CRYPTOPP_BYTESWAP_AVAILABLE
return bswap_16(value);
#elif defined(_MSC_VER) && _MSC_VER >= 1300
return _byteswap_ushort(value);
#else
return rotlFixed(value, 8U);
#endif
}
inline word32 ByteReverse(word32 value)
{
#if defined(__GNUC__)
__asm__ ("bswap %0" : "=r" (value) : "0" (value));
return value;
#elif defined(CRYPTOPP_BYTESWAP_AVAILABLE)
return bswap_32(value);
#elif defined(__MWERKS__) && TARGET_CPU_PPC
return (word32)__lwbrx(&value,0);
#elif _MSC_VER >= 1400 || (_MSC_VER >= 1300 && !defined(_DLL))
return _byteswap_ulong(value);
#elif CRYPTOPP_FAST_ROTATE(32)
// 5 instructions with rotate instruction, 9 without
return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff);
#else
// 6 instructions with rotate instruction, 8 without
value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
return rotlFixed(value, 16U);
#endif
}
#ifdef WORD64_AVAILABLE
inline word64 ByteReverse(word64 value)
{
#if defined(__GNUC__) && defined(__x86_64__)
__asm__ ("bswap %0" : "=r" (value) : "0" (value));
return value;
#elif defined(CRYPTOPP_BYTESWAP_AVAILABLE)
return bswap_64(value);
#elif defined(_MSC_VER) && _MSC_VER >= 1300
return _byteswap_uint64(value);
#elif defined(CRYPTOPP_SLOW_WORD64)
return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32));
#else
value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8);
value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16);
return rotlFixed(value, 32U);
#endif
}
#endif
//
// SHA
//
// http://www.weidai.com/scan-mirror/md.html#SHA-1
class SHA1
{
public:
typedef word32 HashWordType;
static void InitState(word32 *state);
static void Transform(word32 *digest, const word32 *data);
static const char * StaticAlgorithmName() {return "SHA-1";}
};
typedef SHA1 SHA; // for backwards compatibility
// implements the SHA-256 standard
class SHA256
{
public:
typedef word32 HashWordType;
static void InitState(word32 *state);
static void Transform(word32 *digest, const word32 *data);
static const char * StaticAlgorithmName() {return "SHA-256";}
};
// implements the SHA-224 standard
class SHA224
{
public:
typedef word32 HashWordType;
static void InitState(word32 *state);
static void Transform(word32 *digest, const word32 *data) {SHA256::Transform(digest, data);}
static const char * StaticAlgorithmName() {return "SHA-224";}
};
#ifdef WORD64_AVAILABLE
// implements the SHA-512 standard
class SHA512
{
public:
typedef word64 HashWordType;
static void InitState(word64 *state);
static void Transform(word64 *digest, const word64 *data);
static const char * StaticAlgorithmName() {return "SHA-512";}
};
// implements the SHA-384 standard
class SHA384
{
public:
typedef word64 HashWordType;
static void InitState(word64 *state);
static void Transform(word64 *digest, const word64 *data) {SHA512::Transform(digest, data);}
static const char * StaticAlgorithmName() {return "SHA-384";}
};
#endif
}
#endif
"%file: ./sha.cpp"
// This file is public domain
// SHA routines extracted as a standalone file from:
// Crypto++: a C++ Class Library of Cryptographic Schemes
// Version 5.5.2 (9/24/2007)
// http://www.cryptopp.com
// sha.cpp - modified by Wei Dai from Steve Reid's public domain sha1.c
// Steve Reid implemented SHA-1. Wei Dai implemented SHA-2.
// Both are in the public domain.
#include <assert.h>
#include <memory.h>
#include "sha.h"
namespace CryptoPP
{
// start of Steve Reid's code
#define blk0(i) (W[i] = data[i])
#define blk1(i) (W[i&15] = rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1))
void SHA1::InitState(HashWordType *state)
{
state[0] = 0x67452301L;
state[1] = 0xEFCDAB89L;
state[2] = 0x98BADCFEL;
state[3] = 0x10325476L;
state[4] = 0xC3D2E1F0L;
}
#define f1(x,y,z) (z^(x&(y^z)))
#define f2(x,y,z) (x^y^z)
#define f3(x,y,z) ((x&y)|(z&(x|y)))
#define f4(x,y,z) (x^y^z)
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rotlFixed(v,5);w=rotlFixed(w,30);
#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rotlFixed(v,5);w=rotlFixed(w,30);
#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rotlFixed(v,5);w=rotlFixed(w,30);
#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rotlFixed(v,5);w=rotlFixed(w,30);
#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rotlFixed(v,5);w=rotlFixed(w,30);
void SHA1::Transform(word32 *state, const word32 *data)
{
word32 W[16];
/* Copy context->state[] to working vars */
word32 a = state[0];
word32 b = state[1];
word32 c = state[2];
word32 d = state[3];
word32 e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
}
// end of Steve Reid's code
// *************************************************************
void SHA224::InitState(HashWordType *state)
{
static const word32 s[8] = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4};
memcpy(state, s, sizeof(s));
}
void SHA256::InitState(HashWordType *state)
{
static const word32 s[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
memcpy(state, s, sizeof(s));
}
static const word32 SHA256_K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15]))
#define Ch(x,y,z) (z^(x&(y^z)))
#define Maj(x,y,z) ((x&y)|(z&(x|y)))
#define a(i) T[(0-i)&7]
#define b(i) T[(1-i)&7]
#define c(i) T[(2-i)&7]
#define d(i) T[(3-i)&7]
#define e(i) T[(4-i)&7]
#define f(i) T[(5-i)&7]
#define g(i) T[(6-i)&7]
#define h(i) T[(7-i)&7]
#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+SHA256_K[i+j]+(j?blk2(i):blk0(i));\
d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i))
// for SHA256
#define S0(x) (rotrFixed(x,2)^rotrFixed(x,13)^rotrFixed(x,22))
#define S1(x) (rotrFixed(x,6)^rotrFixed(x,11)^rotrFixed(x,25))
#define s0(x) (rotrFixed(x,7)^rotrFixed(x,18)^(x>>3))
#define s1(x) (rotrFixed(x,17)^rotrFixed(x,19)^(x>>10))
void SHA256::Transform(word32 *state, const word32 *data)
{
word32 W[16];
word32 T[8];
/* Copy context->state[] to working vars */
memcpy(T, state, sizeof(T));
/* 64 operations, partially loop unrolled */
for (unsigned int j=0; j<64; j+=16)
{
R( 0); R( 1); R( 2); R( 3);
R( 4); R( 5); R( 6); R( 7);
R( 8); R( 9); R(10); R(11);
R(12); R(13); R(14); R(15);
}
/* Add the working vars back into context.state[] */
state[0] += a(0);
state[1] += b(0);
state[2] += c(0);
state[3] += d(0);
state[4] += e(0);
state[5] += f(0);
state[6] += g(0);
state[7] += h(0);
}
/*
// smaller but slower
void SHA256_Transform(word32 *state, const word32 *data)
{
word32 T[20];
word32 W[32];
unsigned int i = 0, j = 0;
word32 *t = T+8;
memcpy(t, state, 8*4);
word32 e = t[4], a = t[0];
do
{
word32 w = data[j];
W[j] = w;
w += K[j];
w += t[7];
w += S1(e);
w += Ch(e, t[5], t[6]);
e = t[3] + w;
t[3] = t[3+8] = e;
w += S0(t[0]);
a = w + Maj(a, t[1], t[2]);
t[-1] = t[7] = a;
--t;
++j;
if (j%8 == 0)
t += 8;
} while (j<16);
do
{
i = j&0xf;
word32 w = s1(W[i+16-2]) + s0(W[i+16-15]) + W[i] + W[i+16-7];
W[i+16] = W[i] = w;
w += K[j];
w += t[7];
w += S1(e);
w += Ch(e, t[5], t[6]);
e = t[3] + w;
t[3] = t[3+8] = e;
w += S0(t[0]);
a = w + Maj(a, t[1], t[2]);
t[-1] = t[7] = a;
w = s1(W[(i+1)+16-2]) + s0(W[(i+1)+16-15]) + W[(i+1)] + W[(i+1)+16-7];
W[(i+1)+16] = W[(i+1)] = w;
w += K[j+1];
w += (t-1)[7];
w += S1(e);
w += Ch(e, (t-1)[5], (t-1)[6]);
e = (t-1)[3] + w;
(t-1)[3] = (t-1)[3+8] = e;
w += S0((t-1)[0]);
a = w + Maj(a, (t-1)[1], (t-1)[2]);
(t-1)[-1] = (t-1)[7] = a;
t-=2;
j+=2;
if (j%8 == 0)
t += 8;
} while (j<64);
state[0] += a;
state[1] += t[1];
state[2] += t[2];
state[3] += t[3];
state[4] += e;
state[5] += t[5];
state[6] += t[6];
state[7] += t[7];
}
*/
#undef S0
#undef S1
#undef s0
#undef s1
#undef R
// *************************************************************
#ifdef WORD64_AVAILABLE
void SHA384::InitState(HashWordType *state)
{
static const word64 s[8] = {
W64LIT(0xcbbb9d5dc1059ed8), W64LIT(0x629a292a367cd507),
W64LIT(0x9159015a3070dd17), W64LIT(0x152fecd8f70e5939),
W64LIT(0x67332667ffc00b31), W64LIT(0x8eb44a8768581511),
W64LIT(0xdb0c2e0d64f98fa7), W64LIT(0x47b5481dbefa4fa4)};
memcpy(state, s, sizeof(s));
}
void SHA512::InitState(HashWordType *state)
{
static const word64 s[8] = {
W64LIT(0x6a09e667f3bcc908), W64LIT(0xbb67ae8584caa73b),
W64LIT(0x3c6ef372fe94f82b), W64LIT(0xa54ff53a5f1d36f1),
W64LIT(0x510e527fade682d1), W64LIT(0x9b05688c2b3e6c1f),
W64LIT(0x1f83d9abfb41bd6b), W64LIT(0x5be0cd19137e2179)};
memcpy(state, s, sizeof(s));
}
CRYPTOPP_ALIGN_DATA(16) static const word64 SHA512_K[80] CRYPTOPP_SECTION_ALIGN16 = {
W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd),
W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc),
W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019),
W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118),
W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe),
W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2),
W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1),
W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694),
W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3),
W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65),
W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483),
W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5),
W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210),
W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4),
W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725),
W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70),
W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926),
W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df),
W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8),
W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b),
W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001),
W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30),
W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910),
W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8),
W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53),
W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8),
W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb),
W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3),
W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60),
W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec),
W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9),
W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b),
W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207),
W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178),
W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6),
W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b),
W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493),
W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c),
W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a),
W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817)
};
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86
// put assembly version in separate function, otherwise MSVC 2005 SP1 doesn't generate correct code for the non-assembly version
CRYPTOPP_NAKED static void CRYPTOPP_FASTCALL SHA512_SSE2_Transform(word64 *state, const word64 *data)
{
#ifdef __GNUC__
__asm__ __volatile__
(
".intel_syntax noprefix;"
AS1( push ebx)
AS2( mov ebx, eax)
#else
AS1( push ebx)
AS1( push esi)
AS1( push edi)
AS2( lea ebx, SHA512_K)
#endif
AS2( mov eax, esp)
AS2( and esp, 0xfffffff0)
AS2( sub esp, 27*16) // 17*16 for expanded data, 20*8 for state
AS1( push eax)
AS2( xor eax, eax)
AS2( lea edi, [esp+4+8*8]) // start at middle of state buffer. will decrement pointer each round to avoid copying
AS2( lea esi, [esp+4+20*8+8]) // 16-byte alignment, then add 8
AS2( movq mm4, [ecx+0*8])
AS2( movq [edi+0*8], mm4)
AS2( movq mm0, [ecx+1*8])
AS2( movq [edi+1*8], mm0)
AS2( movq mm0, [ecx+2*8])
AS2( movq [edi+2*8], mm0)
AS2( movq mm0, [ecx+3*8])
AS2( movq [edi+3*8], mm0)
AS2( movq mm5, [ecx+4*8])
AS2( movq [edi+4*8], mm5)
AS2( movq mm0, [ecx+5*8])
AS2( movq [edi+5*8], mm0)
AS2( movq mm0, [ecx+6*8])
AS2( movq [edi+6*8], mm0)
AS2( movq mm0, [ecx+7*8])
AS2( movq [edi+7*8], mm0)
ASJ( jmp, 0, f)
#define SSE2_S0_S1(r, a, b, c) \
AS2( movq mm6, r)\
AS2( psrlq r, a)\
AS2( movq mm7, r)\
AS2( psllq mm6, 64-c)\
AS2( pxor mm7, mm6)\
AS2( psrlq r, b-a)\
AS2( pxor mm7, r)\
AS2( psllq mm6, c-b)\
AS2( pxor mm7, mm6)\
AS2( psrlq r, c-b)\
AS2( pxor r, mm7)\
AS2( psllq mm6, b-a)\
AS2( pxor r, mm6)
#define SSE2_s0(r, a, b, c) \
AS2( movdqa xmm6, r)\
AS2( psrlq r, a)\
AS2( movdqa xmm7, r)\
AS2( psllq xmm6, 64-c)\
AS2( pxor xmm7, xmm6)\
AS2( psrlq r, b-a)\
AS2( pxor xmm7, r)\
AS2( psrlq r, c-b)\
AS2( pxor r, xmm7)\
AS2( psllq xmm6, c-a)\
AS2( pxor r, xmm6)
#define SSE2_s1(r, a, b, c) \
AS2( movdqa xmm6, r)\
AS2( psrlq r, a)\
AS2( movdqa xmm7, r)\
AS2( psllq xmm6, 64-c)\
AS2( pxor xmm7, xmm6)\
AS2( psrlq r, b-a)\
AS2( pxor xmm7, r)\
AS2( psllq xmm6, c-b)\
AS2( pxor xmm7, xmm6)\
AS2( psrlq r, c-b)\
AS2( pxor r, xmm7)
ASL(SHA512_Round)
// k + w is in mm0, a is in mm4, e is in mm5
AS2( paddq mm0, [edi+7*8]) // h
AS2( movq mm2, [edi+5*8]) // f
AS2( movq mm3, [edi+6*8]) // g
AS2( pxor mm2, mm3)
AS2( pand mm2, mm5)
SSE2_S0_S1(mm5,14,18,41)
AS2( pxor mm2, mm3)
AS2( paddq mm0, mm2) // h += Ch(e,f,g)
AS2( paddq mm5, mm0) // h += S1(e)
AS2( movq mm2, [edi+1*8]) // b
AS2( movq mm1, mm2)
AS2( por mm2, mm4)
AS2( pand mm2, [edi+2*8]) // c
AS2( pand mm1, mm4)
AS2( por mm1, mm2)
AS2( paddq mm1, mm5) // temp = h + Maj(a,b,c)
AS2( paddq mm5, [edi+3*8]) // e = d + h
AS2( movq [edi+3*8], mm5)
AS2( movq [edi+11*8], mm5)
SSE2_S0_S1(mm4,28,34,39) // S0(a)
AS2( paddq mm4, mm1) // a = temp + S0(a)
AS2( movq [edi-8], mm4)
AS2( movq [edi+7*8], mm4)
AS1( ret)
// first 16 rounds
ASL(0)
AS2( movq mm0, [edx+eax*8])
AS2( movq [esi+eax*8], mm0)
AS2( movq [esi+eax*8+16*8], mm0)
AS2( paddq mm0, [ebx+eax*8])
ASC( call, SHA512_Round)
AS1( inc eax)
AS2( sub edi, 8)
AS2( test eax, 7)
ASJ( jnz, 0, b)
AS2( add edi, 8*8)
AS2( cmp eax, 16)
ASJ( jne, 0, b)
// rest of the rounds
AS2( movdqu xmm0, [esi+(16-2)*8])
ASL(1)
// data expansion, W[i-2] already in xmm0
AS2( movdqu xmm3, [esi])
AS2( paddq xmm3, [esi+(16-7)*8])
AS2( movdqa xmm2, [esi+(16-15)*8])
SSE2_s1(xmm0, 6, 19, 61)
AS2( paddq xmm0, xmm3)
SSE2_s0(xmm2, 1, 7, 8)
AS2( paddq xmm0, xmm2)
AS2( movdq2q mm0, xmm0)
AS2( movhlps xmm1, xmm0)
AS2( paddq mm0, [ebx+eax*8])
AS2( movlps [esi], xmm0)
AS2( movlps [esi+8], xmm1)
AS2( movlps [esi+8*16], xmm0)
AS2( movlps [esi+8*17], xmm1)
// 2 rounds
ASC( call, SHA512_Round)
AS2( sub edi, 8)
AS2( movdq2q mm0, xmm1)
AS2( paddq mm0, [ebx+eax*8+8])
ASC( call, SHA512_Round)
// update indices and loop
AS2( add esi, 16)
AS2( add eax, 2)
AS2( sub edi, 8)
AS2( test eax, 7)
ASJ( jnz, 1, b)
// do housekeeping every 8 rounds
AS2( mov esi, 0xf)
AS2( and esi, eax)
AS2( lea esi, [esp+4+20*8+8+esi*8])
AS2( add edi, 8*8)
AS2( cmp eax, 80)
ASJ( jne, 1, b)
#define SSE2_CombineState(i) \
AS2( movq mm0, [edi+i*8])\
AS2( paddq mm0, [ecx+i*8])\
AS2( movq [ecx+i*8], mm0)
SSE2_CombineState(0)
SSE2_CombineState(1)
SSE2_CombineState(2)
SSE2_CombineState(3)
SSE2_CombineState(4)
SSE2_CombineState(5)
SSE2_CombineState(6)
SSE2_CombineState(7)
AS1( pop esp)
AS1( emms)
#if defined(__GNUC__)
AS1( pop ebx)
".att_syntax prefix;"
:
: "a" (SHA512_K), "c" (state), "d" (data)
: "%esi", "%edi", "memory", "cc"
);
#else
AS1( pop edi)
AS1( pop esi)
AS1( pop ebx)
AS1( ret)
#endif
}
#endif // #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
void SHA512::Transform(word64 *state, const word64 *data)
{
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86
if (HasSSE2())
{
SHA512_SSE2_Transform(state, data);
return;
}
#endif
#define S0(x) (rotrFixed(x,28)^rotrFixed(x,34)^rotrFixed(x,39))
#define S1(x) (rotrFixed(x,14)^rotrFixed(x,18)^rotrFixed(x,41))
#define s0(x) (rotrFixed(x,1)^rotrFixed(x,8)^(x>>7))
#define s1(x) (rotrFixed(x,19)^rotrFixed(x,61)^(x>>6))
#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+SHA512_K[i+j]+(j?blk2(i):blk0(i));\
d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i))
word64 W[16];
word64 T[8];
/* Copy context->state[] to working vars */
memcpy(T, state, sizeof(T));
/* 80 operations, partially loop unrolled */
for (unsigned int j=0; j<80; j+=16)
{
R( 0); R( 1); R( 2); R( 3);
R( 4); R( 5); R( 6); R( 7);
R( 8); R( 9); R(10); R(11);
R(12); R(13); R(14); R(15);
}
/* Add the working vars back into context.state[] */
state[0] += a(0);
state[1] += b(0);
state[2] += c(0);
state[3] += d(0);
state[4] += e(0);
state[5] += f(0);
state[6] += g(0);
state[7] += h(0);
}
#endif
}
"%file: ./strlcpy.h"
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
inline size_t strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0)
{
while (--n != 0)
{
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0)
{
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
inline size_t strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0')
{
if (n != 1)
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
"%file: ./ui.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.
DECLARE_EVENT_TYPE(wxEVT_UITHREADCALL, -1)
#if wxUSE_GUI
static const bool fGUI=true;
#else
static const bool fGUI=false;
#endif
inline int MyMessageBox(const wxString& message, const wxString& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
{
#if wxUSE_GUI
if (!fDaemon)
return wxMessageBox(message, caption, style, parent, x, y);
#endif
printf("wxMessageBox %s: %s\n", string(caption).c_str(), string(message).c_str());
fprintf(stderr, "%s: %s\n", string(caption).c_str(), string(message).c_str());
return wxOK;
}
#define wxMessageBox MyMessageBox
void HandleCtrlA(wxKeyEvent& event);
string FormatTxStatus(const CWalletTx& wtx);
void UIThreadCall(boost::function0<void>);
int ThreadSafeMessageBox(const string& message, const string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent);
void CalledSetStatusBar(const string& strText, int nField);
void MainFrameRepaint();
void CreateMainWindow();
#if !wxUSE_GUI
inline int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
{
return MyMessageBox(message, caption, style, parent, x, y);
}
inline bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
{
return true;
}
inline void CalledSetStatusBar(const string& strText, int nField)
{
}
inline void UIThreadCall(boost::function0<void> fn)
{
}
inline void MainFrameRepaint()
{
}
inline void CreateMainWindow()
{
}
#else // wxUSE_GUI
class CMainFrame : public CMainFrameBase
{
protected:
// Event handlers
void OnNotebookPageChanged(wxNotebookEvent& event);
void OnClose(wxCloseEvent& event);
void OnIconize(wxIconizeEvent& event);
void OnMouseEvents(wxMouseEvent& event);
void OnKeyDown(wxKeyEvent& event) { HandleCtrlA(event); }
void OnIdle(wxIdleEvent& event);
void OnPaint(wxPaintEvent& event);
void OnPaintListCtrl(wxPaintEvent& event);
void OnMenuFileExit(wxCommandEvent& event);
void OnMenuOptionsGenerate(wxCommandEvent& event);
void OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event);
void OnMenuOptionsChangeYourAddress(wxCommandEvent& event);
void OnMenuOptionsOptions(wxCommandEvent& event);
void OnMenuHelpAbout(wxCommandEvent& event);
void OnButtonSend(wxCommandEvent& event);
void OnButtonAddressBook(wxCommandEvent& event);
void OnSetFocusAddress(wxFocusEvent& event);
void OnMouseEventsAddress(wxMouseEvent& event);
void OnButtonNew(wxCommandEvent& event);
void OnButtonCopy(wxCommandEvent& event);
void OnListColBeginDrag(wxListEvent& event);
void OnListItemActivated(wxListEvent& event);
void OnListItemActivatedProductsSent(wxListEvent& event);
void OnListItemActivatedOrdersSent(wxListEvent& event);
void OnListItemActivatedOrdersReceived(wxListEvent& event);
public:
/** Constructor */
CMainFrame(wxWindow* parent);
~CMainFrame();
// Custom
enum
{
ALL = 0,
SENTRECEIVED = 1,
SENT = 2,
RECEIVED = 3,
};
int nPage;
wxListCtrl* m_listCtrl;
bool fShowGenerated;
bool fShowSent;
bool fShowReceived;
bool fRefreshListCtrl;
bool fRefreshListCtrlRunning;
bool fOnSetFocusAddress;
unsigned int nListViewUpdated;
bool fRefresh;
void OnUIThreadCall(wxCommandEvent& event);
int GetSortIndex(const string& strSort);
void InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5);
bool DeleteLine(uint256 hashKey);
bool InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex=-1);
void RefreshListCtrl();
void RefreshStatusColumn();
};
class CTxDetailsDialog : public CTxDetailsDialogBase
{
protected:
// Event handlers
void OnButtonOK(wxCommandEvent& event);
public:
/** Constructor */
CTxDetailsDialog(wxWindow* parent, CWalletTx wtx);
// State
CWalletTx wtx;
};
class COptionsDialog : public COptionsDialogBase
{
protected:
// Event handlers
void OnListBox(wxCommandEvent& event);
void OnKillFocusTransactionFee(wxFocusEvent& event);
void OnCheckBoxLimitProcessors(wxCommandEvent& event);
void OnCheckBoxUseProxy(wxCommandEvent& event);
void OnKillFocusProxy(wxFocusEvent& event);
void OnButtonOK(wxCommandEvent& event);
void OnButtonCancel(wxCommandEvent& event);
void OnButtonApply(wxCommandEvent& event);
public:
/** Constructor */
COptionsDialog(wxWindow* parent);
// Custom
bool fTmpStartOnSystemStartup;
bool fTmpMinimizeOnClose;
void SelectPage(int nPage);
CAddress GetProxyAddr();
};
class CAboutDialog : public CAboutDialogBase
{
protected:
// Event handlers
void OnButtonOK(wxCommandEvent& event);
public:
/** Constructor */
CAboutDialog(wxWindow* parent);
};
class CSendDialog : public CSendDialogBase
{
protected:
// Event handlers
void OnKeyDown(wxKeyEvent& event) { HandleCtrlA(event); }
void OnTextAddress(wxCommandEvent& event);
void OnKillFocusAmount(wxFocusEvent& event);
void OnButtonAddressBook(wxCommandEvent& event);
void OnButtonPaste(wxCommandEvent& event);
void OnButtonSend(wxCommandEvent& event);
void OnButtonCancel(wxCommandEvent& event);
public:
/** Constructor */
CSendDialog(wxWindow* parent, const wxString& strAddress="");
// Custom
bool fEnabledPrev;
string strFromSave;
string strMessageSave;
};
class CSendingDialog : public CSendingDialogBase
{
public:
// Event handlers
void OnClose(wxCloseEvent& event);
void OnButtonOK(wxCommandEvent& event);
void OnButtonCancel(wxCommandEvent& event);
void OnPaint(wxPaintEvent& event);
public:
/** Constructor */
CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 nPriceIn, const CWalletTx& wtxIn);
~CSendingDialog();
// State
CAddress addr;
int64 nPrice;
CWalletTx wtx;
wxDateTime start;
char pszStatus[10000];
bool fCanCancel;
bool fAbort;
bool fSuccess;
bool fUIDone;
bool fWorkDone;
void Close();
void Repaint();
bool Status();
bool Status(const string& str);
bool Error(const string& str);
void StartTransfer();
void OnReply2(CDataStream& vRecv);
void OnReply3(CDataStream& vRecv);
};
void SendingDialogStartTransfer(void* parg);
void SendingDialogOnReply2(void* parg, CDataStream& vRecv);
void SendingDialogOnReply3(void* parg, CDataStream& vRecv);
class CAddressBookDialog : public CAddressBookDialogBase
{
protected:
// Event handlers
void OnNotebookPageChanged(wxNotebookEvent& event);
void OnListEndLabelEdit(wxListEvent& event);
void OnListItemSelected(wxListEvent& event);
void OnListItemActivated(wxListEvent& event);
void OnButtonDelete(wxCommandEvent& event);
void OnButtonCopy(wxCommandEvent& event);
void OnButtonEdit(wxCommandEvent& event);
void OnButtonNew(wxCommandEvent& event);
void OnButtonOK(wxCommandEvent& event);
void OnButtonCancel(wxCommandEvent& event);
void OnClose(wxCloseEvent& event);
public:
/** Constructor */
CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, int nPageIn, bool fDuringSendIn);
// Custom
enum
{
SENDING = 0,
RECEIVING = 1,
};
int nPage;
wxListCtrl* m_listCtrl;
bool fDuringSend;
wxString GetAddress();
wxString GetSelectedAddress();
wxString GetSelectedSendingAddress();
wxString GetSelectedReceivingAddress();
bool CheckIfMine(const string& strAddress, const string& strTitle);
};
class CGetTextFromUserDialog : public CGetTextFromUserDialogBase
{
protected:
// Event handlers
void OnButtonOK(wxCommandEvent& event) { EndModal(true); }
void OnButtonCancel(wxCommandEvent& event) { EndModal(false); }
void OnClose(wxCloseEvent& event) { EndModal(false); }
void OnKeyDown(wxKeyEvent& event)
{
if (event.GetKeyCode() == '\r' || event.GetKeyCode() == WXK_NUMPAD_ENTER)
EndModal(true);
else
HandleCtrlA(event);
}
public:
/** Constructor */
CGetTextFromUserDialog(wxWindow* parent,
const string& strCaption,
const string& strMessage1,
const string& strValue1="",
const string& strMessage2="",
const string& strValue2="") : CGetTextFromUserDialogBase(parent, wxID_ANY, strCaption)
{
int x = GetSize().GetWidth();
int y = GetSize().GetHeight();
m_staticTextMessage1->SetLabel(strMessage1);
m_textCtrl1->SetValue(strValue1);
y += wxString(strMessage1).Freq('\n') * 14;
if (!strMessage2.empty())
{
m_staticTextMessage2->Show(true);
m_staticTextMessage2->SetLabel(strMessage2);
m_textCtrl2->Show(true);
m_textCtrl2->SetValue(strValue2);
y += 46 + wxString(strMessage2).Freq('\n') * 14;
}
if (!fWindows)
{
x *= 1.14;
y *= 1.14;
}
SetSize(x, y);
}
// Custom
string GetValue() { return (string)m_textCtrl1->GetValue(); }
string GetValue1() { return (string)m_textCtrl1->GetValue(); }
string GetValue2() { return (string)m_textCtrl2->GetValue(); }
};
class CMyTaskBarIcon : public wxTaskBarIcon
{
protected:
// Event handlers
void OnLeftButtonDClick(wxTaskBarIconEvent& event);
void OnMenuRestore(wxCommandEvent& event);
void OnMenuOptions(wxCommandEvent& event);
void OnUpdateUIGenerate(wxUpdateUIEvent& event);
void OnMenuGenerate(wxCommandEvent& event);
void OnMenuExit(wxCommandEvent& event);
public:
CMyTaskBarIcon() : wxTaskBarIcon()
{
Show(true);
}
void Show(bool fShow=true);
void Hide();
void Restore();
void UpdateTooltip();
virtual wxMenu* CreatePopupMenu();
DECLARE_EVENT_TABLE()
};
#endif // wxUSE_GUI
"%file: ./ui.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"
#ifdef _MSC_VER
#include <crtdbg.h>
#endif
DEFINE_EVENT_TYPE(wxEVT_UITHREADCALL)
CMainFrame* pframeMain = NULL;
CMyTaskBarIcon* ptaskbaricon = NULL;
bool fClosedToTray = false;
//////////////////////////////////////////////////////////////////////////////
//
// Util
//
void HandleCtrlA(wxKeyEvent& event)
{
// Ctrl-a select all
event.Skip();
wxTextCtrl* textCtrl = (wxTextCtrl*)event.GetEventObject();
if (event.GetModifiers() == wxMOD_CONTROL && event.GetKeyCode() == 'A')
textCtrl->SetSelection(-1, -1);
}
bool Is24HourTime()
{
//char pszHourFormat[256];
//pszHourFormat[0] = '\0';
//GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, pszHourFormat, 256);
//return (pszHourFormat[0] != '0');
return true;
}
string DateStr(int64 nTime)
{
// Can only be used safely here in the UI
return (string)wxDateTime((time_t)nTime).FormatDate();
}
string DateTimeStr(int64 nTime)
{
// Can only be used safely here in the UI
wxDateTime datetime((time_t)nTime);
if (Is24HourTime())
return (string)datetime.Format("%x %H:%M");
else
return (string)datetime.Format("%x ") + itostr((datetime.GetHour() + 11) % 12 + 1) + (string)datetime.Format(":%M %p");
}
wxString GetItemText(wxListCtrl* listCtrl, int nIndex, int nColumn)
{
// Helper to simplify access to listctrl
wxListItem item;
item.m_itemId = nIndex;
item.m_col = nColumn;
item.m_mask = wxLIST_MASK_TEXT;
if (!listCtrl->GetItem(item))
return "";
return item.GetText();
}
int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1)
{
int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
listCtrl->SetItem(nIndex, 1, str1);
return nIndex;
}
int InsertLine(wxListCtrl* listCtrl, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
{
int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
listCtrl->SetItem(nIndex, 1, str1);
listCtrl->SetItem(nIndex, 2, str2);
listCtrl->SetItem(nIndex, 3, str3);
listCtrl->SetItem(nIndex, 4, str4);
return nIndex;
}
int InsertLine(wxListCtrl* listCtrl, void* pdata, const wxString& str0, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4)
{
int nIndex = listCtrl->InsertItem(listCtrl->GetItemCount(), str0);
listCtrl->SetItemPtrData(nIndex, (wxUIntPtr)pdata);
listCtrl->SetItem(nIndex, 1, str1);
listCtrl->SetItem(nIndex, 2, str2);
listCtrl->SetItem(nIndex, 3, str3);
listCtrl->SetItem(nIndex, 4, str4);
return nIndex;
}
void SetSelection(wxListCtrl* listCtrl, int nIndex)
{
int nSize = listCtrl->GetItemCount();
long nState = (wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
for (int i = 0; i < nSize; i++)
listCtrl->SetItemState(i, (i == nIndex ? nState : 0), nState);
}
int GetSelection(wxListCtrl* listCtrl)
{
int nSize = listCtrl->GetItemCount();
for (int i = 0; i < nSize; i++)
if (listCtrl->GetItemState(i, wxLIST_STATE_FOCUSED))
return i;
return -1;
}
string HtmlEscape(const char* psz, bool fMultiLine=false)
{
int len = 0;
for (const char* p = psz; *p; p++)
{
if (*p == '<') len += 4;
else if (*p == '>') len += 4;
else if (*p == '&') len += 5;
else if (*p == '"') len += 6;
else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
else if (*p == '\n' && fMultiLine) len += 5;
else
len++;
}
string str;
str.reserve(len);
for (const char* p = psz; *p; p++)
{
if (*p == '<') str += "&lt;";
else if (*p == '>') str += "&gt;";
else if (*p == '&') str += "&amp;";
else if (*p == '"') str += "&quot;";
else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += "&nbsp;";
else if (*p == '\n' && fMultiLine) str += "<br>\n";
else
str += *p;
}
return str;
}
string HtmlEscape(const string& str, bool fMultiLine=false)
{
return HtmlEscape(str.c_str(), fMultiLine);
}
void CalledMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y, int* pnRet, bool* pfDone)
{
*pnRet = wxMessageBox(message, caption, style, parent, x, y);
*pfDone = true;
}
int ThreadSafeMessageBox(const string& message, const string& caption, int style, wxWindow* parent, int x, int y)
{
#ifdef __WXMSW__
return wxMessageBox(message, caption, style, parent, x, y);
#else
if (wxThread::IsMain() || fDaemon)
{
return wxMessageBox(message, caption, style, parent, x, y);
}
else
{
int nRet = 0;
bool fDone = false;
UIThreadCall(bind(CalledMessageBox, message, caption, style, parent, x, y, &nRet, &fDone));
while (!fDone)
Sleep(100);
return nRet;
}
#endif
}
bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
{
if (nFeeRequired == 0 || fDaemon)
return true;
string strMessage = strprintf(
_("This transaction is over the size limit. You can still send it for a fee of %s, "
"which goes to the nodes that process your transaction and helps to support the network. "
"Do you want to pay the fee?"),
FormatMoney(nFeeRequired).c_str());
return (ThreadSafeMessageBox(strMessage, strCaption, wxYES_NO, parent) == wxYES);
}
void CalledSetStatusBar(const string& strText, int nField)
{
if (pframeMain && pframeMain->m_statusBar)
pframeMain->m_statusBar->SetStatusText(strText, nField);
}
void SetDefaultReceivingAddress(const string& strAddress)
{
// Update main window address and database
if (pframeMain == NULL)
return;
if (strAddress != pframeMain->m_textCtrlAddress->GetValue())
{
uint160 hash160;
if (!AddressToHash160(strAddress, hash160))
return;
if (!mapPubKeys.count(hash160))
return;
CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
pframeMain->m_textCtrlAddress->SetValue(strAddress);
}
}
//////////////////////////////////////////////////////////////////////////////
//
// CMainFrame
//
CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
{
Connect(wxEVT_UITHREADCALL, wxCommandEventHandler(CMainFrame::OnUIThreadCall), NULL, this);
// Set initially selected page
wxNotebookEvent event;
event.SetSelection(0);
OnNotebookPageChanged(event);
m_notebook->ChangeSelection(0);
// Init
fRefreshListCtrl = false;
fRefreshListCtrlRunning = false;
fOnSetFocusAddress = false;
fRefresh = false;
m_choiceFilter->SetSelection(0);
double dResize = 1.0;
#ifdef __WXMSW__
SetIcon(wxICON(bitcoin));
#else
SetIcon(bitcoin16_xpm);
wxFont fontTmp = m_staticText41->GetFont();
fontTmp.SetFamily(wxFONTFAMILY_TELETYPE);
m_staticTextBalance->SetFont(fontTmp);
m_staticTextBalance->SetSize(140, 17);
// resize to fit ubuntu's huge default font
dResize = 1.22;
SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
#endif
m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
m_listCtrl->SetFocus();
ptaskbaricon = new CMyTaskBarIcon();
#ifdef __WXMAC__
// Mac automatically moves wxID_EXIT, wxID_PREFERENCES and wxID_ABOUT
// to their standard places, leaving these menus empty.
GetMenuBar()->Remove(2); // remove Help menu
GetMenuBar()->Remove(0); // remove File menu
#endif
// Init column headers
int nDateWidth = DateTimeStr(1229413914).size() * 6 + 8;
if (!strstr(DateTimeStr(1229413914).c_str(), "2008"))
nDateWidth += 12;
#ifdef __WXMAC__
nDateWidth += 5;
dResize -= 0.01;
#endif
wxListCtrl* pplistCtrl[] = {m_listCtrlAll, m_listCtrlSentReceived, m_listCtrlSent, m_listCtrlReceived};
foreach(wxListCtrl* p, pplistCtrl)
{
p->InsertColumn(0, "", wxLIST_FORMAT_LEFT, dResize * 0);
p->InsertColumn(1, "", wxLIST_FORMAT_LEFT, dResize * 0);
p->InsertColumn(2, _("Status"), wxLIST_FORMAT_LEFT, dResize * 112);
p->InsertColumn(3, _("Date"), wxLIST_FORMAT_LEFT, dResize * nDateWidth);
p->InsertColumn(4, _("Description"), wxLIST_FORMAT_LEFT, dResize * 409 - nDateWidth);
p->InsertColumn(5, _("Debit"), wxLIST_FORMAT_RIGHT, dResize * 79);
p->InsertColumn(6, _("Credit"), wxLIST_FORMAT_RIGHT, dResize * 79);
}
// Init status bar
int pnWidths[3] = { -100, 88, 300 };
#ifndef __WXMSW__
pnWidths[1] = pnWidths[1] * 1.1 * dResize;
pnWidths[2] = pnWidths[2] * 1.1 * dResize;
#endif
m_statusBar->SetFieldsCount(3, pnWidths);
// Fill your address text box
vector<unsigned char> vchPubKey;
if (CWalletDB("r").ReadDefaultKey(vchPubKey))
m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
// Fill listctrl with wallet transactions
RefreshListCtrl();
}
CMainFrame::~CMainFrame()
{
pframeMain = NULL;
delete ptaskbaricon;
ptaskbaricon = NULL;
}
void CMainFrame::OnNotebookPageChanged(wxNotebookEvent& event)
{
event.Skip();
nPage = event.GetSelection();
if (nPage == ALL)
{
m_listCtrl = m_listCtrlAll;
fShowGenerated = true;
fShowSent = true;
fShowReceived = true;
}
else if (nPage == SENTRECEIVED)
{
m_listCtrl = m_listCtrlSentReceived;
fShowGenerated = false;
fShowSent = true;
fShowReceived = true;
}
else if (nPage == SENT)
{
m_listCtrl = m_listCtrlSent;
fShowGenerated = false;
fShowSent = true;
fShowReceived = false;
}
else if (nPage == RECEIVED)
{
m_listCtrl = m_listCtrlReceived;
fShowGenerated = false;
fShowSent = false;
fShowReceived = true;
}
RefreshListCtrl();
m_listCtrl->SetFocus();
}
void CMainFrame::OnClose(wxCloseEvent& event)
{
if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
{
// Divert close to minimize
event.Veto();
fClosedToTray = true;
Iconize(true);
}
else
{
Destroy();
CreateThread(Shutdown, NULL);
}
}
void CMainFrame::OnIconize(wxIconizeEvent& event)
{
event.Skip();
// Hide the task bar button when minimized.
// Event is sent when the frame is minimized or restored.
// wxWidgets 2.8.9 doesn't have IsIconized() so there's no way
// to get rid of the deprecated warning. Just ignore it.
if (!event.Iconized())
fClosedToTray = false;
#ifndef __WXMSW__
// Tray is not reliable on ubuntu 9.10 gnome
fClosedToTray = false;
#endif
if (fMinimizeToTray && event.Iconized())
fClosedToTray = true;
Show(!fClosedToTray);
ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
}
void CMainFrame::OnMouseEvents(wxMouseEvent& event)
{
event.Skip();
RandAddSeed();
RAND_add(&event.m_x, sizeof(event.m_x), 0.25);
RAND_add(&event.m_y, sizeof(event.m_y), 0.25);
}
void CMainFrame::OnListColBeginDrag(wxListEvent& event)
{
// Hidden columns not resizeable
if (event.GetColumn() <= 1 && !fDebug)
event.Veto();
else
event.Skip();
}
int CMainFrame::GetSortIndex(const string& strSort)
{
#ifdef __WXMSW__
return 0;
#else
// The wx generic listctrl implementation used on GTK doesn't sort,
// so we have to do it ourselves. Remember, we sort in reverse order.
// In the wx generic implementation, they store the list of items
// in a vector, so indexed lookups are fast, but inserts are slower
// the closer they are to the top.
int low = 0;
int high = m_listCtrl->GetItemCount();
while (low < high)
{
int mid = low + ((high - low) / 2);
if (strSort.compare(m_listCtrl->GetItemText(mid).c_str()) >= 0)
high = mid;
else
low = mid + 1;
}
return low;
#endif
}
void CMainFrame::InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5, const wxString& str6)
{
strSort = " " + strSort; // leading space to workaround wx2.9.0 ubuntu 9.10 bug
long nData = *(long*)&hashKey; // where first char of hidden column is displayed
// Find item
if (!fNew && nIndex == -1)
{
string strHash = " " + hashKey.ToString();
while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
break;
}
// fNew is for blind insert, only use if you're sure it's new
if (fNew || nIndex == -1)
{
nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
}
else
{
// If sort key changed, must delete and reinsert to make it relocate
if (GetItemText(m_listCtrl, nIndex, 0) != strSort)
{
m_listCtrl->DeleteItem(nIndex);
nIndex = m_listCtrl->InsertItem(GetSortIndex(strSort), strSort);
}
}
m_listCtrl->SetItem(nIndex, 1, " " + hashKey.ToString());
m_listCtrl->SetItem(nIndex, 2, str2);
m_listCtrl->SetItem(nIndex, 3, str3);
m_listCtrl->SetItem(nIndex, 4, str4);
m_listCtrl->SetItem(nIndex, 5, str5);
m_listCtrl->SetItem(nIndex, 6, str6);
m_listCtrl->SetItemData(nIndex, nData);
}
bool CMainFrame::DeleteLine(uint256 hashKey)
{
long nData = *(long*)&hashKey;
// Find item
int nIndex = -1;
string strHash = " " + hashKey.ToString();
while ((nIndex = m_listCtrl->FindItem(nIndex, nData)) != -1)
if (GetItemText(m_listCtrl, nIndex, 1) == strHash)
break;
if (nIndex != -1)
m_listCtrl->DeleteItem(nIndex);
return nIndex != -1;
}
string FormatTxStatus(const CWalletTx& wtx)
{
// Status
if (!wtx.IsFinal())
{
if (wtx.nLockTime < 500000000)
return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
else
return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str());
}
else
{
int nDepth = wtx.GetDepthInMainChain();
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
return strprintf(_("%d/offline?"), nDepth);
else if (nDepth < 6)
return strprintf(_("%d/unconfirmed"), nDepth);
else
return strprintf(_("%d confirmations"), nDepth);
}
}
string SingleLine(const string& strIn)
{
string strOut;
bool fOneSpace = false;
foreach(int c, strIn)
{
if (isspace(c))
{
fOneSpace = true;
}
else if (c > ' ')
{
if (fOneSpace && !strOut.empty())
strOut += ' ';
strOut += c;
fOneSpace = false;
}
}
return strOut;
}
bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
{
int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
int64 nCredit = wtx.GetCredit(true);
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
uint256 hash = wtx.GetHash();
string strStatus = FormatTxStatus(wtx);
map<string, string> mapValue = wtx.mapValue;
wtx.nLinesDisplayed = 1;
nListViewUpdated++;
// Filter
if (wtx.IsCoinBase())
{
// Don't show generated coin until confirmed by at least one block after it
// so we don't get the user's hopes up until it looks like it's probably accepted.
//
// It is not an error when generated blocks are not accepted. By design,
// some percentage of blocks, like 10% or more, will end up not accepted.
// This is the normal mechanism by which the network copes with latency.
//
// We display regular transactions right away before any confirmation
// because they can always get into some block eventually. Generated coins
// are special because if their block is not accepted, they are not valid.
//
if (wtx.GetDepthInMainChain() < 2)
{
wtx.nLinesDisplayed = 0;
return false;
}
if (!fShowGenerated)
return false;
}
// Find the block the tx is in
CBlockIndex* pindex = NULL;
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
if (mi != mapBlockIndex.end())
pindex = (*mi).second;
// Sort order, unrecorded transactions sort to the top
string strSort = strprintf("%010d-%01d-%010u",
(pindex ? pindex->nHeight : INT_MAX),
(wtx.IsCoinBase() ? 1 : 0),
wtx.nTimeReceived);
// Insert line
if (nNet > 0 || wtx.IsCoinBase())
{
//
// Credit
//
string strDescription;
if (wtx.IsCoinBase())
{
// Generated
strDescription = _("Generated");
if (nCredit == 0)
{
int64 nUnmatured = 0;
foreach(const CTxOut& txout, wtx.vout)
nUnmatured += txout.GetCredit();
if (wtx.IsInMainChain())
{
strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
// Check if the block was requested by anyone
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
strDescription = _("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
}
else
{
strDescription = _("Generated (not accepted)");
}
}
}
else if (!mapValue["from"].empty() || !mapValue["message"].empty())
{
// Received by IP connection
if (!fShowReceived)
return false;
if (!mapValue["from"].empty())
strDescription += _("From: ") + mapValue["from"];
if (!mapValue["message"].empty())
{
if (!strDescription.empty())
strDescription += " - ";
strDescription += mapValue["message"];
}
}
else
{
// Received by Bitcoin Address
if (!fShowReceived)
return false;
foreach(const CTxOut& txout, wtx.vout)
{
if (txout.IsMine())
{
vector<unsigned char> vchPubKey;
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
{
CRITICAL_BLOCK(cs_mapAddressBook)
{
//strDescription += _("Received payment to ");
//strDescription += _("Received with address ");
strDescription += _("From: unknown, Received with: ");
string strAddress = PubKeyToAddress(vchPubKey);
map<string, string>::iterator mi = mapAddressBook.find(strAddress);
if (mi != mapAddressBook.end() && !(*mi).second.empty())
{
string strLabel = (*mi).second;
strDescription += strAddress.substr(0,12) + "... ";
strDescription += "(" + strLabel + ")";
}
else
strDescription += strAddress;
}
}
break;
}
}
}
InsertLine(fNew, nIndex, hash, strSort,
strStatus,
nTime ? DateTimeStr(nTime) : "",
SingleLine(strDescription),
"",
FormatMoney(nNet, true));
}
else
{
bool fAllFromMe = true;
foreach(const CTxIn& txin, wtx.vin)
fAllFromMe = fAllFromMe && txin.IsMine();
bool fAllToMe = true;
foreach(const CTxOut& txout, wtx.vout)
fAllToMe = fAllToMe && txout.IsMine();
if (fAllFromMe && fAllToMe)
{
// Payment to self
int64 nValue = wtx.vout[0].nValue;
InsertLine(fNew, nIndex, hash, strSort,
strStatus,
nTime ? DateTimeStr(nTime) : "",
_("Payment to yourself"),
"",
"");
/// issue: can't tell which is the payment and which is the change anymore
// FormatMoney(nNet - nValue, true),
// FormatMoney(nValue, true));
}
else if (fAllFromMe)
{
//
// Debit
//
if (!fShowSent)
return false;
int64 nTxFee = nDebit - wtx.GetValueOut();
wtx.nLinesDisplayed = 0;
for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
{
const CTxOut& txout = wtx.vout[nOut];
if (txout.IsMine())
continue;
string strAddress;
if (!mapValue["to"].empty())
{
// Sent to IP
strAddress = mapValue["to"];
}
else
{
// Sent to Bitcoin Address
uint160 hash160;
if (ExtractHash160(txout.scriptPubKey, hash160))
strAddress = Hash160ToAddress(hash160);
}
string strDescription = _("To: ");
CRITICAL_BLOCK(cs_mapAddressBook)
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strDescription += mapAddressBook[strAddress] + " ";
strDescription += strAddress;
if (!mapValue["message"].empty())
{
if (!strDescription.empty())
strDescription += " - ";
strDescription += mapValue["message"];
}
int64 nValue = txout.nValue;
if (nTxFee > 0)
{
nValue += nTxFee;
nTxFee = 0;
}
InsertLine(fNew, nIndex, hash, strprintf("%s-%d", strSort.c_str(), nOut),
strStatus,
nTime ? DateTimeStr(nTime) : "",
SingleLine(strDescription),
FormatMoney(-nValue, true),
"");
wtx.nLinesDisplayed++;
}
}
else
{
//
// Mixed debit transaction, can't break down payees
//
bool fAllMine = true;
foreach(const CTxOut& txout, wtx.vout)
fAllMine = fAllMine && txout.IsMine();
foreach(const CTxIn& txin, wtx.vin)
fAllMine = fAllMine && txin.IsMine();
InsertLine(fNew, nIndex, hash, strSort,
strStatus,
nTime ? DateTimeStr(nTime) : "",
"",
FormatMoney(nNet, true),
"");
}
}
return true;
}
void CMainFrame::RefreshListCtrl()
{
fRefreshListCtrl = true;
::wxWakeUpIdle();
}
void CMainFrame::OnIdle(wxIdleEvent& event)
{
if (fRefreshListCtrl)
{
// Collect list of wallet transactions and sort newest first
bool fEntered = false;
vector<pair<unsigned int, uint256> > vSorted;
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
printf("RefreshListCtrl starting\n");
fEntered = true;
fRefreshListCtrl = false;
vWalletUpdated.clear();
// Do the newest transactions first
vSorted.reserve(mapWallet.size());
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
unsigned int nTime = UINT_MAX - wtx.GetTxTime();
vSorted.push_back(make_pair(nTime, (*it).first));
}
m_listCtrl->DeleteAllItems();
}
if (!fEntered)
return;
sort(vSorted.begin(), vSorted.end());
// Fill list control
for (int i = 0; i < vSorted.size();)
{
if (fShutdown)
return;
bool fEntered = false;
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
fEntered = true;
uint256& hash = vSorted[i++].second;
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
if (mi != mapWallet.end())
InsertTransaction((*mi).second, true);
}
if (!fEntered || i == 100 || i % 500 == 0)
wxYield();
}
printf("RefreshListCtrl done\n");
// Update transaction total display
MainFrameRepaint();
}
else
{
// Check for time updates
static int64 nLastTime;
if (GetTime() > nLastTime + 30)
{
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
nLastTime = GetTime();
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx& wtx = (*it).second;
if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
InsertTransaction(wtx, false);
}
}
}
}
}
void CMainFrame::RefreshStatusColumn()
{
static int nLastTop;
static CBlockIndex* pindexLastBest;
static unsigned int nLastRefreshed;
int nTop = max((int)m_listCtrl->GetTopItem(), 0);
if (nTop == nLastTop && pindexLastBest == pindexBest)
return;
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
int nStart = nTop;
int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
{
// If no updates, only need to do the part that moved onto the screen
if (nStart >= nLastTop && nStart < nLastTop + 100)
nStart = nLastTop + 100;
if (nEnd >= nLastTop && nEnd < nLastTop + 100)
nEnd = nLastTop;
}
nLastTop = nTop;
pindexLastBest = pindexBest;
nLastRefreshed = nListViewUpdated;
for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
{
uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
if (mi == mapWallet.end())
{
printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
continue;
}
CWalletTx& wtx = (*mi).second;
if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
{
if (!InsertTransaction(wtx, false, nIndex))
m_listCtrl->DeleteItem(nIndex--);
}
else
m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
}
}
}
void CMainFrame::OnPaint(wxPaintEvent& event)
{
event.Skip();
if (fRefresh)
{
fRefresh = false;
Refresh();
}
}
unsigned int nNeedRepaint = 0;
unsigned int nLastRepaint = 0;
int64 nLastRepaintTime = 0;
int64 nRepaintInterval = 500;
void ThreadDelayedRepaint(void* parg)
{
while (!fShutdown)
{
if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
{
nLastRepaint = nNeedRepaint;
if (pframeMain)
{
printf("DelayedRepaint\n");
wxPaintEvent event;
pframeMain->fRefresh = true;
pframeMain->GetEventHandler()->AddPendingEvent(event);
}
}
Sleep(nRepaintInterval);
}
}
void MainFrameRepaint()
{
// This is called by network code that shouldn't access pframeMain
// directly because it could still be running after the UI is closed.
if (pframeMain)
{
// Don't repaint too often
static int64 nLastRepaintRequest;
if (GetTimeMillis() - nLastRepaintRequest < 100)
{
nNeedRepaint++;
return;
}
nLastRepaintRequest = GetTimeMillis();
printf("MainFrameRepaint\n");
wxPaintEvent event;
pframeMain->fRefresh = true;
pframeMain->GetEventHandler()->AddPendingEvent(event);
}
}
void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
{
// Skip lets the listctrl do the paint, we're just hooking the message
event.Skip();
if (ptaskbaricon)
ptaskbaricon->UpdateTooltip();
//
// Slower stuff
//
static int nTransactionCount;
bool fPaintedBalance = false;
if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
{
nLastRepaint = nNeedRepaint;
nLastRepaintTime = GetTimeMillis();
// Update listctrl contents
if (!vWalletUpdated.empty())
{
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
string strTop;
if (m_listCtrl->GetItemCount())
strTop = (string)m_listCtrl->GetItemText(0);
foreach(uint256 hash, vWalletUpdated)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
if (mi != mapWallet.end())
InsertTransaction((*mi).second, false);
}
vWalletUpdated.clear();
if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
m_listCtrl->ScrollList(0, INT_MIN/2);
}
}
// Balance total
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
fPaintedBalance = true;
m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
// Count hidden and multi-line transactions
nTransactionCount = 0;
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx& wtx = (*it).second;
nTransactionCount += wtx.nLinesDisplayed;
}
}
}
if (!vWalletUpdated.empty() || !fPaintedBalance)
nNeedRepaint++;
// Update status column of visible items only
RefreshStatusColumn();
// Update status bar
string strGen = "";
if (fGenerateBitcoins)
strGen = _(" Generating");
if (fGenerateBitcoins && vNodes.empty())
strGen = _("(not connected)");
m_statusBar->SetStatusText(strGen, 1);
string strStatus = strprintf(_(" %d connections %d blocks %d transactions"), vNodes.size(), nBestHeight + 1, nTransactionCount);
m_statusBar->SetStatusText(strStatus, 2);
if (fDebug && GetTime() - nThreadSocketHandlerHeartbeat > 60)
m_statusBar->SetStatusText(" ERROR: ThreadSocketHandler has stopped", 0);
// Update receiving address
string strDefaultAddress = PubKeyToAddress(vchDefaultKey);
if (m_textCtrlAddress->GetValue() != strDefaultAddress)
m_textCtrlAddress->SetValue(strDefaultAddress);
}
void UIThreadCall(boost::function0<void> fn)
{
// Call this with a function object created with bind.
// bind needs all parameters to match the function's expected types
// and all default parameters specified. Some examples:
// UIThreadCall(bind(wxBell));
// UIThreadCall(bind(wxMessageBox, wxT("Message"), wxT("Title"), wxOK, (wxWindow*)NULL, -1, -1));
// UIThreadCall(bind(&CMainFrame::OnMenuHelpAbout, pframeMain, event));
if (pframeMain)
{
wxCommandEvent event(wxEVT_UITHREADCALL);
event.SetClientData((void*)new boost::function0<void>(fn));
pframeMain->GetEventHandler()->AddPendingEvent(event);
}
}
void CMainFrame::OnUIThreadCall(wxCommandEvent& event)
{
boost::function0<void>* pfn = (boost::function0<void>*)event.GetClientData();
(*pfn)();
delete pfn;
}
void CMainFrame::OnMenuFileExit(wxCommandEvent& event)
{
// File->Exit
Close(true);
}
void CMainFrame::OnMenuOptionsGenerate(wxCommandEvent& event)
{
// Options->Generate Coins
GenerateBitcoins(event.IsChecked());
}
void CMainFrame::OnUpdateUIOptionsGenerate(wxUpdateUIEvent& event)
{
event.Check(fGenerateBitcoins);
}
void CMainFrame::OnMenuOptionsChangeYourAddress(wxCommandEvent& event)
{
// Options->Your Receiving Addresses
CAddressBookDialog dialog(this, "", CAddressBookDialog::RECEIVING, false);
if (!dialog.ShowModal())
return;
}
void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
{
// Options->Options
COptionsDialog dialog(this);
dialog.ShowModal();
}
void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event)
{
// Help->About
CAboutDialog dialog(this);
dialog.ShowModal();
}
void CMainFrame::OnButtonSend(wxCommandEvent& event)
{
// Toolbar: Send
CSendDialog dialog(this);
dialog.ShowModal();
}
void CMainFrame::OnButtonAddressBook(wxCommandEvent& event)
{
// Toolbar: Address Book
CAddressBookDialog dialogAddr(this, "", CAddressBookDialog::SENDING, false);
if (dialogAddr.ShowModal() == 2)
{
// Send
CSendDialog dialogSend(this, dialogAddr.GetSelectedAddress());
dialogSend.ShowModal();
}
}
void CMainFrame::OnSetFocusAddress(wxFocusEvent& event)
{
// Automatically select-all when entering window
event.Skip();
m_textCtrlAddress->SetSelection(-1, -1);
fOnSetFocusAddress = true;
}
void CMainFrame::OnMouseEventsAddress(wxMouseEvent& event)
{
event.Skip();
if (fOnSetFocusAddress)
m_textCtrlAddress->SetSelection(-1, -1);
fOnSetFocusAddress = false;
}
void CMainFrame::OnButtonNew(wxCommandEvent& event)
{
// Ask name
CGetTextFromUserDialog dialog(this,
_("New Receiving Address"),
_("It's good policy to use a new address for each payment you receive.\n\nLabel"),
"");
if (!dialog.ShowModal())
return;
string strName = dialog.GetValue();
// Generate new key
string strAddress = PubKeyToAddress(GenerateNewKey());
// Save
SetAddressBookName(strAddress, strName);
SetDefaultReceivingAddress(strAddress);
}
void CMainFrame::OnButtonCopy(wxCommandEvent& event)
{
// Copy address box to clipboard
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(m_textCtrlAddress->GetValue()));
wxTheClipboard->Close();
}
}
void CMainFrame::OnListItemActivated(wxListEvent& event)
{
uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
CWalletTx wtx;
CRITICAL_BLOCK(cs_mapWallet)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
if (mi == mapWallet.end())
{
printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
return;
}
wtx = (*mi).second;
}
CTxDetailsDialog dialog(this, wtx);
dialog.ShowModal();
//CTxDetailsDialog* pdialog = new CTxDetailsDialog(this, wtx);
//pdialog->Show();
}
//////////////////////////////////////////////////////////////////////////////
//
// CTxDetailsDialog
//
CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetailsDialogBase(parent)
{
CRITICAL_BLOCK(cs_mapAddressBook)
{
string strHTML;
strHTML.reserve(4000);
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
int64 nTime = wtx.GetTxTime();
int64 nCredit = wtx.GetCredit();
int64 nDebit = wtx.GetDebit();
int64 nNet = nCredit - nDebit;
strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
int nRequests = wtx.GetRequestCount();
if (nRequests != -1)
{
if (nRequests == 0)
strHTML += _(", has not been successfully broadcast yet");
else if (nRequests == 1)
strHTML += strprintf(_(", broadcast through %d node"), nRequests);
else
strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
}
strHTML += "<br>";
strHTML += _("<b>Date:</b> ") + (nTime ? DateTimeStr(nTime) : "") + "<br>";
//
// From
//
if (wtx.IsCoinBase())
{
strHTML += _("<b>Source:</b> Generated<br>");
}
else if (!wtx.mapValue["from"].empty())
{
// Online transaction
if (!wtx.mapValue["from"].empty())
strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
}
else
{
// Offline transaction
if (nNet > 0)
{
// Credit
foreach(const CTxOut& txout, wtx.vout)
{
if (txout.IsMine())
{
vector<unsigned char> vchPubKey;
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
{
string strAddress = PubKeyToAddress(vchPubKey);
if (mapAddressBook.count(strAddress))
{
strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
strHTML += _("<b>To:</b> ");
strHTML += HtmlEscape(strAddress);
if (!mapAddressBook[strAddress].empty())
strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")";
else
strHTML += _(" (yours)");
strHTML += "<br>";
}
}
break;
}
}
}
}
//
// To
//
string strAddress;
if (!wtx.mapValue["to"].empty())
{
// Online transaction
strAddress = wtx.mapValue["to"];
strHTML += _("<b>To:</b> ");
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strHTML += mapAddressBook[strAddress] + " ";
strHTML += HtmlEscape(strAddress) + "<br>";
}
//
// Amount
//
if (wtx.IsCoinBase() && nCredit == 0)
{
//
// Coinbase
//
int64 nUnmatured = 0;
foreach(const CTxOut& txout, wtx.vout)
nUnmatured += txout.GetCredit();
strHTML += _("<b>Credit:</b> ");
if (wtx.IsInMainChain())
strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
else
strHTML += _("(not accepted)");
strHTML += "<br>";
}
else if (nNet > 0)
{
//
// Credit
//
strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
}
else
{
bool fAllFromMe = true;
foreach(const CTxIn& txin, wtx.vin)
fAllFromMe = fAllFromMe && txin.IsMine();
bool fAllToMe = true;
foreach(const CTxOut& txout, wtx.vout)
fAllToMe = fAllToMe && txout.IsMine();
if (fAllFromMe)
{
//
// Debit
//
foreach(const CTxOut& txout, wtx.vout)
{
if (txout.IsMine())
continue;
if (wtx.mapValue["to"].empty())
{
// Offline transaction
uint160 hash160;
if (ExtractHash160(txout.scriptPubKey, hash160))
{
string strAddress = Hash160ToAddress(hash160);
strHTML += _("<b>To:</b> ");
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
strHTML += mapAddressBook[strAddress] + " ";
strHTML += strAddress;
strHTML += "<br>";
}
}
strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
}
if (fAllToMe)
{
// Payment to self
/// issue: can't tell which is the payment and which is the change anymore
//int64 nValue = wtx.vout[0].nValue;
//strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
//strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
}
int64 nTxFee = nDebit - wtx.GetValueOut();
if (nTxFee > 0)
strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
}
else
{
//
// Mixed debit transaction
//
foreach(const CTxIn& txin, wtx.vin)
if (txin.IsMine())
strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
foreach(const CTxOut& txout, wtx.vout)
if (txout.IsMine())
strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>";
}
}
strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
//
// Message
//
if (!wtx.mapValue["message"].empty())
strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
if (wtx.IsCoinBase())
strHTML += string() + "<br>" + _("Generated coins must wait 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, it will change to \"not accepted\" and not be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
//
// Debug view
//
if (fDebug)
{
strHTML += "<hr><br>debug print<br><br>";
foreach(const CTxIn& txin, wtx.vin)
if (txin.IsMine())
strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
foreach(const CTxOut& txout, wtx.vout)
if (txout.IsMine())
strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
strHTML += "<b>Inputs:</b><br>";
CRITICAL_BLOCK(cs_mapWallet)
{
foreach(const CTxIn& txin, wtx.vin)
{
COutPoint prevout = txin.prevout;
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size())
{
strHTML += HtmlEscape(prev.ToString(), true);
strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";
strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
}
}
}
}
strHTML += "<br><hr><br><b>Transaction:</b><br>";
strHTML += HtmlEscape(wtx.ToString(), true);
}
strHTML += "</font></html>";
string(strHTML.begin(), strHTML.end()).swap(strHTML);
m_htmlWin->SetPage(strHTML);
m_buttonOK->SetFocus();
}
}
void CTxDetailsDialog::OnButtonOK(wxCommandEvent& event)
{
Close();
//Destroy();
}
//////////////////////////////////////////////////////////////////////////////
//
// COptionsDialog
//
COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
{
// Set up list box of page choices
m_listBox->Append(_("Main"));
//m_listBox->Append(_("Test 2"));
m_listBox->SetSelection(0);
SelectPage(0);
#ifndef __WXMSW__
m_checkBoxMinimizeOnClose->SetLabel(_("&Minimize on close"));
m_checkBoxStartOnSystemStartup->Enable(false); // not implemented yet
#endif
// Init values
m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
m_checkBoxLimitProcessors->SetValue(fLimitProcessors);
m_spinCtrlLimitProcessors->Enable(fLimitProcessors);
m_spinCtrlLimitProcessors->SetValue(nLimitProcessors);
int nProcessors = wxThread::GetCPUCount();
if (nProcessors < 1)
nProcessors = 999;
m_spinCtrlLimitProcessors->SetRange(1, nProcessors);
m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
m_checkBoxUseProxy->SetValue(fUseProxy);
m_textCtrlProxyIP->Enable(fUseProxy);
m_textCtrlProxyPort->Enable(fUseProxy);
m_staticTextProxyIP->Enable(fUseProxy);
m_staticTextProxyPort->Enable(fUseProxy);
m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
m_buttonOK->SetFocus();
}
void COptionsDialog::SelectPage(int nPage)
{
m_panelMain->Show(nPage == 0);
m_panelTest2->Show(nPage == 1);
m_scrolledWindow->Layout();
m_scrolledWindow->SetScrollbars(0, 0, 0, 0, 0, 0);
}
void COptionsDialog::OnListBox(wxCommandEvent& event)
{
SelectPage(event.GetSelection());
}
void COptionsDialog::OnKillFocusTransactionFee(wxFocusEvent& event)
{
event.Skip();
int64 nTmp = nTransactionFee;
ParseMoney(m_textCtrlTransactionFee->GetValue(), nTmp);
m_textCtrlTransactionFee->SetValue(FormatMoney(nTmp));
}
void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)
{
m_spinCtrlLimitProcessors->Enable(event.IsChecked());
}
void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
{
m_textCtrlProxyIP->Enable(event.IsChecked());
m_textCtrlProxyPort->Enable(event.IsChecked());
m_staticTextProxyIP->Enable(event.IsChecked());
m_staticTextProxyPort->Enable(event.IsChecked());
}
CAddress COptionsDialog::GetProxyAddr()
{
// Be careful about byte order, addr.ip and addr.port are big endian
CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
if (addr.ip == INADDR_NONE)
addr.ip = addrProxy.ip;
int nPort = atoi(m_textCtrlProxyPort->GetValue());
addr.port = htons(nPort);
if (nPort <= 0 || nPort > USHRT_MAX)
addr.port = addrProxy.port;
return addr;
}
void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
{
event.Skip();
m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
}
void COptionsDialog::OnButtonOK(wxCommandEvent& event)
{
OnButtonApply(event);
Close();
}
void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
{
Close();
}
void COptionsDialog::OnButtonApply(wxCommandEvent& event)
{
CWalletDB walletdb;
int64 nPrevTransactionFee = nTransactionFee;
if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
walletdb.WriteSetting("nTransactionFee", nTransactionFee);
int nPrevMaxProc = (fLimitProcessors ? nLimitProcessors : INT_MAX);
if (fLimitProcessors != m_checkBoxLimitProcessors->GetValue())
{
fLimitProcessors = m_checkBoxLimitProcessors->GetValue();
walletdb.WriteSetting("fLimitProcessors", fLimitProcessors);
}
if (nLimitProcessors != m_spinCtrlLimitProcessors->GetValue())
{
nLimitProcessors = m_spinCtrlLimitProcessors->GetValue();
walletdb.WriteSetting("nLimitProcessors", nLimitProcessors);
}
if (fGenerateBitcoins && (fLimitProcessors ? nLimitProcessors : INT_MAX) > nPrevMaxProc)
GenerateBitcoins(fGenerateBitcoins);
if (fTmpStartOnSystemStartup != m_checkBoxStartOnSystemStartup->GetValue())
{
fTmpStartOnSystemStartup = m_checkBoxStartOnSystemStartup->GetValue();
SetStartOnSystemStartup(fTmpStartOnSystemStartup);
}
if (fMinimizeToTray != m_checkBoxMinimizeToTray->GetValue())
{
fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
}
if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())
{
fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
}
fUseProxy = m_checkBoxUseProxy->GetValue();
walletdb.WriteSetting("fUseProxy", fUseProxy);
addrProxy = GetProxyAddr();
walletdb.WriteSetting("addrProxy", addrProxy);
}
//////////////////////////////////////////////////////////////////////////////
//
// CAboutDialog
//
CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
{
m_staticTextVersion->SetLabel(strprintf(_("version 0.%d.%d beta"), VERSION/100, VERSION%100));
// Change (c) into UTF-8 or ANSI copyright symbol
wxString str = m_staticTextMain->GetLabel();
#if wxUSE_UNICODE
str.Replace("(c)", wxString::FromUTF8("\xC2\xA9"));
#else
str.Replace("(c)", "\xA9");
#endif
m_staticTextMain->SetLabel(str);
#ifndef __WXMSW__
// Resize on Linux to make the window fit the text.
// The text was wrapped manually rather than using the Wrap setting because
// the wrap would be too small on Linux and it can't be changed at this point.
wxFont fontTmp = m_staticTextMain->GetFont();
if (fontTmp.GetPointSize() > 8);
fontTmp.SetPointSize(8);
m_staticTextMain->SetFont(fontTmp);
SetSize(GetSize().GetWidth() + 44, GetSize().GetHeight() + 10);
#endif
}
void CAboutDialog::OnButtonOK(wxCommandEvent& event)
{
Close();
}
//////////////////////////////////////////////////////////////////////////////
//
// CSendDialog
//
CSendDialog::CSendDialog(wxWindow* parent, const wxString& strAddress) : CSendDialogBase(parent)
{
// Init
m_textCtrlAddress->SetValue(strAddress);
m_choiceTransferType->SetSelection(0);
m_bitmapCheckMark->Show(false);
fEnabledPrev = true;
m_textCtrlAddress->SetFocus();
//// todo: should add a display of your balance for convenience
#ifndef __WXMSW__
wxFont fontTmp = m_staticTextInstructions->GetFont();
if (fontTmp.GetPointSize() > 9);
fontTmp.SetPointSize(9);
m_staticTextInstructions->SetFont(fontTmp);
SetSize(725, 380);
#endif
// Set Icon
wxIcon iconSend;
iconSend.CopyFromBitmap(wxBitmap(send16noshadow_xpm));
SetIcon(iconSend);
wxCommandEvent event;
OnTextAddress(event);
// Fixup the tab order
m_buttonPaste->MoveAfterInTabOrder(m_buttonCancel);
m_buttonAddress->MoveAfterInTabOrder(m_buttonPaste);
this->Layout();
}
void CSendDialog::OnTextAddress(wxCommandEvent& event)
{
// Check mark
event.Skip();
bool fBitcoinAddress = IsValidBitcoinAddress(m_textCtrlAddress->GetValue());
m_bitmapCheckMark->Show(fBitcoinAddress);
// Grey out message if bitcoin address
bool fEnable = !fBitcoinAddress;
m_staticTextFrom->Enable(fEnable);
m_textCtrlFrom->Enable(fEnable);
m_staticTextMessage->Enable(fEnable);
m_textCtrlMessage->Enable(fEnable);
m_textCtrlMessage->SetBackgroundColour(wxSystemSettings::GetColour(fEnable ? wxSYS_COLOUR_WINDOW : wxSYS_COLOUR_BTNFACE));
if (!fEnable && fEnabledPrev)
{
strFromSave = m_textCtrlFrom->GetValue();
strMessageSave = m_textCtrlMessage->GetValue();
m_textCtrlFrom->SetValue(_("Will appear as \"From: Unknown\""));
m_textCtrlMessage->SetValue(_("Can't include a message when sending to a Bitcoin address"));
}
else if (fEnable && !fEnabledPrev)
{
m_textCtrlFrom->SetValue(strFromSave);
m_textCtrlMessage->SetValue(strMessageSave);
}
fEnabledPrev = fEnable;
}
void CSendDialog::OnKillFocusAmount(wxFocusEvent& event)
{
// Reformat the amount
event.Skip();
if (m_textCtrlAmount->GetValue().Trim().empty())
return;
int64 nTmp;
if (ParseMoney(m_textCtrlAmount->GetValue(), nTmp))
m_textCtrlAmount->SetValue(FormatMoney(nTmp));
}
void CSendDialog::OnButtonAddressBook(wxCommandEvent& event)
{
// Open address book
CAddressBookDialog dialog(this, m_textCtrlAddress->GetValue(), CAddressBookDialog::SENDING, true);
if (dialog.ShowModal())
m_textCtrlAddress->SetValue(dialog.GetSelectedAddress());
}
void CSendDialog::OnButtonPaste(wxCommandEvent& event)
{
// Copy clipboard to address box
if (wxTheClipboard->Open())
{
if (wxTheClipboard->IsSupported(wxDF_TEXT))
{
wxTextDataObject data;
wxTheClipboard->GetData(data);
m_textCtrlAddress->SetValue(data.GetText());
}
wxTheClipboard->Close();
}
}
void CSendDialog::OnButtonSend(wxCommandEvent& event)
{
CWalletTx wtx;
string strAddress = (string)m_textCtrlAddress->GetValue();
// Parse amount
int64 nValue = 0;
if (!ParseMoney(m_textCtrlAmount->GetValue(), nValue) || nValue <= 0)
{
wxMessageBox(_("Error in amount "), _("Send Coins"));
return;
}
if (nValue > GetBalance())
{
wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
return;
}
if (nValue + nTransactionFee > GetBalance())
{
wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
return;
}
// Parse bitcoin address
uint160 hash160;
bool fBitcoinAddress = AddressToHash160(strAddress, hash160);
if (fBitcoinAddress)
{
// Send to bitcoin address
CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
string strError = SendMoney(scriptPubKey, nValue, wtx, true);
if (strError == "")
wxMessageBox(_("Payment sent "), _("Sending..."));
else if (strError != "ABORTED")
wxMessageBox(strError + " ", _("Sending..."));
}
else
{
// Parse IP address
CAddress addr(strAddress);
if (!addr.IsValid())
{
wxMessageBox(_("Invalid address "), _("Send Coins"));
return;
}
// Message
wtx.mapValue["to"] = strAddress;
wtx.mapValue["from"] = m_textCtrlFrom->GetValue();
wtx.mapValue["message"] = m_textCtrlMessage->GetValue();
// Send to IP address
CSendingDialog* pdialog = new CSendingDialog(this, addr, nValue, wtx);
if (!pdialog->ShowModal())
return;
}
CRITICAL_BLOCK(cs_mapAddressBook)
if (!mapAddressBook.count(strAddress))
SetAddressBookName(strAddress, "");
EndModal(true);
}
void CSendDialog::OnButtonCancel(wxCommandEvent& event)
{
// Cancel
EndModal(false);
}
//////////////////////////////////////////////////////////////////////////////
//
// CSendingDialog
//
CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 nPriceIn, const CWalletTx& wtxIn) : CSendingDialogBase(NULL) // we have to give null so parent can't destroy us
{
addr = addrIn;
nPrice = nPriceIn;
wtx = wtxIn;
start = wxDateTime::UNow();
memset(pszStatus, 0, sizeof(pszStatus));
fCanCancel = true;
fAbort = false;
fSuccess = false;
fUIDone = false;
fWorkDone = false;
#ifndef __WXMSW__
SetSize(1.2 * GetSize().GetWidth(), 1.08 * GetSize().GetHeight());
#endif
SetTitle(strprintf(_("Sending %s to %s"), FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
m_textCtrlStatus->SetValue("");
CreateThread(SendingDialogStartTransfer, this);
}
CSendingDialog::~CSendingDialog()
{
printf("~CSendingDialog()\n");
}
void CSendingDialog::Close()
{
// Last one out turn out the lights.
// fWorkDone signals that work side is done and UI thread should call destroy.
// fUIDone signals that UI window has closed and work thread should call destroy.
// This allows the window to disappear and end modality when cancelled
// without making the user wait for ConnectNode to return. The dialog object
// hangs around in the background until the work thread exits.
if (IsModal())
EndModal(fSuccess);
else
Show(false);
if (fWorkDone)
Destroy();
else
fUIDone = true;
}
void CSendingDialog::OnClose(wxCloseEvent& event)
{
if (!event.CanVeto() || fWorkDone || fAbort || !fCanCancel)
{
Close();
}
else
{
event.Veto();
wxCommandEvent cmdevent;
OnButtonCancel(cmdevent);
}
}
void CSendingDialog::OnButtonOK(wxCommandEvent& event)
{
if (fWorkDone)
Close();
}
void CSendingDialog::OnButtonCancel(wxCommandEvent& event)
{
if (fCanCancel)
fAbort = true;
}
void CSendingDialog::OnPaint(wxPaintEvent& event)
{
event.Skip();
if (strlen(pszStatus) > 130)
m_textCtrlStatus->SetValue(string("\n") + pszStatus);
else
m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
m_staticTextSending->SetFocus();
if (!fCanCancel)
m_buttonCancel->Enable(false);
if (fWorkDone)
{
m_buttonOK->Enable(true);
m_buttonOK->SetFocus();
m_buttonCancel->Enable(false);
}
if (fAbort && fCanCancel && IsShown())
{
strcpy(pszStatus, _("CANCELLED"));
m_buttonOK->Enable(true);
m_buttonOK->SetFocus();
m_buttonCancel->Enable(false);
m_buttonCancel->SetLabel(_("Cancelled"));
Close();
wxMessageBox(_("Transfer cancelled "), _("Sending..."), wxOK, this);
}
}
//
// Everything from here on is not in the UI thread and must only communicate
// with the rest of the dialog through variables and calling repaint.
//
void CSendingDialog::Repaint()
{
Refresh();
wxPaintEvent event;
GetEventHandler()->AddPendingEvent(event);
}
bool CSendingDialog::Status()
{
if (fUIDone)
{
Destroy();
return false;
}
if (fAbort && fCanCancel)
{
memset(pszStatus, 0, 10);
strcpy(pszStatus, _("CANCELLED"));
Repaint();
fWorkDone = true;
return false;
}
return true;
}
bool CSendingDialog::Status(const string& str)
{
if (!Status())
return false;
// This can be read by the UI thread at any time,
// so copy in a way that can be read cleanly at all times.
memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
Repaint();
return true;
}
bool CSendingDialog::Error(const string& str)
{
fCanCancel = false;
fWorkDone = true;
Status(string(_("Error: ")) + str);
return false;
}
void SendingDialogStartTransfer(void* parg)
{
((CSendingDialog*)parg)->StartTransfer();
}
void CSendingDialog::StartTransfer()
{
// Make sure we have enough money
if (nPrice + nTransactionFee > GetBalance())
{
Error(_("Insufficient funds"));
return;
}
// We may have connected already for product details
if (!Status(_("Connecting...")))
return;
CNode* pnode = ConnectNode(addr, 15 * 60);
if (!pnode)
{
Error(_("Unable to connect"));
return;
}
// Send order to seller, with response going to OnReply2 via event handler
if (!Status(_("Requesting public key...")))
return;
pnode->PushRequest("checkorder", wtx, SendingDialogOnReply2, this);
}
void SendingDialogOnReply2(void* parg, CDataStream& vRecv)
{
((CSendingDialog*)parg)->OnReply2(vRecv);
}
void CSendingDialog::OnReply2(CDataStream& vRecv)
{
if (!Status(_("Received public key...")))
return;
CScript scriptPubKey;
int nRet;
try
{
vRecv >> nRet;
if (nRet > 0)
{
string strMessage;
vRecv >> strMessage;
Error(_("Transfer was not accepted"));
//// todo: enlarge the window and enable a hidden white box to put seller's message
return;
}
vRecv >> scriptPubKey;
}
catch (...)
{
//// what do we want to do about this?
Error(_("Invalid response received"));
return;
}
// Pause to give the user a chance to cancel
while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
{
Sleep(200);
if (!Status())
return;
}
CRITICAL_BLOCK(cs_main)
{
// Pay
if (!Status(_("Creating transaction...")))
return;
if (nPrice + nTransactionFee > GetBalance())
{
Error(_("Insufficient funds"));
return;
}
CKey key;
int64 nFeeRequired;
if (!CreateTransaction(scriptPubKey, nPrice, wtx, key, nFeeRequired))
{
if (nPrice + nFeeRequired > GetBalance())
Error(strprintf(_("This is an oversized transaction that requires a transaction fee of %s"), FormatMoney(nFeeRequired).c_str()));
else
Error(_("Transaction creation failed"));
return;
}
// Transaction fee
if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
{
Error(_("Transaction aborted"));
return;
}
// Make sure we're still connected
CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
if (!pnode)
{
Error(_("Lost connection, transaction cancelled"));
return;
}
// Last chance to cancel
Sleep(50);
if (!Status())
return;
fCanCancel = false;
if (fAbort)
{
fCanCancel = true;
if (!Status())
return;
fCanCancel = false;
}
if (!Status(_("Sending payment...")))
return;
// Commit
if (!CommitTransaction(wtx, key))
{
Error(_("The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."));
return;
}
// Send payment tx to seller, with response going to OnReply3 via event handler
CWalletTx wtxSend = wtx;
wtxSend.fFromMe = false;
pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this);
Status(_("Waiting for confirmation..."));
MainFrameRepaint();
}
}
void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
{
((CSendingDialog*)parg)->OnReply3(vRecv);
}
void CSendingDialog::OnReply3(CDataStream& vRecv)
{
int nRet;
try
{
vRecv >> nRet;
if (nRet > 0)
{
Error(_("The payment was sent, but the recipient was unable to verify it.\n"
"The transaction is recorded and will credit to the recipient,\n"
"but the comment information will be blank."));
return;
}
}
catch (...)
{
//// what do we want to do about this?
Error(_("Payment was sent, but an invalid response was received"));
return;
}
fSuccess = true;
fWorkDone = true;
Status(_("Payment completed"));
}
//////////////////////////////////////////////////////////////////////////////
//
// CAddressBookDialog
//
CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInitSelected, int nPageIn, bool fDuringSendIn) : CAddressBookDialogBase(parent)
{
// Set initially selected page
wxNotebookEvent event;
event.SetSelection(nPageIn);
OnNotebookPageChanged(event);
m_notebook->ChangeSelection(nPageIn);
fDuringSend = fDuringSendIn;
if (!fDuringSend)
m_buttonCancel->Show(false);
// Set Icon
wxIcon iconAddressBook;
iconAddressBook.CopyFromBitmap(wxBitmap(addressbook16_xpm));
SetIcon(iconAddressBook);
// Init column headers
m_listCtrlSending->InsertColumn(0, _("Name"), wxLIST_FORMAT_LEFT, 200);
m_listCtrlSending->InsertColumn(1, _("Address"), wxLIST_FORMAT_LEFT, 350);
m_listCtrlSending->SetFocus();
m_listCtrlReceiving->InsertColumn(0, _("Label"), wxLIST_FORMAT_LEFT, 200);
m_listCtrlReceiving->InsertColumn(1, _("Bitcoin Address"), wxLIST_FORMAT_LEFT, 350);
m_listCtrlReceiving->SetFocus();
// Fill listctrl with address book data
CRITICAL_BLOCK(cs_mapKeys)
CRITICAL_BLOCK(cs_mapAddressBook)
{
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
foreach(const PAIRTYPE(string, string)& item, mapAddressBook)
{
string strAddress = item.first;
string strName = item.second;
uint160 hash160;
bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
wxListCtrl* plistCtrl = fMine ? m_listCtrlReceiving : m_listCtrlSending;
int nIndex = InsertLine(plistCtrl, strName, strAddress);
if (strAddress == (fMine ? strDefaultReceiving : string(strInitSelected)))
plistCtrl->SetItemState(nIndex, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
}
}
}
wxString CAddressBookDialog::GetSelectedAddress()
{
int nIndex = GetSelection(m_listCtrl);
if (nIndex == -1)
return "";
return GetItemText(m_listCtrl, nIndex, 1);
}
wxString CAddressBookDialog::GetSelectedSendingAddress()
{
int nIndex = GetSelection(m_listCtrlSending);
if (nIndex == -1)
return "";
return GetItemText(m_listCtrlSending, nIndex, 1);
}
wxString CAddressBookDialog::GetSelectedReceivingAddress()
{
int nIndex = GetSelection(m_listCtrlReceiving);
if (nIndex == -1)
return "";
return GetItemText(m_listCtrlReceiving, nIndex, 1);
}
void CAddressBookDialog::OnNotebookPageChanged(wxNotebookEvent& event)
{
event.Skip();
nPage = event.GetSelection();
if (nPage == SENDING)
m_listCtrl = m_listCtrlSending;
else if (nPage == RECEIVING)
m_listCtrl = m_listCtrlReceiving;
m_buttonDelete->Show(nPage == SENDING);
m_buttonCopy->Show(nPage == RECEIVING);
this->Layout();
m_listCtrl->SetFocus();
}
void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
{
// Update address book with edited name
event.Skip();
if (event.IsEditCancelled())
return;
string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
SetAddressBookName(strAddress, string(event.GetText()));
pframeMain->RefreshListCtrl();
}
void CAddressBookDialog::OnListItemSelected(wxListEvent& event)
{
event.Skip();
if (nPage == RECEIVING)
SetDefaultReceivingAddress((string)GetSelectedReceivingAddress());
}
void CAddressBookDialog::OnListItemActivated(wxListEvent& event)
{
event.Skip();
if (fDuringSend)
{
// Doubleclick returns selection
EndModal(GetSelectedAddress() != "" ? 2 : 0);
return;
}
// Doubleclick edits item
wxCommandEvent event2;
OnButtonEdit(event2);
}
void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
{
if (nPage != SENDING)
return;
for (int nIndex = m_listCtrl->GetItemCount()-1; nIndex >= 0; nIndex--)
{
if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
{
string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
CWalletDB().EraseName(strAddress);
m_listCtrl->DeleteItem(nIndex);
}
}
pframeMain->RefreshListCtrl();
}
void CAddressBookDialog::OnButtonCopy(wxCommandEvent& event)
{
// Copy address box to clipboard
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(GetSelectedAddress()));
wxTheClipboard->Close();
}
}
bool CAddressBookDialog::CheckIfMine(const string& strAddress, const string& strTitle)
{
uint160 hash160;
bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
if (fMine)
wxMessageBox(_("This is one of your own addresses for receiving payments and cannot be entered in the address book. "), strTitle);
return fMine;
}
void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
{
int nIndex = GetSelection(m_listCtrl);
if (nIndex == -1)
return;
string strName = (string)m_listCtrl->GetItemText(nIndex);
string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
string strAddressOrg = strAddress;
if (nPage == SENDING)
{
// Ask name and address
do
{
CGetTextFromUserDialog dialog(this, _("Edit Address"), _("Name"), strName, _("Address"), strAddress);
if (!dialog.ShowModal())
return;
strName = dialog.GetValue1();
strAddress = dialog.GetValue2();
}
while (CheckIfMine(strAddress, _("Edit Address")));
}
else if (nPage == RECEIVING)
{
// Ask name
CGetTextFromUserDialog dialog(this, _("Edit Address Label"), _("Label"), strName);
if (!dialog.ShowModal())
return;
strName = dialog.GetValue();
}
// Write back
if (strAddress != strAddressOrg)
CWalletDB().EraseName(strAddressOrg);
SetAddressBookName(strAddress, strName);
m_listCtrl->SetItem(nIndex, 1, strAddress);
m_listCtrl->SetItemText(nIndex, strName);
pframeMain->RefreshListCtrl();
}
void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
{
string strName;
string strAddress;
if (nPage == SENDING)
{
// Ask name and address
do
{
CGetTextFromUserDialog dialog(this, _("Add Address"), _("Name"), strName, _("Address"), strAddress);
if (!dialog.ShowModal())
return;
strName = dialog.GetValue1();
strAddress = dialog.GetValue2();
}
while (CheckIfMine(strAddress, _("Add Address")));
}
else if (nPage == RECEIVING)
{
// Ask name
CGetTextFromUserDialog dialog(this,
_("New Receiving Address"),
_("It's good policy to use a new address for each payment you receive.\n\nLabel"),
"");
if (!dialog.ShowModal())
return;
strName = dialog.GetValue();
// Generate new key
strAddress = PubKeyToAddress(GenerateNewKey());
}
// Add to list and select it
SetAddressBookName(strAddress, strName);
int nIndex = InsertLine(m_listCtrl, strName, strAddress);
SetSelection(m_listCtrl, nIndex);
m_listCtrl->SetFocus();
if (nPage == SENDING)
pframeMain->RefreshListCtrl();
}
void CAddressBookDialog::OnButtonOK(wxCommandEvent& event)
{
// OK
EndModal(GetSelectedAddress() != "" ? 1 : 0);
}
void CAddressBookDialog::OnButtonCancel(wxCommandEvent& event)
{
// Cancel
EndModal(0);
}
void CAddressBookDialog::OnClose(wxCloseEvent& event)
{
// Close
EndModal(0);
}
//////////////////////////////////////////////////////////////////////////////
//
// CMyTaskBarIcon
//
enum
{
ID_TASKBAR_RESTORE = 10001,
ID_TASKBAR_OPTIONS,
ID_TASKBAR_GENERATE,
ID_TASKBAR_EXIT,
};
BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)
EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
END_EVENT_TABLE()
void CMyTaskBarIcon::Show(bool fShow)
{
static char pszPrevTip[200];
if (fShow)
{
string strTooltip = _("Bitcoin");
if (fGenerateBitcoins)
strTooltip = _("Bitcoin - Generating");
if (fGenerateBitcoins && vNodes.empty())
strTooltip = _("Bitcoin - (not connected)");
// Optimization, only update when changed, using char array to be reentrant
if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
{
strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
#ifdef __WXMSW__
SetIcon(wxICON(bitcoin), strTooltip);
#else
SetIcon(bitcoin20_xpm, strTooltip);
#endif
}
}
else
{
strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
RemoveIcon();
}
}
void CMyTaskBarIcon::Hide()
{
Show(false);
}
void CMyTaskBarIcon::OnLeftButtonDClick(wxTaskBarIconEvent& event)
{
Restore();
}
void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
{
Restore();
}
void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
{
// Since it's modal, get the main window to do it
wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_PREFERENCES);
pframeMain->GetEventHandler()->AddPendingEvent(event2);
}
void CMyTaskBarIcon::Restore()
{
pframeMain->Show();
wxIconizeEvent event(0, false);
pframeMain->GetEventHandler()->AddPendingEvent(event);
pframeMain->Iconize(false);
pframeMain->Raise();
}
void CMyTaskBarIcon::OnMenuGenerate(wxCommandEvent& event)
{
GenerateBitcoins(event.IsChecked());
}
void CMyTaskBarIcon::OnUpdateUIGenerate(wxUpdateUIEvent& event)
{
event.Check(fGenerateBitcoins);
}
void CMyTaskBarIcon::OnMenuExit(wxCommandEvent& event)
{
pframeMain->Close(true);
}
void CMyTaskBarIcon::UpdateTooltip()
{
if (IsIconInstalled())
Show(true);
}
wxMenu* CMyTaskBarIcon::CreatePopupMenu()
{
wxMenu* pmenu = new wxMenu;
pmenu->Append(ID_TASKBAR_RESTORE, _("&Open Bitcoin"));
pmenu->Append(ID_TASKBAR_OPTIONS, _("O&ptions..."));
pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, _("&Generate Coins"))->Check(fGenerateBitcoins);
#ifndef __WXMAC_OSX__ // Mac has built-in quit menu
pmenu->AppendSeparator();
pmenu->Append(ID_TASKBAR_EXIT, _("E&xit"));
#endif
return pmenu;
}
void CreateMainWindow()
{
pframeMain = new CMainFrame(NULL);
if (mapArgs.count("-min"))
pframeMain->Iconize(true);
pframeMain->Show(true); // have to show first to get taskbar button to hide
if (fMinimizeToTray && pframeMain->IsIconized())
fClosedToTray = true;
pframeMain->Show(!fClosedToTray);
ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
CreateThread(ThreadDelayedRepaint, NULL);
}
"%file: ./ui.rc"
bitcoin ICON "rc/bitcoin.ico"
#include "wx/msw/wx.rc"
check ICON "rc/check.ico"
send16 BITMAP "rc/send16.bmp"
send16mask BITMAP "rc/send16mask.bmp"
send16masknoshadow BITMAP "rc/send16masknoshadow.bmp"
send20 BITMAP "rc/send20.bmp"
send20mask BITMAP "rc/send20mask.bmp"
addressbook16 BITMAP "rc/addressbook16.bmp"
addressbook16mask BITMAP "rc/addressbook16mask.bmp"
addressbook20 BITMAP "rc/addressbook20.bmp"
addressbook20mask BITMAP "rc/addressbook20mask.bmp"
"%file: ./uibase.h"
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Apr 16 2008)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __uibase__
#define __uibase__
#include <wx/intl.h>
#include <wx/string.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/menu.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/toolbar.h>
#include <wx/statusbr.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/panel.h>
#include <wx/choice.h>
#include <wx/listctrl.h>
#include <wx/notebook.h>
#include <wx/frame.h>
#include <wx/html/htmlwin.h>
#include <wx/dialog.h>
#include <wx/listbox.h>
#include <wx/checkbox.h>
#include <wx/spinctrl.h>
#include <wx/scrolwin.h>
#include <wx/statbmp.h>
///////////////////////////////////////////////////////////////////////////
#define wxID_MAINFRAME 1000
#define wxID_OPTIONSGENERATEBITCOINS 1001
#define wxID_BUTTONSEND 1002
#define wxID_BUTTONRECEIVE 1003
#define wxID_TEXTCTRLADDRESS 1004
#define wxID_BUTTONNEW 1005
#define wxID_BUTTONCOPY 1006
#define wxID_TRANSACTIONFEE 1007
#define wxID_PROXYIP 1008
#define wxID_PROXYPORT 1009
#define wxID_TEXTCTRLPAYTO 1010
#define wxID_BUTTONPASTE 1011
#define wxID_BUTTONADDRESSBOOK 1012
#define wxID_TEXTCTRLAMOUNT 1013
#define wxID_CHOICETRANSFERTYPE 1014
#define wxID_LISTCTRL 1015
#define wxID_BUTTONRENAME 1016
#define wxID_PANELSENDING 1017
#define wxID_LISTCTRLSENDING 1018
#define wxID_PANELRECEIVING 1019
#define wxID_LISTCTRLRECEIVING 1020
#define wxID_BUTTONDELETE 1021
#define wxID_BUTTONEDIT 1022
#define wxID_TEXTCTRL 1023
///////////////////////////////////////////////////////////////////////////////
/// Class CMainFrameBase
///////////////////////////////////////////////////////////////////////////////
class CMainFrameBase : public wxFrame
{
private:
protected:
wxMenuBar* m_menubar;
wxMenu* m_menuFile;
wxMenu* m_menuHelp;
wxToolBar* m_toolBar;
wxStaticText* m_staticText32;
wxButton* m_buttonNew;
wxButton* m_buttonCopy;
wxPanel* m_panel14;
wxStaticText* m_staticText41;
wxStaticText* m_staticTextBalance;
wxChoice* m_choiceFilter;
wxNotebook* m_notebook;
wxPanel* m_panel9;
wxPanel* m_panel91;
wxPanel* m_panel92;
wxPanel* m_panel93;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ){ event.Skip(); }
virtual void OnIconize( wxIconizeEvent& event ){ event.Skip(); }
virtual void OnIdle( wxIdleEvent& event ){ event.Skip(); }
virtual void OnMouseEvents( wxMouseEvent& event ){ event.Skip(); }
virtual void OnPaint( wxPaintEvent& event ){ event.Skip(); }
virtual void OnMenuFileExit( wxCommandEvent& event ){ event.Skip(); }
virtual void OnMenuOptionsGenerate( wxCommandEvent& event ){ event.Skip(); }
virtual void OnUpdateUIOptionsGenerate( wxUpdateUIEvent& event ){ event.Skip(); }
virtual void OnMenuOptionsChangeYourAddress( wxCommandEvent& event ){ event.Skip(); }
virtual void OnMenuOptionsOptions( wxCommandEvent& event ){ event.Skip(); }
virtual void OnMenuHelpAbout( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonSend( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonAddressBook( wxCommandEvent& event ){ event.Skip(); }
virtual void OnKeyDown( wxKeyEvent& event ){ event.Skip(); }
virtual void OnMouseEventsAddress( wxMouseEvent& event ){ event.Skip(); }
virtual void OnSetFocusAddress( wxFocusEvent& event ){ event.Skip(); }
virtual void OnButtonNew( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCopy( wxCommandEvent& event ){ event.Skip(); }
virtual void OnNotebookPageChanged( wxNotebookEvent& event ){ event.Skip(); }
virtual void OnListColBeginDrag( wxListEvent& event ){ event.Skip(); }
virtual void OnListItemActivated( wxListEvent& event ){ event.Skip(); }
virtual void OnPaintListCtrl( wxPaintEvent& event ){ event.Skip(); }
public:
wxMenu* m_menuOptions;
wxStatusBar* m_statusBar;
wxTextCtrl* m_textCtrlAddress;
wxListCtrl* m_listCtrlAll;
wxListCtrl* m_listCtrlSentReceived;
wxListCtrl* m_listCtrlSent;
wxListCtrl* m_listCtrlReceived;
CMainFrameBase( wxWindow* parent, wxWindowID id = wxID_MAINFRAME, const wxString& title = _("Bitcoin"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 723,484 ), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL );
~CMainFrameBase();
};
///////////////////////////////////////////////////////////////////////////////
/// Class CTxDetailsDialogBase
///////////////////////////////////////////////////////////////////////////////
class CTxDetailsDialogBase : public wxDialog
{
private:
protected:
wxHtmlWindow* m_htmlWin;
wxButton* m_buttonOK;
// Virtual event handlers, overide them in your derived class
virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); }
public:
CTxDetailsDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Transaction Details"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 620,450 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~CTxDetailsDialogBase();
};
///////////////////////////////////////////////////////////////////////////////
/// Class COptionsDialogBase
///////////////////////////////////////////////////////////////////////////////
class COptionsDialogBase : public wxDialog
{
private:
protected:
wxListBox* m_listBox;
wxScrolledWindow* m_scrolledWindow;
wxPanel* m_panelMain;
wxStaticText* m_staticText32;
wxStaticText* m_staticText31;
wxTextCtrl* m_textCtrlTransactionFee;
wxCheckBox* m_checkBoxLimitProcessors;
wxSpinCtrl* m_spinCtrlLimitProcessors;
wxStaticText* m_staticText35;
wxCheckBox* m_checkBoxStartOnSystemStartup;
wxCheckBox* m_checkBoxMinimizeToTray;
wxCheckBox* m_checkBoxMinimizeOnClose;
wxCheckBox* m_checkBoxUseProxy;
wxStaticText* m_staticTextProxyIP;
wxTextCtrl* m_textCtrlProxyIP;
wxStaticText* m_staticTextProxyPort;
wxTextCtrl* m_textCtrlProxyPort;
wxPanel* m_panelTest2;
wxStaticText* m_staticText321;
wxStaticText* m_staticText69;
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
wxButton* m_buttonApply;
// Virtual event handlers, overide them in your derived class
virtual void OnListBox( wxCommandEvent& event ){ event.Skip(); }
virtual void OnKillFocusTransactionFee( wxFocusEvent& event ){ event.Skip(); }
virtual void OnCheckBoxLimitProcessors( wxCommandEvent& event ){ event.Skip(); }
virtual void OnCheckBoxMinimizeToTray( wxCommandEvent& event ){ event.Skip(); }
virtual void OnCheckBoxUseProxy( wxCommandEvent& event ){ event.Skip(); }
virtual void OnKillFocusProxy( wxFocusEvent& event ){ event.Skip(); }
virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCancel( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonApply( wxCommandEvent& event ){ event.Skip(); }
public:
COptionsDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Options"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 540,360 ), long style = wxDEFAULT_DIALOG_STYLE );
~COptionsDialogBase();
};
///////////////////////////////////////////////////////////////////////////////
/// Class CAboutDialogBase
///////////////////////////////////////////////////////////////////////////////
class CAboutDialogBase : public wxDialog
{
private:
protected:
wxStaticBitmap* m_bitmap;
wxStaticText* m_staticText40;
wxStaticText* m_staticTextMain;
wxButton* m_buttonOK;
// Virtual event handlers, overide them in your derived class
virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); }
public:
wxStaticText* m_staticTextVersion;
CAboutDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("About Bitcoin"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 532,329 ), long style = wxDEFAULT_DIALOG_STYLE );
~CAboutDialogBase();
};
///////////////////////////////////////////////////////////////////////////////
/// Class CSendDialogBase
///////////////////////////////////////////////////////////////////////////////
class CSendDialogBase : public wxDialog
{
private:
protected:
wxStaticText* m_staticTextInstructions;
wxStaticBitmap* m_bitmapCheckMark;
wxStaticText* m_staticText36;
wxTextCtrl* m_textCtrlAddress;
wxButton* m_buttonPaste;
wxButton* m_buttonAddress;
wxStaticText* m_staticText19;
wxTextCtrl* m_textCtrlAmount;
wxStaticText* m_staticText20;
wxChoice* m_choiceTransferType;
wxStaticText* m_staticTextFrom;
wxTextCtrl* m_textCtrlFrom;
wxStaticText* m_staticTextMessage;
wxTextCtrl* m_textCtrlMessage;
wxButton* m_buttonSend;
wxButton* m_buttonCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnKeyDown( wxKeyEvent& event ){ event.Skip(); }
virtual void OnTextAddress( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonPaste( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonAddressBook( wxCommandEvent& event ){ event.Skip(); }
virtual void OnKillFocusAmount( wxFocusEvent& event ){ event.Skip(); }
virtual void OnButtonSend( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCancel( wxCommandEvent& event ){ event.Skip(); }
public:
CSendDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Send Coins"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 675,298 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~CSendDialogBase();
};
///////////////////////////////////////////////////////////////////////////////
/// Class CSendingDialogBase
///////////////////////////////////////////////////////////////////////////////
class CSendingDialogBase : public wxDialog
{
private:
protected:
wxStaticText* m_staticTextSending;
wxTextCtrl* m_textCtrlStatus;
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ){ event.Skip(); }
virtual void OnPaint( wxPaintEvent& event ){ event.Skip(); }
virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCancel( wxCommandEvent& event ){ event.Skip(); }
public:
CSendingDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Sending..."), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 442,151 ), long style = wxDEFAULT_DIALOG_STYLE );
~CSendingDialogBase();
};
///////////////////////////////////////////////////////////////////////////////
/// Class CYourAddressDialogBase
///////////////////////////////////////////////////////////////////////////////
class CYourAddressDialogBase : public wxDialog
{
private:
protected:
wxStaticText* m_staticText45;
wxListCtrl* m_listCtrl;
wxButton* m_buttonRename;
wxButton* m_buttonNew;
wxButton* m_buttonCopy;
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ){ event.Skip(); }
virtual void OnListEndLabelEdit( wxListEvent& event ){ event.Skip(); }
virtual void OnListItemActivated( wxListEvent& event ){ event.Skip(); }
virtual void OnListItemSelected( wxListEvent& event ){ event.Skip(); }
virtual void OnButtonRename( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonNew( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCopy( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCancel( wxCommandEvent& event ){ event.Skip(); }
public:
CYourAddressDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Your Bitcoin Addresses"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 610,390 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~CYourAddressDialogBase();
};
///////////////////////////////////////////////////////////////////////////////
/// Class CAddressBookDialogBase
///////////////////////////////////////////////////////////////////////////////
class CAddressBookDialogBase : public wxDialog
{
private:
protected:
wxNotebook* m_notebook;
wxPanel* m_panelSending;
wxStaticText* m_staticText55;
wxListCtrl* m_listCtrlSending;
wxPanel* m_panelReceiving;
wxStaticText* m_staticText45;
wxListCtrl* m_listCtrlReceiving;
wxButton* m_buttonDelete;
wxButton* m_buttonCopy;
wxButton* m_buttonEdit;
wxButton* m_buttonNew;
wxButton* m_buttonOK;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ){ event.Skip(); }
virtual void OnNotebookPageChanged( wxNotebookEvent& event ){ event.Skip(); }
virtual void OnListEndLabelEdit( wxListEvent& event ){ event.Skip(); }
virtual void OnListItemActivated( wxListEvent& event ){ event.Skip(); }
virtual void OnListItemSelected( wxListEvent& event ){ event.Skip(); }
virtual void OnButtonDelete( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCopy( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonEdit( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonNew( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCancel( wxCommandEvent& event ){ event.Skip(); }
public:
wxButton* m_buttonCancel;
CAddressBookDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Address Book"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 610,390 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~CAddressBookDialogBase();
};
///////////////////////////////////////////////////////////////////////////////
/// Class CGetTextFromUserDialogBase
///////////////////////////////////////////////////////////////////////////////
class CGetTextFromUserDialogBase : public wxDialog
{
private:
protected:
wxStaticText* m_staticTextMessage1;
wxTextCtrl* m_textCtrl1;
wxStaticText* m_staticTextMessage2;
wxTextCtrl* m_textCtrl2;
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ){ event.Skip(); }
virtual void OnKeyDown( wxKeyEvent& event ){ event.Skip(); }
virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); }
virtual void OnButtonCancel( wxCommandEvent& event ){ event.Skip(); }
public:
CGetTextFromUserDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 440,138 ), long style = wxDEFAULT_DIALOG_STYLE );
~CGetTextFromUserDialogBase();
};
#endif //__uibase__
"%file: ./uibase.cpp"
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Apr 16 2008)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "uibase.h"
#include "xpm/about.xpm"
#include "xpm/addressbook20.xpm"
#include "xpm/check.xpm"
#include "xpm/send20.xpm"
///////////////////////////////////////////////////////////////////////////
CMainFrameBase::CMainFrameBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
m_menubar = new wxMenuBar( 0 );
m_menubar->SetBackgroundColour( wxColour( 240, 240, 240 ) );
m_menuFile = new wxMenu();
wxMenuItem* m_menuFileExit;
m_menuFileExit = new wxMenuItem( m_menuFile, wxID_EXIT, wxString( _("E&xit") ) , wxEmptyString, wxITEM_NORMAL );
m_menuFile->Append( m_menuFileExit );
m_menubar->Append( m_menuFile, _("&File") );
m_menuOptions = new wxMenu();
wxMenuItem* m_menuOptionsGenerateBitcoins;
m_menuOptionsGenerateBitcoins = new wxMenuItem( m_menuOptions, wxID_OPTIONSGENERATEBITCOINS, wxString( _("&Generate Coins") ) , wxEmptyString, wxITEM_CHECK );
m_menuOptions->Append( m_menuOptionsGenerateBitcoins );
wxMenuItem* m_menuOptionsChangeYourAddress;
m_menuOptionsChangeYourAddress = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( _("&Your Receiving Addresses...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsChangeYourAddress );
wxMenuItem* m_menuOptionsOptions;
m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_PREFERENCES, wxString( _("&Options...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsOptions );
m_menubar->Append( m_menuOptions, _("&Settings") );
m_menuHelp = new wxMenu();
wxMenuItem* m_menuHelpAbout;
m_menuHelpAbout = new wxMenuItem( m_menuHelp, wxID_ABOUT, wxString( _("&About...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuHelp->Append( m_menuHelpAbout );
m_menubar->Append( m_menuHelp, _("&Help") );
this->SetMenuBar( m_menubar );
m_toolBar = this->CreateToolBar( wxTB_FLAT|wxTB_HORZ_TEXT, wxID_ANY );
m_toolBar->SetToolBitmapSize( wxSize( 20,20 ) );
m_toolBar->SetToolSeparation( 1 );
m_toolBar->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) );
m_toolBar->AddTool( wxID_BUTTONSEND, _("Send Coins"), wxBitmap( send20_xpm ), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString );
m_toolBar->AddTool( wxID_BUTTONRECEIVE, _("Address Book"), wxBitmap( addressbook20_xpm ), wxNullBitmap, wxITEM_NORMAL, wxEmptyString, wxEmptyString );
m_toolBar->Realize();
m_statusBar = this->CreateStatusBar( 1, wxST_SIZEGRIP, wxID_ANY );
m_statusBar->SetBackgroundColour( wxColour( 240, 240, 240 ) );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );
bSizer2->Add( 0, 2, 0, wxEXPAND, 5 );
wxBoxSizer* bSizer85;
bSizer85 = new wxBoxSizer( wxHORIZONTAL );
m_staticText32 = new wxStaticText( this, wxID_ANY, _("Your Bitcoin Address:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText32->Wrap( -1 );
bSizer85->Add( m_staticText32, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_textCtrlAddress = new wxTextCtrl( this, wxID_TEXTCTRLADDRESS, wxEmptyString, wxDefaultPosition, wxSize( 340,-1 ), wxTE_READONLY );
bSizer85->Add( m_textCtrlAddress, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_buttonNew = new wxButton( this, wxID_BUTTONNEW, _(" &New... "), wxDefaultPosition, wxSize( -1,-1 ), wxBU_EXACTFIT );
bSizer85->Add( m_buttonNew, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 );
m_buttonCopy = new wxButton( this, wxID_BUTTONCOPY, _(" &Copy to Clipboard "), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
bSizer85->Add( m_buttonCopy, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
bSizer85->Add( 0, 0, 0, wxEXPAND, 5 );
bSizer2->Add( bSizer85, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxHORIZONTAL );
m_panel14 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer66;
bSizer66 = new wxBoxSizer( wxHORIZONTAL );
m_staticText41 = new wxStaticText( m_panel14, wxID_ANY, _("Balance:"), wxDefaultPosition, wxSize( -1,15 ), 0 );
m_staticText41->Wrap( -1 );
bSizer66->Add( m_staticText41, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
m_staticTextBalance = new wxStaticText( m_panel14, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 120,15 ), wxALIGN_RIGHT|wxST_NO_AUTORESIZE );
m_staticTextBalance->Wrap( -1 );
m_staticTextBalance->SetFont( wxFont( 8, 70, 90, 90, false, wxEmptyString ) );
m_staticTextBalance->SetBackgroundColour( wxColour( 255, 255, 255 ) );
bSizer66->Add( m_staticTextBalance, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_panel14->SetSizer( bSizer66 );
m_panel14->Layout();
bSizer66->Fit( m_panel14 );
bSizer3->Add( m_panel14, 1, wxEXPAND|wxALIGN_BOTTOM|wxALL, 5 );
bSizer3->Add( 0, 0, 0, wxEXPAND, 5 );
wxString m_choiceFilterChoices[] = { _(" All"), _(" Sent"), _(" Received"), _(" In Progress") };
int m_choiceFilterNChoices = sizeof( m_choiceFilterChoices ) / sizeof( wxString );
m_choiceFilter = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxSize( 110,-1 ), m_choiceFilterNChoices, m_choiceFilterChoices, 0 );
m_choiceFilter->SetSelection( 0 );
m_choiceFilter->Hide();
bSizer3->Add( m_choiceFilter, 0, wxALIGN_BOTTOM|wxTOP|wxRIGHT|wxLEFT, 5 );
bSizer2->Add( bSizer3, 0, wxEXPAND, 5 );
m_notebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_panel9 = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer11;
bSizer11 = new wxBoxSizer( wxVERTICAL );
m_listCtrlAll = new wxListCtrl( m_panel9, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_DESCENDING );
bSizer11->Add( m_listCtrlAll, 1, wxEXPAND, 5 );
m_panel9->SetSizer( bSizer11 );
m_panel9->Layout();
bSizer11->Fit( m_panel9 );
m_notebook->AddPage( m_panel9, _("All Transactions"), true );
m_panel91 = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer111;
bSizer111 = new wxBoxSizer( wxVERTICAL );
m_listCtrlSentReceived = new wxListCtrl( m_panel91, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_DESCENDING );
bSizer111->Add( m_listCtrlSentReceived, 1, wxEXPAND, 5 );
m_panel91->SetSizer( bSizer111 );
m_panel91->Layout();
bSizer111->Fit( m_panel91 );
m_notebook->AddPage( m_panel91, _("Sent/Received"), false );
m_panel92 = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer112;
bSizer112 = new wxBoxSizer( wxVERTICAL );
m_listCtrlSent = new wxListCtrl( m_panel92, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_DESCENDING );
bSizer112->Add( m_listCtrlSent, 1, wxEXPAND, 5 );
m_panel92->SetSizer( bSizer112 );
m_panel92->Layout();
bSizer112->Fit( m_panel92 );
m_notebook->AddPage( m_panel92, _("Sent"), false );
m_panel93 = new wxPanel( m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer113;
bSizer113 = new wxBoxSizer( wxVERTICAL );
m_listCtrlReceived = new wxListCtrl( m_panel93, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_DESCENDING );
bSizer113->Add( m_listCtrlReceived, 1, wxEXPAND, 5 );
m_panel93->SetSizer( bSizer113 );
m_panel93->Layout();
bSizer113->Fit( m_panel93 );
m_notebook->AddPage( m_panel93, _("Received"), false );
bSizer2->Add( m_notebook, 1, wxEXPAND, 5 );
this->SetSizer( bSizer2 );
this->Layout();
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CMainFrameBase::OnClose ) );
this->Connect( wxEVT_ICONIZE, wxIconizeEventHandler( CMainFrameBase::OnIconize ) );
this->Connect( wxEVT_IDLE, wxIdleEventHandler( CMainFrameBase::OnIdle ) );
this->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_MOTION, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Connect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaint ) );
this->Connect( m_menuFileExit->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuFileExit ) );
this->Connect( m_menuOptionsGenerateBitcoins->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsGenerate ) );
this->Connect( m_menuOptionsGenerateBitcoins->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler( CMainFrameBase::OnUpdateUIOptionsGenerate ) );
this->Connect( m_menuOptionsChangeYourAddress->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeYourAddress ) );
this->Connect( m_menuOptionsOptions->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsOptions ) );
this->Connect( m_menuHelpAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) );
this->Connect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) );
this->Connect( wxID_BUTTONRECEIVE, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonAddressBook ) );
m_textCtrlAddress->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( CMainFrameBase::OnKeyDown ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_MOTION, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( CMainFrameBase::OnSetFocusAddress ), NULL, this );
m_buttonNew->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonNew ), NULL, this );
m_buttonCopy->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonCopy ), NULL, this );
m_notebook->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( CMainFrameBase::OnNotebookPageChanged ), NULL, this );
m_listCtrlAll->Connect( wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( CMainFrameBase::OnListColBeginDrag ), NULL, this );
m_listCtrlAll->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CMainFrameBase::OnListItemActivated ), NULL, this );
m_listCtrlAll->Connect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaintListCtrl ), NULL, this );
m_listCtrlSentReceived->Connect( wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( CMainFrameBase::OnListColBeginDrag ), NULL, this );
m_listCtrlSentReceived->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CMainFrameBase::OnListItemActivated ), NULL, this );
m_listCtrlSentReceived->Connect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaintListCtrl ), NULL, this );
m_listCtrlSent->Connect( wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( CMainFrameBase::OnListColBeginDrag ), NULL, this );
m_listCtrlSent->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CMainFrameBase::OnListItemActivated ), NULL, this );
m_listCtrlSent->Connect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaintListCtrl ), NULL, this );
m_listCtrlReceived->Connect( wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( CMainFrameBase::OnListColBeginDrag ), NULL, this );
m_listCtrlReceived->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CMainFrameBase::OnListItemActivated ), NULL, this );
m_listCtrlReceived->Connect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaintListCtrl ), NULL, this );
}
CMainFrameBase::~CMainFrameBase()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CMainFrameBase::OnClose ) );
this->Disconnect( wxEVT_ICONIZE, wxIconizeEventHandler( CMainFrameBase::OnIconize ) );
this->Disconnect( wxEVT_IDLE, wxIdleEventHandler( CMainFrameBase::OnIdle ) );
this->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_RIGHT_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_MOTION, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( CMainFrameBase::OnMouseEvents ) );
this->Disconnect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaint ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuFileExit ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsGenerate ) );
this->Disconnect( wxID_ANY, wxEVT_UPDATE_UI, wxUpdateUIEventHandler( CMainFrameBase::OnUpdateUIOptionsGenerate ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsChangeYourAddress ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuOptionsOptions ) );
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( CMainFrameBase::OnMenuHelpAbout ) );
this->Disconnect( wxID_BUTTONSEND, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonSend ) );
this->Disconnect( wxID_BUTTONRECEIVE, wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonAddressBook ) );
m_textCtrlAddress->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( CMainFrameBase::OnKeyDown ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_RIGHT_UP, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_MOTION, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( CMainFrameBase::OnMouseEventsAddress ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_SET_FOCUS, wxFocusEventHandler( CMainFrameBase::OnSetFocusAddress ), NULL, this );
m_buttonNew->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonNew ), NULL, this );
m_buttonCopy->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CMainFrameBase::OnButtonCopy ), NULL, this );
m_notebook->Disconnect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( CMainFrameBase::OnNotebookPageChanged ), NULL, this );
m_listCtrlAll->Disconnect( wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( CMainFrameBase::OnListColBeginDrag ), NULL, this );
m_listCtrlAll->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CMainFrameBase::OnListItemActivated ), NULL, this );
m_listCtrlAll->Disconnect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaintListCtrl ), NULL, this );
m_listCtrlSentReceived->Disconnect( wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( CMainFrameBase::OnListColBeginDrag ), NULL, this );
m_listCtrlSentReceived->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CMainFrameBase::OnListItemActivated ), NULL, this );
m_listCtrlSentReceived->Disconnect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaintListCtrl ), NULL, this );
m_listCtrlSent->Disconnect( wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( CMainFrameBase::OnListColBeginDrag ), NULL, this );
m_listCtrlSent->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CMainFrameBase::OnListItemActivated ), NULL, this );
m_listCtrlSent->Disconnect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaintListCtrl ), NULL, this );
m_listCtrlReceived->Disconnect( wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, wxListEventHandler( CMainFrameBase::OnListColBeginDrag ), NULL, this );
m_listCtrlReceived->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CMainFrameBase::OnListItemActivated ), NULL, this );
m_listCtrlReceived->Disconnect( wxEVT_PAINT, wxPaintEventHandler( CMainFrameBase::OnPaintListCtrl ), NULL, this );
}
CTxDetailsDialogBase::CTxDetailsDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizer64;
bSizer64 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer66;
bSizer66 = new wxBoxSizer( wxVERTICAL );
m_htmlWin = new wxHtmlWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO );
bSizer66->Add( m_htmlWin, 1, wxALL|wxEXPAND, 5 );
bSizer64->Add( bSizer66, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer65;
bSizer65 = new wxBoxSizer( wxHORIZONTAL );
m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer65->Add( m_buttonOK, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer64->Add( bSizer65, 0, wxALIGN_RIGHT, 5 );
this->SetSizer( bSizer64 );
this->Layout();
// Connect Events
m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CTxDetailsDialogBase::OnButtonOK ), NULL, this );
}
CTxDetailsDialogBase::~CTxDetailsDialogBase()
{
// Disconnect Events
m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CTxDetailsDialogBase::OnButtonOK ), NULL, this );
}
COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizer55;
bSizer55 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer66;
bSizer66 = new wxBoxSizer( wxHORIZONTAL );
m_listBox = new wxListBox( this, wxID_ANY, wxDefaultPosition, wxSize( 110,-1 ), 0, NULL, wxLB_NEEDED_SB|wxLB_SINGLE );
bSizer66->Add( m_listBox, 0, wxEXPAND|wxRIGHT, 5 );
m_scrolledWindow = new wxScrolledWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_scrolledWindow->SetScrollRate( 5, 5 );
wxBoxSizer* bSizer63;
bSizer63 = new wxBoxSizer( wxVERTICAL );
m_panelMain = new wxPanel( m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer69;
bSizer69 = new wxBoxSizer( wxVERTICAL );
bSizer69->Add( 0, 16, 0, wxEXPAND, 5 );
m_staticText32 = new wxStaticText( m_panelMain, wxID_ANY, _("Optional transaction fee you give to the nodes that process your transactions."), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText32->Wrap( -1 );
m_staticText32->Hide();
bSizer69->Add( m_staticText32, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
wxBoxSizer* bSizer56;
bSizer56 = new wxBoxSizer( wxHORIZONTAL );
m_staticText31 = new wxStaticText( m_panelMain, wxID_ANY, _("Transaction fee:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText31->Wrap( -1 );
m_staticText31->Hide();
bSizer56->Add( m_staticText31, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
m_textCtrlTransactionFee = new wxTextCtrl( m_panelMain, wxID_TRANSACTIONFEE, wxEmptyString, wxDefaultPosition, wxSize( 70,-1 ), 0 );
m_textCtrlTransactionFee->Hide();
bSizer56->Add( m_textCtrlTransactionFee, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
bSizer69->Add( bSizer56, 0, wxEXPAND, 5 );
wxBoxSizer* bSizer71;
bSizer71 = new wxBoxSizer( wxHORIZONTAL );
m_checkBoxLimitProcessors = new wxCheckBox( m_panelMain, wxID_ANY, _("&Limit coin generation to"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer71->Add( m_checkBoxLimitProcessors, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_spinCtrlLimitProcessors = new wxSpinCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 48,-1 ), wxSP_ARROW_KEYS, 1, 999, 1 );
bSizer71->Add( m_spinCtrlLimitProcessors, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText35 = new wxStaticText( m_panelMain, wxID_ANY, _("processors"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText35->Wrap( -1 );
bSizer71->Add( m_staticText35, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
bSizer69->Add( bSizer71, 0, 0, 5 );
m_checkBoxStartOnSystemStartup = new wxCheckBox( m_panelMain, wxID_ANY, _("&Start Bitcoin on system startup"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_checkBoxStartOnSystemStartup, 0, wxALL, 5 );
m_checkBoxMinimizeToTray = new wxCheckBox( m_panelMain, wxID_ANY, _("&Minimize to the tray instead of the taskbar"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_checkBoxMinimizeToTray, 0, wxALL, 5 );
m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, _("M&inimize to the tray on close"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_checkBoxMinimizeOnClose, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
wxBoxSizer* bSizer102;
bSizer102 = new wxBoxSizer( wxHORIZONTAL );
m_checkBoxUseProxy = new wxCheckBox( m_panelMain, wxID_ANY, _("&Connect through socks4 proxy: "), wxDefaultPosition, wxDefaultSize, 0 );
bSizer102->Add( m_checkBoxUseProxy, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
bSizer69->Add( bSizer102, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer103;
bSizer103 = new wxBoxSizer( wxHORIZONTAL );
bSizer103->Add( 18, 0, 0, 0, 5 );
m_staticTextProxyIP = new wxStaticText( m_panelMain, wxID_ANY, _("Proxy &IP:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextProxyIP->Wrap( -1 );
bSizer103->Add( m_staticTextProxyIP, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_textCtrlProxyIP = new wxTextCtrl( m_panelMain, wxID_PROXYIP, wxEmptyString, wxDefaultPosition, wxSize( 140,-1 ), 0 );
m_textCtrlProxyIP->SetMaxLength( 15 );
bSizer103->Add( m_textCtrlProxyIP, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticTextProxyPort = new wxStaticText( m_panelMain, wxID_ANY, _(" &Port:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextProxyPort->Wrap( -1 );
bSizer103->Add( m_staticTextProxyPort, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_textCtrlProxyPort = new wxTextCtrl( m_panelMain, wxID_PROXYPORT, wxEmptyString, wxDefaultPosition, wxSize( 55,-1 ), 0 );
m_textCtrlProxyPort->SetMaxLength( 5 );
bSizer103->Add( m_textCtrlProxyPort, 0, wxALIGN_CENTER_VERTICAL, 5 );
bSizer69->Add( bSizer103, 1, wxEXPAND, 5 );
m_panelMain->SetSizer( bSizer69 );
m_panelMain->Layout();
bSizer69->Fit( m_panelMain );
bSizer63->Add( m_panelMain, 0, wxEXPAND, 5 );
m_panelTest2 = new wxPanel( m_scrolledWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer64;
bSizer64 = new wxBoxSizer( wxVERTICAL );
bSizer64->Add( 0, 16, 0, wxEXPAND, 5 );
m_staticText321 = new wxStaticText( m_panelTest2, wxID_ANY, _("// [don't translate] Test panel 2 for future expansion"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText321->Wrap( -1 );
bSizer64->Add( m_staticText321, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_staticText69 = new wxStaticText( m_panelTest2, wxID_ANY, _("// [don't translate] Let's not start multiple pages until the first page is filled up"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText69->Wrap( -1 );
bSizer64->Add( m_staticText69, 0, wxALL, 5 );
m_panelTest2->SetSizer( bSizer64 );
m_panelTest2->Layout();
bSizer64->Fit( m_panelTest2 );
bSizer63->Add( m_panelTest2, 0, wxEXPAND, 5 );
m_scrolledWindow->SetSizer( bSizer63 );
m_scrolledWindow->Layout();
bSizer63->Fit( m_scrolledWindow );
bSizer66->Add( m_scrolledWindow, 1, wxEXPAND|wxLEFT, 5 );
bSizer55->Add( bSizer66, 1, wxEXPAND|wxALL, 9 );
wxBoxSizer* bSizer58;
bSizer58 = new wxBoxSizer( wxHORIZONTAL );
m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer58->Add( m_buttonOK, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer58->Add( m_buttonCancel, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonApply = new wxButton( this, wxID_APPLY, _("&Apply"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer58->Add( m_buttonApply, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer55->Add( bSizer58, 0, wxALIGN_RIGHT, 5 );
this->SetSizer( bSizer55 );
this->Layout();
// Connect Events
m_listBox->Connect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( COptionsDialogBase::OnListBox ), NULL, this );
m_textCtrlTransactionFee->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusTransactionFee ), NULL, this );
m_checkBoxLimitProcessors->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxLimitProcessors ), NULL, this );
m_checkBoxMinimizeToTray->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxMinimizeToTray ), NULL, this );
m_checkBoxUseProxy->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxUseProxy ), NULL, this );
m_textCtrlProxyIP->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this );
m_textCtrlProxyPort->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this );
m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonCancel ), NULL, this );
m_buttonApply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonApply ), NULL, this );
}
COptionsDialogBase::~COptionsDialogBase()
{
// Disconnect Events
m_listBox->Disconnect( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler( COptionsDialogBase::OnListBox ), NULL, this );
m_textCtrlTransactionFee->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusTransactionFee ), NULL, this );
m_checkBoxLimitProcessors->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxLimitProcessors ), NULL, this );
m_checkBoxMinimizeToTray->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxMinimizeToTray ), NULL, this );
m_checkBoxUseProxy->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxUseProxy ), NULL, this );
m_textCtrlProxyIP->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this );
m_textCtrlProxyPort->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this );
m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonCancel ), NULL, this );
m_buttonApply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonApply ), NULL, this );
}
CAboutDialogBase::CAboutDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizer63;
bSizer63 = new wxBoxSizer( wxHORIZONTAL );
m_bitmap = new wxStaticBitmap( this, wxID_ANY, wxBitmap( about_xpm ), wxDefaultPosition, wxDefaultSize, 0 );
bSizer63->Add( m_bitmap, 0, 0, 5 );
wxBoxSizer* bSizer60;
bSizer60 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer62;
bSizer62 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer631;
bSizer631 = new wxBoxSizer( wxVERTICAL );
bSizer631->Add( 0, 65, 0, wxEXPAND, 5 );
wxBoxSizer* bSizer64;
bSizer64 = new wxBoxSizer( wxHORIZONTAL );
m_staticText40 = new wxStaticText( this, wxID_ANY, _("Bitcoin "), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText40->Wrap( -1 );
m_staticText40->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) );
bSizer64->Add( m_staticText40, 0, wxALIGN_BOTTOM|wxTOP|wxBOTTOM|wxLEFT, 5 );
m_staticTextVersion = new wxStaticText( this, wxID_ANY, _("version"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextVersion->Wrap( -1 );
m_staticTextVersion->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) );
bSizer64->Add( m_staticTextVersion, 0, wxALIGN_BOTTOM|wxTOP|wxBOTTOM|wxRIGHT, 5 );
bSizer631->Add( bSizer64, 0, wxEXPAND, 5 );
bSizer631->Add( 0, 4, 0, wxEXPAND, 5 );
m_staticTextMain = new wxStaticText( this, wxID_ANY, _("Copyright (c) 2009-2010 Satoshi Nakamoto.\n\nThis is experimental software. Do not rely on it for actual financial transactions.\n\nDistributed under the MIT/X11 software license, see the accompanying file \nlicense.txt or http://www.opensource.org/licenses/mit-license.php.\n\nThis product includes software developed by the OpenSSL Project for use in the \nOpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by \nEric Young (eay@cryptsoft.com)."), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextMain->Wrap( -1 );
bSizer631->Add( m_staticTextMain, 0, wxALL, 5 );
bSizer631->Add( 0, 0, 1, wxEXPAND, 5 );
bSizer62->Add( bSizer631, 1, wxEXPAND, 5 );
bSizer60->Add( bSizer62, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer61;
bSizer61 = new wxBoxSizer( wxHORIZONTAL );
bSizer61->Add( 0, 0, 1, wxEXPAND, 5 );
m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer61->Add( m_buttonOK, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer60->Add( bSizer61, 0, wxALIGN_RIGHT|wxEXPAND|wxRIGHT, 5 );
bSizer63->Add( bSizer60, 1, wxEXPAND|wxLEFT, 5 );
this->SetSizer( bSizer63 );
this->Layout();
// Connect Events
m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAboutDialogBase::OnButtonOK ), NULL, this );
}
CAboutDialogBase::~CAboutDialogBase()
{
// Disconnect Events
m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAboutDialogBase::OnButtonOK ), NULL, this );
}
CSendDialogBase::CSendDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizer21;
bSizer21 = new wxBoxSizer( wxVERTICAL );
bSizer21->Add( 0, 5, 0, wxEXPAND, 5 );
wxFlexGridSizer* fgSizer1;
fgSizer1 = new wxFlexGridSizer( 0, 2, 0, 0 );
fgSizer1->AddGrowableCol( 1 );
fgSizer1->SetFlexibleDirection( wxBOTH );
fgSizer1->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
fgSizer1->Add( 0, 0, 0, wxEXPAND, 5 );
m_staticTextInstructions = new wxStaticText( this, wxID_ANY, _("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextInstructions->Wrap( -1 );
fgSizer1->Add( m_staticTextInstructions, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizer47;
bSizer47 = new wxBoxSizer( wxHORIZONTAL );
bSizer47->SetMinSize( wxSize( 70,-1 ) );
bSizer47->Add( 0, 0, 1, wxEXPAND, 5 );
m_bitmapCheckMark = new wxStaticBitmap( this, wxID_ANY, wxBitmap( check_xpm ), wxDefaultPosition, wxSize( 16,16 ), 0 );
bSizer47->Add( m_bitmapCheckMark, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_staticText36 = new wxStaticText( this, wxID_ANY, _("Pay &To:"), wxDefaultPosition, wxSize( -1,-1 ), wxALIGN_RIGHT );
m_staticText36->Wrap( -1 );
bSizer47->Add( m_staticText36, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
fgSizer1->Add( bSizer47, 1, wxEXPAND|wxLEFT, 5 );
wxBoxSizer* bSizer19;
bSizer19 = new wxBoxSizer( wxHORIZONTAL );
m_textCtrlAddress = new wxTextCtrl( this, wxID_TEXTCTRLPAYTO, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
bSizer19->Add( m_textCtrlAddress, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
wxBoxSizer* bSizer66;
bSizer66 = new wxBoxSizer( wxHORIZONTAL );
m_buttonPaste = new wxButton( this, wxID_BUTTONPASTE, _("&Paste"), wxDefaultPosition, wxSize( -1,-1 ), wxBU_EXACTFIT );
bSizer66->Add( m_buttonPaste, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxEXPAND, 5 );
m_buttonAddress = new wxButton( this, wxID_BUTTONADDRESSBOOK, _(" Address &Book..."), wxDefaultPosition, wxDefaultSize, 0 );
bSizer66->Add( m_buttonAddress, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxEXPAND, 5 );
bSizer19->Add( bSizer66, 0, wxALIGN_CENTER_VERTICAL, 5 );
fgSizer1->Add( bSizer19, 1, wxEXPAND|wxRIGHT, 5 );
m_staticText19 = new wxStaticText( this, wxID_ANY, _("&Amount:"), wxDefaultPosition, wxSize( -1,-1 ), wxALIGN_RIGHT );
m_staticText19->Wrap( -1 );
fgSizer1->Add( m_staticText19, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT|wxALIGN_RIGHT, 5 );
m_textCtrlAmount = new wxTextCtrl( this, wxID_TEXTCTRLAMOUNT, wxEmptyString, wxDefaultPosition, wxSize( 145,-1 ), 0 );
m_textCtrlAmount->SetMaxLength( 20 );
m_textCtrlAmount->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) );
fgSizer1->Add( m_textCtrlAmount, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_staticText20 = new wxStaticText( this, wxID_ANY, _("T&ransfer:"), wxDefaultPosition, wxSize( -1,-1 ), wxALIGN_RIGHT );
m_staticText20->Wrap( -1 );
m_staticText20->Hide();
fgSizer1->Add( m_staticText20, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxTOP|wxBOTTOM|wxLEFT, 5 );
wxString m_choiceTransferTypeChoices[] = { _(" Standard") };
int m_choiceTransferTypeNChoices = sizeof( m_choiceTransferTypeChoices ) / sizeof( wxString );
m_choiceTransferType = new wxChoice( this, wxID_CHOICETRANSFERTYPE, wxDefaultPosition, wxDefaultSize, m_choiceTransferTypeNChoices, m_choiceTransferTypeChoices, 0 );
m_choiceTransferType->SetSelection( 0 );
m_choiceTransferType->Hide();
fgSizer1->Add( m_choiceTransferType, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
fgSizer1->Add( 0, 3, 0, wxEXPAND, 5 );
fgSizer1->Add( 0, 0, 0, wxEXPAND, 5 );
bSizer21->Add( fgSizer1, 0, wxEXPAND|wxLEFT, 5 );
wxBoxSizer* bSizer672;
bSizer672 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer681;
bSizer681 = new wxBoxSizer( wxVERTICAL );
m_staticTextFrom = new wxStaticText( this, wxID_ANY, _("&From:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextFrom->Wrap( -1 );
bSizer681->Add( m_staticTextFrom, 0, wxBOTTOM|wxLEFT, 5 );
m_textCtrlFrom = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer681->Add( m_textCtrlFrom, 0, wxLEFT|wxEXPAND, 5 );
bSizer672->Add( bSizer681, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bSizer21->Add( bSizer672, 0, wxEXPAND, 5 );
wxBoxSizer* bSizer67;
bSizer67 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer68;
bSizer68 = new wxBoxSizer( wxVERTICAL );
m_staticTextMessage = new wxStaticText( this, wxID_ANY, _("&Message:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextMessage->Wrap( -1 );
bSizer68->Add( m_staticTextMessage, 0, wxTOP|wxBOTTOM|wxLEFT, 5 );
m_textCtrlMessage = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE );
bSizer68->Add( m_textCtrlMessage, 1, wxEXPAND|wxLEFT, 5 );
bSizer67->Add( bSizer68, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bSizer21->Add( bSizer67, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer23;
bSizer23 = new wxBoxSizer( wxHORIZONTAL );
bSizer23->Add( 0, 0, 1, wxEXPAND, 5 );
m_buttonSend = new wxButton( this, wxID_BUTTONSEND, _("&Send"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
m_buttonSend->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 90, false, wxEmptyString ) );
bSizer23->Add( m_buttonSend, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer23->Add( m_buttonCancel, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer21->Add( bSizer23, 0, wxEXPAND, 5 );
this->SetSizer( bSizer21 );
this->Layout();
// Connect Events
m_textCtrlAddress->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( CSendDialogBase::OnKeyDown ), NULL, this );
m_textCtrlAddress->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( CSendDialogBase::OnTextAddress ), NULL, this );
m_buttonPaste->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendDialogBase::OnButtonPaste ), NULL, this );
m_buttonAddress->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendDialogBase::OnButtonAddressBook ), NULL, this );
m_textCtrlAmount->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( CSendDialogBase::OnKeyDown ), NULL, this );
m_textCtrlAmount->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( CSendDialogBase::OnKillFocusAmount ), NULL, this );
m_textCtrlFrom->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( CSendDialogBase::OnKeyDown ), NULL, this );
m_textCtrlMessage->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( CSendDialogBase::OnKeyDown ), NULL, this );
m_buttonSend->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendDialogBase::OnButtonSend ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendDialogBase::OnButtonCancel ), NULL, this );
}
CSendDialogBase::~CSendDialogBase()
{
// Disconnect Events
m_textCtrlAddress->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( CSendDialogBase::OnKeyDown ), NULL, this );
m_textCtrlAddress->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( CSendDialogBase::OnTextAddress ), NULL, this );
m_buttonPaste->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendDialogBase::OnButtonPaste ), NULL, this );
m_buttonAddress->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendDialogBase::OnButtonAddressBook ), NULL, this );
m_textCtrlAmount->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( CSendDialogBase::OnKeyDown ), NULL, this );
m_textCtrlAmount->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( CSendDialogBase::OnKillFocusAmount ), NULL, this );
m_textCtrlFrom->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( CSendDialogBase::OnKeyDown ), NULL, this );
m_textCtrlMessage->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( CSendDialogBase::OnKeyDown ), NULL, this );
m_buttonSend->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendDialogBase::OnButtonSend ), NULL, this );
m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendDialogBase::OnButtonCancel ), NULL, this );
}
CSendingDialogBase::CSendingDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizer68;
bSizer68 = new wxBoxSizer( wxVERTICAL );
m_staticTextSending = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,14 ), 0 );
m_staticTextSending->Wrap( -1 );
bSizer68->Add( m_staticTextSending, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 8 );
m_textCtrlStatus = new wxTextCtrl( this, wxID_ANY, _("\n\nConnecting..."), wxDefaultPosition, wxDefaultSize, wxTE_CENTRE|wxTE_MULTILINE|wxTE_NO_VSCROLL|wxTE_READONLY|wxNO_BORDER );
m_textCtrlStatus->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
bSizer68->Add( m_textCtrlStatus, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 );
wxBoxSizer* bSizer69;
bSizer69 = new wxBoxSizer( wxHORIZONTAL );
bSizer69->Add( 0, 0, 1, wxEXPAND, 5 );
m_buttonOK = new wxButton( this, wxID_ANY, _("OK"), wxDefaultPosition, wxDefaultSize, 0 );
m_buttonOK->Enable( false );
bSizer69->Add( m_buttonOK, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer69->Add( m_buttonCancel, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer68->Add( bSizer69, 0, wxEXPAND, 5 );
this->SetSizer( bSizer68 );
this->Layout();
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CSendingDialogBase::OnClose ) );
this->Connect( wxEVT_PAINT, wxPaintEventHandler( CSendingDialogBase::OnPaint ) );
m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendingDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendingDialogBase::OnButtonCancel ), NULL, this );
}
CSendingDialogBase::~CSendingDialogBase()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CSendingDialogBase::OnClose ) );
this->Disconnect( wxEVT_PAINT, wxPaintEventHandler( CSendingDialogBase::OnPaint ) );
m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendingDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CSendingDialogBase::OnButtonCancel ), NULL, this );
}
CYourAddressDialogBase::CYourAddressDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizer68;
bSizer68 = new wxBoxSizer( wxVERTICAL );
bSizer68->Add( 0, 5, 0, wxEXPAND, 5 );
m_staticText45 = new wxStaticText( this, wxID_ANY, _("These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you. The highlighted address is displayed in the main window."), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText45->Wrap( 590 );
bSizer68->Add( m_staticText45, 0, wxALL, 5 );
m_listCtrl = new wxListCtrl( this, wxID_LISTCTRL, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_ASCENDING );
bSizer68->Add( m_listCtrl, 1, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizer69;
bSizer69 = new wxBoxSizer( wxHORIZONTAL );
bSizer69->Add( 0, 0, 1, wxEXPAND, 5 );
m_buttonRename = new wxButton( this, wxID_BUTTONRENAME, _("&Edit..."), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_buttonRename, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonNew = new wxButton( this, wxID_BUTTONNEW, _(" &New Address... "), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer69->Add( m_buttonNew, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonCopy = new wxButton( this, wxID_BUTTONCOPY, _(" &Copy to Clipboard "), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer69->Add( m_buttonCopy, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_buttonOK, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
m_buttonCancel->Hide();
bSizer69->Add( m_buttonCancel, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer68->Add( bSizer69, 0, wxEXPAND, 5 );
this->SetSizer( bSizer68 );
this->Layout();
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CYourAddressDialogBase::OnClose ) );
m_listCtrl->Connect( wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler( CYourAddressDialogBase::OnListEndLabelEdit ), NULL, this );
m_listCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CYourAddressDialogBase::OnListItemActivated ), NULL, this );
m_listCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( CYourAddressDialogBase::OnListItemSelected ), NULL, this );
m_buttonRename->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonRename ), NULL, this );
m_buttonNew->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonNew ), NULL, this );
m_buttonCopy->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonCopy ), NULL, this );
m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonCancel ), NULL, this );
}
CYourAddressDialogBase::~CYourAddressDialogBase()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CYourAddressDialogBase::OnClose ) );
m_listCtrl->Disconnect( wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler( CYourAddressDialogBase::OnListEndLabelEdit ), NULL, this );
m_listCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CYourAddressDialogBase::OnListItemActivated ), NULL, this );
m_listCtrl->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( CYourAddressDialogBase::OnListItemSelected ), NULL, this );
m_buttonRename->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonRename ), NULL, this );
m_buttonNew->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonNew ), NULL, this );
m_buttonCopy->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonCopy ), NULL, this );
m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CYourAddressDialogBase::OnButtonCancel ), NULL, this );
}
CAddressBookDialogBase::CAddressBookDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizer58;
bSizer58 = new wxBoxSizer( wxVERTICAL );
m_notebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_panelSending = new wxPanel( m_notebook, wxID_PANELSENDING, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer68;
bSizer68 = new wxBoxSizer( wxVERTICAL );
bSizer68->Add( 0, 0, 0, wxEXPAND, 5 );
m_staticText55 = new wxStaticText( m_panelSending, wxID_ANY, _("Bitcoin Address"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText55->Wrap( -1 );
m_staticText55->Hide();
bSizer68->Add( m_staticText55, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_listCtrlSending = new wxListCtrl( m_panelSending, wxID_LISTCTRLSENDING, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_ASCENDING );
bSizer68->Add( m_listCtrlSending, 1, wxALL|wxEXPAND, 5 );
m_panelSending->SetSizer( bSizer68 );
m_panelSending->Layout();
bSizer68->Fit( m_panelSending );
m_notebook->AddPage( m_panelSending, _("Sending"), false );
m_panelReceiving = new wxPanel( m_notebook, wxID_PANELRECEIVING, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer681;
bSizer681 = new wxBoxSizer( wxVERTICAL );
bSizer681->Add( 0, 0, 0, wxEXPAND, 5 );
m_staticText45 = new wxStaticText( m_panelReceiving, wxID_ANY, _("These are your Bitcoin addresses for receiving payments. You can give a different one to each sender to keep track of who is paying you. The highlighted address will be displayed in the main window."), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText45->Wrap( 570 );
bSizer681->Add( m_staticText45, 0, wxTOP|wxRIGHT|wxLEFT, 6 );
bSizer681->Add( 0, 2, 0, wxEXPAND, 5 );
m_listCtrlReceiving = new wxListCtrl( m_panelReceiving, wxID_LISTCTRLRECEIVING, wxDefaultPosition, wxDefaultSize, wxLC_NO_SORT_HEADER|wxLC_REPORT|wxLC_SORT_ASCENDING );
bSizer681->Add( m_listCtrlReceiving, 1, wxALL|wxEXPAND, 5 );
m_panelReceiving->SetSizer( bSizer681 );
m_panelReceiving->Layout();
bSizer681->Fit( m_panelReceiving );
m_notebook->AddPage( m_panelReceiving, _("Receiving"), true );
bSizer58->Add( m_notebook, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizer69;
bSizer69 = new wxBoxSizer( wxHORIZONTAL );
bSizer69->Add( 0, 0, 1, wxEXPAND, 5 );
m_buttonDelete = new wxButton( this, wxID_BUTTONDELETE, _("&Delete"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_buttonDelete, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonCopy = new wxButton( this, wxID_BUTTONCOPY, _(" &Copy to Clipboard "), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer69->Add( m_buttonCopy, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonEdit = new wxButton( this, wxID_BUTTONEDIT, _("&Edit..."), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_buttonEdit, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonNew = new wxButton( this, wxID_BUTTONNEW, _(" &New Address... "), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_buttonNew, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer69->Add( m_buttonOK, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer69->Add( m_buttonCancel, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer58->Add( bSizer69, 0, wxEXPAND, 5 );
this->SetSizer( bSizer58 );
this->Layout();
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CAddressBookDialogBase::OnClose ) );
m_notebook->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( CAddressBookDialogBase::OnNotebookPageChanged ), NULL, this );
m_listCtrlSending->Connect( wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler( CAddressBookDialogBase::OnListEndLabelEdit ), NULL, this );
m_listCtrlSending->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CAddressBookDialogBase::OnListItemActivated ), NULL, this );
m_listCtrlSending->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( CAddressBookDialogBase::OnListItemSelected ), NULL, this );
m_listCtrlReceiving->Connect( wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler( CAddressBookDialogBase::OnListEndLabelEdit ), NULL, this );
m_listCtrlReceiving->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CAddressBookDialogBase::OnListItemActivated ), NULL, this );
m_listCtrlReceiving->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( CAddressBookDialogBase::OnListItemSelected ), NULL, this );
m_buttonDelete->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonDelete ), NULL, this );
m_buttonCopy->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonCopy ), NULL, this );
m_buttonEdit->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonEdit ), NULL, this );
m_buttonNew->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonNew ), NULL, this );
m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonCancel ), NULL, this );
}
CAddressBookDialogBase::~CAddressBookDialogBase()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CAddressBookDialogBase::OnClose ) );
m_notebook->Disconnect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( CAddressBookDialogBase::OnNotebookPageChanged ), NULL, this );
m_listCtrlSending->Disconnect( wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler( CAddressBookDialogBase::OnListEndLabelEdit ), NULL, this );
m_listCtrlSending->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CAddressBookDialogBase::OnListItemActivated ), NULL, this );
m_listCtrlSending->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( CAddressBookDialogBase::OnListItemSelected ), NULL, this );
m_listCtrlReceiving->Disconnect( wxEVT_COMMAND_LIST_END_LABEL_EDIT, wxListEventHandler( CAddressBookDialogBase::OnListEndLabelEdit ), NULL, this );
m_listCtrlReceiving->Disconnect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler( CAddressBookDialogBase::OnListItemActivated ), NULL, this );
m_listCtrlReceiving->Disconnect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( CAddressBookDialogBase::OnListItemSelected ), NULL, this );
m_buttonDelete->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonDelete ), NULL, this );
m_buttonCopy->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonCopy ), NULL, this );
m_buttonEdit->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonEdit ), NULL, this );
m_buttonNew->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonNew ), NULL, this );
m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CAddressBookDialogBase::OnButtonCancel ), NULL, this );
}
CGetTextFromUserDialogBase::CGetTextFromUserDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bSizer79;
bSizer79 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer81;
bSizer81 = new wxBoxSizer( wxVERTICAL );
bSizer81->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextMessage1 = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextMessage1->Wrap( -1 );
bSizer81->Add( m_staticTextMessage1, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_textCtrl1 = new wxTextCtrl( this, wxID_TEXTCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
bSizer81->Add( m_textCtrl1, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 );
m_staticTextMessage2 = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextMessage2->Wrap( -1 );
m_staticTextMessage2->Hide();
bSizer81->Add( m_staticTextMessage2, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
m_textCtrl2 = new wxTextCtrl( this, wxID_TEXTCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
m_textCtrl2->Hide();
bSizer81->Add( m_textCtrl2, 0, wxALL|wxEXPAND|wxALIGN_CENTER_HORIZONTAL, 5 );
bSizer81->Add( 0, 0, 1, wxEXPAND, 5 );
bSizer79->Add( bSizer81, 1, wxEXPAND|wxALL, 10 );
wxBoxSizer* bSizer80;
bSizer80 = new wxBoxSizer( wxHORIZONTAL );
bSizer80->Add( 0, 0, 1, wxEXPAND, 5 );
m_buttonOK = new wxButton( this, wxID_OK, _("OK"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
bSizer80->Add( m_buttonOK, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_buttonCancel = new wxButton( this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer80->Add( m_buttonCancel, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
bSizer79->Add( bSizer80, 0, wxEXPAND, 5 );
this->SetSizer( bSizer79 );
this->Layout();
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CGetTextFromUserDialogBase::OnClose ) );
m_textCtrl1->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( CGetTextFromUserDialogBase::OnKeyDown ), NULL, this );
m_textCtrl2->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( CGetTextFromUserDialogBase::OnKeyDown ), NULL, this );
m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CGetTextFromUserDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CGetTextFromUserDialogBase::OnButtonCancel ), NULL, this );
}
CGetTextFromUserDialogBase::~CGetTextFromUserDialogBase()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( CGetTextFromUserDialogBase::OnClose ) );
m_textCtrl1->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( CGetTextFromUserDialogBase::OnKeyDown ), NULL, this );
m_textCtrl2->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( CGetTextFromUserDialogBase::OnKeyDown ), NULL, this );
m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CGetTextFromUserDialogBase::OnButtonOK ), NULL, this );
m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( CGetTextFromUserDialogBase::OnButtonCancel ), NULL, this );
}
"%file: ./uint256.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.
#include <limits.h>
#include <string>
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 int64;
typedef unsigned __int64 uint64;
#else
typedef long long int64;
typedef unsigned long long uint64;
#endif
#if defined(_MSC_VER) && _MSC_VER < 1300
#define for if (false) ; else for
#endif
inline int Testuint256AdHoc(vector<string> vArg);
// We have to keep a separate base class without constructors
// so the compiler will let us use it in a union
template<unsigned int BITS>
class base_uint
{
protected:
enum { WIDTH=BITS/32 };
unsigned int pn[WIDTH];
public:
bool operator!() const
{
for (int i = 0; i < WIDTH; i++)
if (pn[i] != 0)
return false;
return true;
}
const base_uint operator~() const
{
base_uint ret;
for (int i = 0; i < WIDTH; i++)
ret.pn[i] = ~pn[i];
return ret;
}
const base_uint operator-() const
{
base_uint ret;
for (int i = 0; i < WIDTH; i++)
ret.pn[i] = ~pn[i];
ret++;
return ret;
}
base_uint& operator=(uint64 b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
return *this;
}
base_uint& operator^=(const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] ^= b.pn[i];
return *this;
}
base_uint& operator&=(const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] &= b.pn[i];
return *this;
}
base_uint& operator|=(const base_uint& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] |= b.pn[i];
return *this;
}
base_uint& operator^=(uint64 b)
{
pn[0] ^= (unsigned int)b;
pn[1] ^= (unsigned int)(b >> 32);
return *this;
}
base_uint& operator&=(uint64 b)
{
pn[0] &= (unsigned int)b;
pn[1] &= (unsigned int)(b >> 32);
return *this;
}
base_uint& operator|=(uint64 b)
{
pn[0] |= (unsigned int)b;
pn[1] |= (unsigned int)(b >> 32);
return *this;
}
base_uint& operator<<=(unsigned int shift)
{
base_uint a(*this);
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
int k = shift / 32;
shift = shift % 32;
for (int i = 0; i < WIDTH; i++)
{
if (i+k+1 < WIDTH && shift != 0)
pn[i+k+1] |= (a.pn[i] >> (32-shift));
if (i+k < WIDTH)
pn[i+k] |= (a.pn[i] << shift);
}
return *this;
}
base_uint& operator>>=(unsigned int shift)
{
base_uint a(*this);
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
int k = shift / 32;
shift = shift % 32;
for (int i = 0; i < WIDTH; i++)
{
if (i-k-1 >= 0 && shift != 0)
pn[i-k-1] |= (a.pn[i] << (32-shift));
if (i-k >= 0)
pn[i-k] |= (a.pn[i] >> shift);
}
return *this;
}
base_uint& operator+=(const base_uint& b)
{
uint64 carry = 0;
for (int i = 0; i < WIDTH; i++)
{
uint64 n = carry + pn[i] + b.pn[i];
pn[i] = n & 0xffffffff;
carry = n >> 32;
}
return *this;
}
base_uint& operator-=(const base_uint& b)
{
*this += -b;
return *this;
}
base_uint& operator+=(uint64 b64)
{
base_uint b;
b = b64;
*this += b;
return *this;
}
base_uint& operator-=(uint64 b64)
{
base_uint b;
b = b64;
*this += -b;
return *this;
}
base_uint& operator++()
{
// prefix operator
int i = 0;
while (++pn[i] == 0 && i < WIDTH-1)
i++;
return *this;
}
const base_uint operator++(int)
{
// postfix operator
const base_uint ret = *this;
++(*this);
return ret;
}
base_uint& operator--()
{
// prefix operator
int i = 0;
while (--pn[i] == -1 && i < WIDTH-1)
i++;
return *this;
}
const base_uint operator--(int)
{
// postfix operator
const base_uint ret = *this;
--(*this);
return ret;
}
friend inline bool operator<(const base_uint& a, const base_uint& b)
{
for (int i = base_uint::WIDTH-1; i >= 0; i--)
{
if (a.pn[i] < b.pn[i])
return true;
else if (a.pn[i] > b.pn[i])
return false;
}
return false;
}
friend inline bool operator<=(const base_uint& a, const base_uint& b)
{
for (int i = base_uint::WIDTH-1; i >= 0; i--)
{
if (a.pn[i] < b.pn[i])
return true;
else if (a.pn[i] > b.pn[i])
return false;
}
return true;
}
friend inline bool operator>(const base_uint& a, const base_uint& b)
{
for (int i = base_uint::WIDTH-1; i >= 0; i--)
{
if (a.pn[i] > b.pn[i])
return true;
else if (a.pn[i] < b.pn[i])
return false;
}
return false;
}
friend inline bool operator>=(const base_uint& a, const base_uint& b)
{
for (int i = base_uint::WIDTH-1; i >= 0; i--)
{
if (a.pn[i] > b.pn[i])
return true;
else if (a.pn[i] < b.pn[i])
return false;
}
return true;
}
friend inline bool operator==(const base_uint& a, const base_uint& b)
{
for (int i = 0; i < base_uint::WIDTH; i++)
if (a.pn[i] != b.pn[i])
return false;
return true;
}
friend inline bool operator==(const base_uint& a, uint64 b)
{
if (a.pn[0] != (unsigned int)b)
return false;
if (a.pn[1] != (unsigned int)(b >> 32))
return false;
for (int i = 2; i < base_uint::WIDTH; i++)
if (a.pn[i] != 0)
return false;
return true;
}
friend inline bool operator!=(const base_uint& a, const base_uint& b)
{
return (!(a == b));
}
friend inline bool operator!=(const base_uint& a, uint64 b)
{
return (!(a == b));
}
std::string GetHex() const
{
char psz[sizeof(pn)*2 + 1];
for (int i = 0; i < sizeof(pn); i++)
sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]);
return string(psz, psz + sizeof(pn)*2);
}
void SetHex(const char* psz)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
// skip leading spaces
while (isspace(*psz))
psz++;
// skip 0x
if (psz[0] == '0' && tolower(psz[1]) == 'x')
psz += 2;
// hex string to uint
static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
const char* pbegin = psz;
while (phexdigit[*psz] || *psz == '0')
psz++;
psz--;
unsigned char* p1 = (unsigned char*)pn;
unsigned char* pend = p1 + WIDTH * 4;
while (psz >= pbegin && p1 < pend)
{
*p1 = phexdigit[(unsigned char)*psz--];
if (psz >= pbegin)
{
*p1 |= (phexdigit[(unsigned char)*psz--] << 4);
p1++;
}
}
}
void SetHex(const std::string& str)
{
SetHex(str.c_str());
}
std::string ToString() const
{
return (GetHex());
}
unsigned char* begin()
{
return (unsigned char*)&pn[0];
}
unsigned char* end()
{
return (unsigned char*)&pn[WIDTH];
}
unsigned int size()
{
return sizeof(pn);
}
unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const
{
return sizeof(pn);
}
template<typename Stream>
void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
{
s.write((char*)pn, sizeof(pn));
}
template<typename Stream>
void Unserialize(Stream& s, int nType=0, int nVersion=VERSION)
{
s.read((char*)pn, sizeof(pn));
}
friend class uint160;
friend class uint256;
friend inline int Testuint256AdHoc(vector<string> vArg);
};
typedef base_uint<160> base_uint160;
typedef base_uint<256> base_uint256;
//
// uint160 and uint256 could be implemented as templates, but to keep
// compile errors and debugging cleaner, they're copy and pasted.
//
//////////////////////////////////////////////////////////////////////////////
//
// uint160
//
class uint160 : public base_uint160
{
public:
typedef base_uint160 basetype;
uint160()
{
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
}
uint160(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
uint160& operator=(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
return *this;
}
uint160(uint64 b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
}
uint160& operator=(uint64 b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
return *this;
}
explicit uint160(const std::string& str)
{
SetHex(str);
}
explicit uint160(const std::vector<unsigned char>& vch)
{
if (vch.size() == sizeof(pn))
memcpy(pn, &vch[0], sizeof(pn));
else
*this = 0;
}
};
inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; }
inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; }
inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; }
inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; }
inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; }
inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; }
inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; }
inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; }
inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; }
inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; }
inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; }
inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; }
inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; }
inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; }
inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; }
inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; }
inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; }
inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; }
inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; }
inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; }
inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; }
inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; }
inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; }
inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; }
inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; }
inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; }
inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; }
inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; }
inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; }
inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; }
inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; }
inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; }
inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; }
inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; }
//////////////////////////////////////////////////////////////////////////////
//
// uint256
//
class uint256 : public base_uint256
{
public:
typedef base_uint256 basetype;
uint256()
{
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
}
uint256(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
uint256& operator=(const basetype& b)
{
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
return *this;
}
uint256(uint64 b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
}
uint256& operator=(uint64 b)
{
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
pn[i] = 0;
return *this;
}
explicit uint256(const std::string& str)
{
SetHex(str);
}
explicit uint256(const std::vector<unsigned char>& vch)
{
if (vch.size() == sizeof(pn))
memcpy(pn, &vch[0], sizeof(pn));
else
*this = 0;
}
};
inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; }
inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; }
inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; }
inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; }
inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; }
inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; }
inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; }
inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; }
inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; }
inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; }
inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; }
inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; }
inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; }
inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; }
inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; }
inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; }
inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; }
inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; }
inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; }
inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; }
inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; }
inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; }
inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; }
inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; }
inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; }
inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; }
inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; }
inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; }
inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; }
inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; }
inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; }
inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; }
inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; }
inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; }
inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; }
inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; }
inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; }
inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; }
inline bool operator!=(const uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; }
inline const uint256 operator^(const uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; }
inline const uint256 operator&(const uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; }
inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; }
inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; }
inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; }
inline int Testuint256AdHoc(vector<string> vArg)
{
uint256 g(0);
printf("%s\n", g.ToString().c_str());
g--; printf("g--\n");
printf("%s\n", g.ToString().c_str());
g--; printf("g--\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
uint256 a(7);
printf("a=7\n");
printf("%s\n", a.ToString().c_str());
uint256 b;
printf("b undefined\n");
printf("%s\n", b.ToString().c_str());
int c = 3;
a = c;
a.pn[3] = 15;
printf("%s\n", a.ToString().c_str());
uint256 k(c);
a = 5;
a.pn[3] = 15;
printf("%s\n", a.ToString().c_str());
b = 1;
b <<= 52;
a |= b;
a ^= 0x500;
printf("a %s\n", a.ToString().c_str());
a = a | b | (uint256)0x1000;
printf("a %s\n", a.ToString().c_str());
printf("b %s\n", b.ToString().c_str());
a = 0xfffffffe;
a.pn[4] = 9;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
uint256 d = a--;
printf("%s\n", d.ToString().c_str());
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
d = a;
printf("%s\n", d.ToString().c_str());
for (int i = uint256::WIDTH-1; i >= 0; i--) printf("%08x", d.pn[i]); printf("\n");
uint256 neg = d;
neg = ~neg;
printf("%s\n", neg.ToString().c_str());
uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111");
printf("\n");
printf("%s\n", e.ToString().c_str());
printf("\n");
uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111");
uint256 x2;
printf("%s\n", x1.ToString().c_str());
for (int i = 0; i < 270; i += 4)
{
x2 = x1 << i;
printf("%s\n", x2.ToString().c_str());
}
printf("\n");
printf("%s\n", x1.ToString().c_str());
for (int i = 0; i < 270; i += 4)
{
x2 = x1;
x2 >>= i;
printf("%s\n", x2.ToString().c_str());
}
for (int i = 0; i < 100; i++)
{
uint256 k = (~uint256(0) >> i);
printf("%s\n", k.ToString().c_str());
}
for (int i = 0; i < 100; i++)
{
uint256 k = (~uint256(0) << i);
printf("%s\n", k.ToString().c_str());
}
return (0);
}
"%file: ./uiproject.fbp"
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="9" />
<object class="Project" expanded="1">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">uibase</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="internationalize">1</property>
<property name="name"></property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Frame" expanded="0">
<property name="bg">wxSYS_COLOUR_BTNFACE</property>
<property name="center"></property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="extra_style"></property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_MAINFRAME</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">CMainFrameBase</property>
<property name="pos"></property>
<property name="size">723,484</property>
<property name="style">wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER</property>
<property name="subclass"></property>
<property name="title">Bitcoin</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<property name="xrc_skip_sizer">1</property>
<event name="OnActivate"></event>
<event name="OnActivateApp"></event>
<event name="OnChar"></event>
<event name="OnClose">OnClose</event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnHibernate"></event>
<event name="OnIconize">OnIconize</event>
<event name="OnIdle">OnIdle</event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents">OnMouseEvents</event>
<event name="OnMouseWheel"></event>
<event name="OnPaint">OnPaint</event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxMenuBar" expanded="1">
<property name="bg">240,240,240</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">MyMenuBar</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_menubar</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxMenu" expanded="1">
<property name="label">&amp;File</property>
<property name="name">m_menuFile</property>
<property name="permission">protected</property>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_EXIT</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">E&amp;xit</property>
<property name="name">m_menuFileExit</property>
<property name="permission">none</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuFileExit</event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="wxMenu" expanded="1">
<property name="label">&amp;Settings</property>
<property name="name">m_menuOptions</property>
<property name="permission">public</property>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_OPTIONSGENERATEBITCOINS</property>
<property name="kind">wxITEM_CHECK</property>
<property name="label">&amp;Generate Coins</property>
<property name="name">m_menuOptionsGenerateBitcoins</property>
<property name="permission">none</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuOptionsGenerate</event>
<event name="OnUpdateUI">OnUpdateUIOptionsGenerate</event>
</object>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_ANY</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">&amp;Your Receiving Addresses...</property>
<property name="name">m_menuOptionsChangeYourAddress</property>
<property name="permission">none</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuOptionsChangeYourAddress</event>
<event name="OnUpdateUI"></event>
</object>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_PREFERENCES</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">&amp;Options...</property>
<property name="name">m_menuOptionsOptions</property>
<property name="permission">none</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuOptionsOptions</event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="wxMenu" expanded="1">
<property name="label">&amp;Help</property>
<property name="name">m_menuHelp</property>
<property name="permission">protected</property>
<object class="wxMenuItem" expanded="1">
<property name="bitmap"></property>
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_ABOUT</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">&amp;About...</property>
<property name="name">m_menuHelpAbout</property>
<property name="permission">none</property>
<property name="shortcut"></property>
<property name="unchecked_bitmap"></property>
<event name="OnMenuSelection">OnMenuHelpAbout</event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
<object class="wxToolBar" expanded="1">
<property name="bg"></property>
<property name="bitmapsize">20,20</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font">,90,90,-1,70,0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="margins"></property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_toolBar</property>
<property name="packing">1</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="separation">1</property>
<property name="size">-1,-1</property>
<property name="style">wxTB_FLAT|wxTB_HORZ_TEXT</property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="tool" expanded="1">
<property name="bitmap">xpm/send20.xpm; Load From File</property>
<property name="id">wxID_BUTTONSEND</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">Send Coins</property>
<property name="name">m_tool1</property>
<property name="statusbar"></property>
<property name="tooltip"></property>
<event name="OnMenuSelection"></event>
<event name="OnToolClicked">OnButtonSend</event>
<event name="OnToolEnter"></event>
<event name="OnToolRClicked"></event>
<event name="OnUpdateUI"></event>
</object>
<object class="tool" expanded="1">
<property name="bitmap">xpm/addressbook20.xpm; Load From File</property>
<property name="id">wxID_BUTTONRECEIVE</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">Address Book</property>
<property name="name">m_tool2</property>
<property name="statusbar"></property>
<property name="tooltip"></property>
<event name="OnMenuSelection"></event>
<event name="OnToolClicked">OnButtonAddressBook</event>
<event name="OnToolEnter"></event>
<event name="OnToolRClicked"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="wxStatusBar" expanded="1">
<property name="bg">240,240,240</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="fields">1</property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_statusBar</property>
<property name="permission">public</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style">wxST_SIZEGRIP</property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer2</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">2</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer85</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="bg"></property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Your Bitcoin Address:</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_staticText32</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxTextCtrl" expanded="1">
<property name="bg"></property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_TEXTCTRLADDRESS</property>
<property name="maximum_size">-1,-1</property>
<property name="maxlength">0</property>
<property name="minimum_size">-1,-1</property>
<property name="name">m_textCtrlAddress</property>
<property name="permission">public</property>
<property name="pos"></property>
<property name="size">340,-1</property>
<property name="style">wxTE_READONLY</property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown">OnKeyDown</event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents">OnMouseEventsAddress</event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus">OnSetFocusAddress</event>
<event name="OnSize"></event>
<event name="OnText"></event>
<event name="OnTextEnter"></event>
<event name="OnTextMaxLen"></event>
<event name="OnTextURL"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxRIGHT|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="bg"></property>
<property name="context_help"></property>
<property name="default">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_BUTTONNEW</property>
<property name="label"> &amp;New... </property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_buttonNew</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="style">wxBU_EXACTFIT</property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnButtonNew</event>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="bg"></property>
<property name="context_help"></property>
<property name="default">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_BUTTONCOPY</property>
<property name="label"> &amp;Copy to Clipboard </property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_buttonCopy</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style">wxBU_EXACTFIT</property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnButtonCopy</event>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer3</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALIGN_BOTTOM|wxALL</property>
<property name="proportion">1</property>
<object class="wxPanel" expanded="1">
<property name="bg"></property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_panel14</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size"></property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer66</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="bg"></property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Balance:</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_staticText41</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size">-1,15</property>
<property name="style"></property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="bg">255,255,255</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font">,90,90,8,70,0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label"></property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_staticTextBalance</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size">120,15</property>
<property name="style">wxALIGN_RIGHT|wxST_NO_AUTORESIZE</property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_BOTTOM|wxTOP|wxRIGHT|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="1">
<property name="bg"></property>
<property name="choices">&quot; All&quot; &quot; Sent&quot; &quot; Received&quot; &quot; In Progress&quot;</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">1</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_choiceFilter</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="selection">0</property>
<property name="size">110,-1</property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnChoice"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxNotebook" expanded="1">
<property name="bg"></property>
<property name="bitmapsize"></property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_notebook</property>
<property name="permission">protected</property>
<property name="pos"></property>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment