move back to original directory structure
This commit is contained in:
208
src/base58.h
Normal file
208
src/base58.h
Normal file
@@ -0,0 +1,208 @@
|
||||
// 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.
|
||||
|
||||
|
||||
//
|
||||
// Why base-58 instead of standard base-64 encoding?
|
||||
// - Don't want 0OIl characters that look the same in some fonts and
|
||||
// could be used to create visually identical looking account numbers.
|
||||
// - A string with non-alphanumeric characters is not as easily accepted as an account number.
|
||||
// - E-mail usually won't line-break if there's no punctuation to break at.
|
||||
// - Doubleclicking selects the whole number as one word if it's all alphanumeric.
|
||||
//
|
||||
#ifndef BITCOIN_BASE58_H
|
||||
#define BITCOIN_BASE58_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "bignum.h"
|
||||
|
||||
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
|
||||
inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum bn58 = 58;
|
||||
CBigNum bn0 = 0;
|
||||
|
||||
// Convert big endian data to little endian
|
||||
// Extra zero at the end make sure bignum will interpret as a positive number
|
||||
std::vector<unsigned char> vchTmp(pend-pbegin+1, 0);
|
||||
reverse_copy(pbegin, pend, vchTmp.begin());
|
||||
|
||||
// Convert little endian data to bignum
|
||||
CBigNum bn;
|
||||
bn.setvch(vchTmp);
|
||||
|
||||
// Convert bignum to std::string
|
||||
std::string str;
|
||||
str.reserve((pend - pbegin) * 138 / 100 + 1);
|
||||
CBigNum dv;
|
||||
CBigNum rem;
|
||||
while (bn > bn0)
|
||||
{
|
||||
if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
|
||||
throw bignum_error("EncodeBase58 : BN_div failed");
|
||||
bn = dv;
|
||||
unsigned int c = rem.getulong();
|
||||
str += pszBase58[c];
|
||||
}
|
||||
|
||||
// Leading zeroes encoded as base58 zeros
|
||||
for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
|
||||
str += pszBase58[0];
|
||||
|
||||
// Convert little endian std::string to big endian
|
||||
reverse(str.begin(), str.end());
|
||||
return str;
|
||||
}
|
||||
|
||||
inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
return EncodeBase58(&vch[0], &vch[0] + vch.size());
|
||||
}
|
||||
|
||||
inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
vchRet.clear();
|
||||
CBigNum bn58 = 58;
|
||||
CBigNum bn = 0;
|
||||
CBigNum bnChar;
|
||||
while (isspace(*psz))
|
||||
psz++;
|
||||
|
||||
// Convert big endian string to bignum
|
||||
for (const char* p = psz; *p; p++)
|
||||
{
|
||||
const char* p1 = strchr(pszBase58, *p);
|
||||
if (p1 == NULL)
|
||||
{
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
if (*p != '\0')
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
bnChar.setulong(p1 - pszBase58);
|
||||
if (!BN_mul(&bn, &bn, &bn58, pctx))
|
||||
throw bignum_error("DecodeBase58 : BN_mul failed");
|
||||
bn += bnChar;
|
||||
}
|
||||
|
||||
// Get bignum as little endian data
|
||||
std::vector<unsigned char> vchTmp = bn.getvch();
|
||||
|
||||
// Trim off sign byte if present
|
||||
if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80)
|
||||
vchTmp.erase(vchTmp.end()-1);
|
||||
|
||||
// Restore leading zeros
|
||||
int nLeadingZeros = 0;
|
||||
for (const char* p = psz; *p == pszBase58[0]; p++)
|
||||
nLeadingZeros++;
|
||||
vchRet.assign(nLeadingZeros + vchTmp.size(), 0);
|
||||
|
||||
// Convert little endian data to big endian
|
||||
reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
return DecodeBase58(str.c_str(), vchRet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
|
||||
{
|
||||
// add 4-byte hash check to the end
|
||||
std::vector<unsigned char> vch(vchIn);
|
||||
uint256 hash = Hash(vch.begin(), vch.end());
|
||||
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
|
||||
return EncodeBase58(vch);
|
||||
}
|
||||
|
||||
inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
if (!DecodeBase58(psz, vchRet))
|
||||
return false;
|
||||
if (vchRet.size() < 4)
|
||||
{
|
||||
vchRet.clear();
|
||||
return false;
|
||||
}
|
||||
uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);
|
||||
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)
|
||||
{
|
||||
vchRet.clear();
|
||||
return false;
|
||||
}
|
||||
vchRet.resize(vchRet.size()-4);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
return DecodeBase58Check(str.c_str(), vchRet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define ADDRESSVERSION ((unsigned char)(fTestNet ? 111 : 0))
|
||||
|
||||
inline std::string Hash160ToAddress(uint160 hash160)
|
||||
{
|
||||
// add 1-byte version number to the front
|
||||
std::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)
|
||||
{
|
||||
std::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 std::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 std::string& str)
|
||||
{
|
||||
return IsValidBitcoinAddress(str.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline std::string PubKeyToAddress(const std::vector<unsigned char>& vchPubKey)
|
||||
{
|
||||
return Hash160ToAddress(Hash160(vchPubKey));
|
||||
}
|
||||
|
||||
#endif
|
||||
534
src/bignum.h
Normal file
534
src/bignum.h
Normal file
@@ -0,0 +1,534 @@
|
||||
// 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.
|
||||
#ifndef BITCOIN_BIGNUM_H
|
||||
#define BITCOIN_BIGNUM_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
class bignum_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit bignum_error(const std::string& str) : std::runtime_error(str) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CAutoBN_CTX
|
||||
{
|
||||
protected:
|
||||
BN_CTX* pctx;
|
||||
BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; }
|
||||
|
||||
public:
|
||||
CAutoBN_CTX()
|
||||
{
|
||||
pctx = BN_CTX_new();
|
||||
if (pctx == NULL)
|
||||
throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL");
|
||||
}
|
||||
|
||||
~CAutoBN_CTX()
|
||||
{
|
||||
if (pctx != NULL)
|
||||
BN_CTX_free(pctx);
|
||||
}
|
||||
|
||||
operator BN_CTX*() { return pctx; }
|
||||
BN_CTX& operator*() { return *pctx; }
|
||||
BN_CTX** operator&() { return &pctx; }
|
||||
bool operator!() { return (pctx == NULL); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CBigNum : public BIGNUM
|
||||
{
|
||||
public:
|
||||
CBigNum()
|
||||
{
|
||||
BN_init(this);
|
||||
}
|
||||
|
||||
CBigNum(const CBigNum& b)
|
||||
{
|
||||
BN_init(this);
|
||||
if (!BN_copy(this, &b))
|
||||
{
|
||||
BN_clear_free(this);
|
||||
throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed");
|
||||
}
|
||||
}
|
||||
|
||||
CBigNum& operator=(const CBigNum& b)
|
||||
{
|
||||
if (!BN_copy(this, &b))
|
||||
throw bignum_error("CBigNum::operator= : BN_copy failed");
|
||||
return (*this);
|
||||
}
|
||||
|
||||
~CBigNum()
|
||||
{
|
||||
BN_clear_free(this);
|
||||
}
|
||||
|
||||
CBigNum(char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
|
||||
CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
|
||||
CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
|
||||
CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
|
||||
CBigNum(int64 n) { BN_init(this); setint64(n); }
|
||||
CBigNum(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;
|
||||
std::string str;
|
||||
CBigNum bn = *this;
|
||||
BN_set_negative(&bn, false);
|
||||
CBigNum dv;
|
||||
CBigNum rem;
|
||||
if (BN_cmp(&bn, &bn0) == 0)
|
||||
return "0";
|
||||
while (BN_cmp(&bn, &bn0) > 0)
|
||||
{
|
||||
if (!BN_div(&dv, &rem, &bn, &bnBase, pctx))
|
||||
throw bignum_error("CBigNum::ToString() : BN_div failed");
|
||||
bn = dv;
|
||||
unsigned int c = rem.getulong();
|
||||
str += "0123456789abcdef"[c];
|
||||
}
|
||||
if (BN_is_negative(this))
|
||||
str += "-";
|
||||
reverse(str.begin(), str.end());
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string GetHex() const
|
||||
{
|
||||
return ToString(16);
|
||||
}
|
||||
|
||||
unsigned int GetSerializeSize(int nType=0, int nVersion=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)
|
||||
{
|
||||
std::vector<unsigned char> vch;
|
||||
::Unserialize(s, vch, nType, nVersion);
|
||||
setvch(vch);
|
||||
}
|
||||
|
||||
|
||||
bool operator!() const
|
||||
{
|
||||
return BN_is_zero(this);
|
||||
}
|
||||
|
||||
CBigNum& operator+=(const CBigNum& b)
|
||||
{
|
||||
if (!BN_add(this, this, &b))
|
||||
throw bignum_error("CBigNum::operator+= : BN_add failed");
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& operator-=(const CBigNum& b)
|
||||
{
|
||||
*this = *this - b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& operator*=(const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
if (!BN_mul(this, this, &b, pctx))
|
||||
throw bignum_error("CBigNum::operator*= : BN_mul failed");
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& operator/=(const CBigNum& b)
|
||||
{
|
||||
*this = *this / b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& operator%=(const CBigNum& b)
|
||||
{
|
||||
*this = *this % b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& operator<<=(unsigned int shift)
|
||||
{
|
||||
if (!BN_lshift(this, this, shift))
|
||||
throw bignum_error("CBigNum:operator<<= : BN_lshift failed");
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBigNum& operator>>=(unsigned int shift)
|
||||
{
|
||||
// Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
|
||||
// if built on ubuntu 9.04 or 9.10, probably depends on version of openssl
|
||||
CBigNum a = 1;
|
||||
a <<= shift;
|
||||
if (BN_cmp(&a, this) > 0)
|
||||
{
|
||||
*this = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!BN_rshift(this, this, shift))
|
||||
throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
CBigNum& operator++()
|
||||
{
|
||||
// prefix operator
|
||||
if (!BN_add(this, this, BN_value_one()))
|
||||
throw bignum_error("CBigNum::operator++ : BN_add failed");
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CBigNum operator++(int)
|
||||
{
|
||||
// postfix operator
|
||||
const CBigNum ret = *this;
|
||||
++(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CBigNum& operator--()
|
||||
{
|
||||
// prefix operator
|
||||
CBigNum r;
|
||||
if (!BN_sub(&r, this, BN_value_one()))
|
||||
throw bignum_error("CBigNum::operator-- : BN_sub failed");
|
||||
*this = r;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const CBigNum operator--(int)
|
||||
{
|
||||
// postfix operator
|
||||
const CBigNum ret = *this;
|
||||
--(*this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
|
||||
friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b);
|
||||
friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b);
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CBigNum r;
|
||||
if (!BN_add(&r, &a, &b))
|
||||
throw bignum_error("CBigNum::operator+ : BN_add failed");
|
||||
return r;
|
||||
}
|
||||
|
||||
inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CBigNum r;
|
||||
if (!BN_sub(&r, &a, &b))
|
||||
throw bignum_error("CBigNum::operator- : BN_sub failed");
|
||||
return r;
|
||||
}
|
||||
|
||||
inline const CBigNum operator-(const CBigNum& a)
|
||||
{
|
||||
CBigNum r(a);
|
||||
BN_set_negative(&r, !BN_is_negative(&r));
|
||||
return r;
|
||||
}
|
||||
|
||||
inline const CBigNum operator*(const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum r;
|
||||
if (!BN_mul(&r, &a, &b, pctx))
|
||||
throw bignum_error("CBigNum::operator* : BN_mul failed");
|
||||
return r;
|
||||
}
|
||||
|
||||
inline const CBigNum operator/(const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum r;
|
||||
if (!BN_div(&r, NULL, &a, &b, pctx))
|
||||
throw bignum_error("CBigNum::operator/ : BN_div failed");
|
||||
return r;
|
||||
}
|
||||
|
||||
inline const CBigNum operator%(const CBigNum& a, const CBigNum& b)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum r;
|
||||
if (!BN_mod(&r, &a, &b, pctx))
|
||||
throw bignum_error("CBigNum::operator% : BN_div failed");
|
||||
return r;
|
||||
}
|
||||
|
||||
inline const CBigNum operator<<(const CBigNum& a, unsigned int shift)
|
||||
{
|
||||
CBigNum r;
|
||||
if (!BN_lshift(&r, &a, shift))
|
||||
throw bignum_error("CBigNum:operator<< : BN_lshift failed");
|
||||
return r;
|
||||
}
|
||||
|
||||
inline const CBigNum operator>>(const CBigNum& a, unsigned int shift)
|
||||
{
|
||||
CBigNum r = a;
|
||||
r >>= shift;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); }
|
||||
inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); }
|
||||
inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); }
|
||||
inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); }
|
||||
inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); }
|
||||
inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); }
|
||||
|
||||
#endif
|
||||
462
src/cryptopp/config.h
Normal file
462
src/cryptopp/config.h
Normal file
@@ -0,0 +1,462 @@
|
||||
#ifndef CRYPTOPP_CONFIG_H
|
||||
#define CRYPTOPP_CONFIG_H
|
||||
|
||||
//// Bitcoin: disable SSE2 on 32-bit
|
||||
#if !defined(_M_X64) && !defined(__x86_64__)
|
||||
#define CRYPTOPP_DISABLE_SSE2 1
|
||||
#endif
|
||||
//////////// end of Bitcoin changes
|
||||
|
||||
|
||||
// ***************** Important Settings ********************
|
||||
|
||||
// define this if running on a big-endian CPU
|
||||
#if !defined(IS_LITTLE_ENDIAN) && (defined(__BIG_ENDIAN__) || defined(__sparc) || defined(__sparc__) || defined(__hppa__) || defined(__mips__) || (defined(__MWERKS__) && !defined(__INTEL__)))
|
||||
# define IS_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
// define this if running on a little-endian CPU
|
||||
// big endian will be assumed if IS_LITTLE_ENDIAN is not defined
|
||||
#ifndef IS_BIG_ENDIAN
|
||||
# define IS_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
// define this if you want to disable all OS-dependent features,
|
||||
// such as sockets and OS-provided random number generators
|
||||
// #define NO_OS_DEPENDENCE
|
||||
|
||||
// Define this to use features provided by Microsoft's CryptoAPI.
|
||||
// Currently the only feature used is random number generation.
|
||||
// This macro will be ignored if NO_OS_DEPENDENCE is defined.
|
||||
#define USE_MS_CRYPTOAPI
|
||||
|
||||
// Define this to 1 to enforce the requirement in FIPS 186-2 Change Notice 1 that only 1024 bit moduli be used
|
||||
#ifndef DSA_1024_BIT_MODULUS_ONLY
|
||||
# define DSA_1024_BIT_MODULUS_ONLY 1
|
||||
#endif
|
||||
|
||||
// ***************** Less Important Settings ***************
|
||||
|
||||
// define this to retain (as much as possible) old deprecated function and class names
|
||||
// #define CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY
|
||||
|
||||
#define GZIP_OS_CODE 0
|
||||
|
||||
// Try this if your CPU has 256K internal cache or a slow multiply instruction
|
||||
// and you want a (possibly) faster IDEA implementation using log tables
|
||||
// #define IDEA_LARGECACHE
|
||||
|
||||
// Define this if, for the linear congruential RNG, you want to use
|
||||
// the original constants as specified in S.K. Park and K.W. Miller's
|
||||
// CACM paper.
|
||||
// #define LCRNG_ORIGINAL_NUMBERS
|
||||
|
||||
// choose which style of sockets to wrap (mostly useful for cygwin which has both)
|
||||
#define PREFER_BERKELEY_STYLE_SOCKETS
|
||||
// #define PREFER_WINDOWS_STYLE_SOCKETS
|
||||
|
||||
// set the name of Rijndael cipher, was "Rijndael" before version 5.3
|
||||
#define CRYPTOPP_RIJNDAEL_NAME "AES"
|
||||
|
||||
// ***************** Important Settings Again ********************
|
||||
// But the defaults should be ok.
|
||||
|
||||
// namespace support is now required
|
||||
#ifdef NO_NAMESPACE
|
||||
# error namespace support is now required
|
||||
#endif
|
||||
|
||||
// Define this to workaround a Microsoft CryptoAPI bug where
|
||||
// each call to CryptAcquireContext causes a 100 KB memory leak.
|
||||
// Defining this will cause Crypto++ to make only one call to CryptAcquireContext.
|
||||
#define WORKAROUND_MS_BUG_Q258000
|
||||
|
||||
#ifdef CRYPTOPP_DOXYGEN_PROCESSING
|
||||
// Avoid putting "CryptoPP::" in front of everything in Doxygen output
|
||||
# define CryptoPP
|
||||
# define NAMESPACE_BEGIN(x)
|
||||
# define NAMESPACE_END
|
||||
// Get Doxygen to generate better documentation for these typedefs
|
||||
# define DOCUMENTED_TYPEDEF(x, y) class y : public x {};
|
||||
#else
|
||||
# define NAMESPACE_BEGIN(x) namespace x {
|
||||
# define NAMESPACE_END }
|
||||
# define DOCUMENTED_TYPEDEF(x, y) typedef x y;
|
||||
#endif
|
||||
#define ANONYMOUS_NAMESPACE_BEGIN namespace {
|
||||
#define USING_NAMESPACE(x) using namespace x;
|
||||
#define DOCUMENTED_NAMESPACE_BEGIN(x) namespace x {
|
||||
#define DOCUMENTED_NAMESPACE_END }
|
||||
|
||||
// What is the type of the third parameter to bind?
|
||||
// For Unix, the new standard is ::socklen_t (typically unsigned int), and the old standard is int.
|
||||
// Unfortunately there is no way to tell whether or not socklen_t is defined.
|
||||
// To work around this, TYPE_OF_SOCKLEN_T is a macro so that you can change it from the makefile.
|
||||
#ifndef TYPE_OF_SOCKLEN_T
|
||||
# if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# define TYPE_OF_SOCKLEN_T int
|
||||
# else
|
||||
# define TYPE_OF_SOCKLEN_T ::socklen_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__) && defined(PREFER_WINDOWS_STYLE_SOCKETS)
|
||||
# define __USE_W32_SOCKETS
|
||||
#endif
|
||||
|
||||
typedef unsigned char byte; // put in global namespace to avoid ambiguity with other byte typedefs
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
typedef unsigned short word16;
|
||||
typedef unsigned int word32;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef unsigned __int64 word64;
|
||||
#define W64LIT(x) x##ui64
|
||||
#else
|
||||
typedef unsigned long long word64;
|
||||
#define W64LIT(x) x##ULL
|
||||
#endif
|
||||
|
||||
// define large word type, used for file offsets and such
|
||||
typedef word64 lword;
|
||||
const lword LWORD_MAX = W64LIT(0xffffffffffffffff);
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define CRYPTOPP_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
// define hword, word, and dword. these are used for multiprecision integer arithmetic
|
||||
// Intel compiler won't have _umul128 until version 10.0. See http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30231625.aspx
|
||||
#if (defined(_MSC_VER) && (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000) && (defined(_M_X64) || defined(_M_IA64))) || (defined(__DECCXX) && defined(__alpha__)) || (defined(__INTEL_COMPILER) && defined(__x86_64__)) || (defined(__SUNPRO_CC) && defined(__x86_64__))
|
||||
typedef word32 hword;
|
||||
typedef word64 word;
|
||||
#else
|
||||
#define CRYPTOPP_NATIVE_DWORD_AVAILABLE
|
||||
#if defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || defined(__x86_64__) || defined(__mips64) || defined(__sparc64__)
|
||||
#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !(CRYPTOPP_GCC_VERSION == 40001 && defined(__APPLE__)) && CRYPTOPP_GCC_VERSION >= 30400
|
||||
// GCC 4.0.1 on MacOS X is missing __umodti3 and __udivti3
|
||||
// mode(TI) division broken on amd64 with GCC earlier than GCC 3.4
|
||||
typedef word32 hword;
|
||||
typedef word64 word;
|
||||
typedef __uint128_t dword;
|
||||
typedef __uint128_t word128;
|
||||
#define CRYPTOPP_WORD128_AVAILABLE
|
||||
#else
|
||||
// if we're here, it means we're on a 64-bit CPU but we don't have a way to obtain 128-bit multiplication results
|
||||
typedef word16 hword;
|
||||
typedef word32 word;
|
||||
typedef word64 dword;
|
||||
#endif
|
||||
#else
|
||||
// being here means the native register size is probably 32 bits or less
|
||||
#define CRYPTOPP_BOOL_SLOW_WORD64 1
|
||||
typedef word16 hword;
|
||||
typedef word32 word;
|
||||
typedef word64 dword;
|
||||
#endif
|
||||
#endif
|
||||
#ifndef CRYPTOPP_BOOL_SLOW_WORD64
|
||||
#define CRYPTOPP_BOOL_SLOW_WORD64 0
|
||||
#endif
|
||||
|
||||
const unsigned int WORD_SIZE = sizeof(word);
|
||||
const unsigned int WORD_BITS = WORD_SIZE * 8;
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#ifndef CRYPTOPP_L1_CACHE_LINE_SIZE
|
||||
// This should be a lower bound on the L1 cache line size. It's used for defense against timing attacks.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define CRYPTOPP_L1_CACHE_LINE_SIZE 64
|
||||
#else
|
||||
// L1 cache line size is 32 on Pentium III and earlier
|
||||
#define CRYPTOPP_L1_CACHE_LINE_SIZE 32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if _MSC_VER == 1200
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#if _MSC_VER > 1200 || defined(_mm_free)
|
||||
#define CRYPTOPP_MSVC6PP_OR_LATER // VC 6 processor pack or later
|
||||
#else
|
||||
#define CRYPTOPP_MSVC6_NO_PP // VC 6 without processor pack
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CRYPTOPP_ALIGN_DATA
|
||||
#if defined(CRYPTOPP_MSVC6PP_OR_LATER)
|
||||
#define CRYPTOPP_ALIGN_DATA(x) __declspec(align(x))
|
||||
#elif defined(__GNUC__)
|
||||
#define CRYPTOPP_ALIGN_DATA(x) __attribute__((aligned(x)))
|
||||
#else
|
||||
#define CRYPTOPP_ALIGN_DATA(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CRYPTOPP_SECTION_ALIGN16
|
||||
#if defined(__GNUC__) && !defined(__APPLE__)
|
||||
// the alignment attribute doesn't seem to work without this section attribute when -fdata-sections is turned on
|
||||
#define CRYPTOPP_SECTION_ALIGN16 __attribute__((section ("CryptoPP_Align16")))
|
||||
#else
|
||||
#define CRYPTOPP_SECTION_ALIGN16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) || defined(__fastcall)
|
||||
#define CRYPTOPP_FASTCALL __fastcall
|
||||
#else
|
||||
#define CRYPTOPP_FASTCALL
|
||||
#endif
|
||||
|
||||
// VC60 workaround: it doesn't allow typename in some places
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1300)
|
||||
#define CPP_TYPENAME
|
||||
#else
|
||||
#define CPP_TYPENAME typename
|
||||
#endif
|
||||
|
||||
// VC60 workaround: can't cast unsigned __int64 to float or double
|
||||
#if defined(_MSC_VER) && !defined(CRYPTOPP_MSVC6PP_OR_LATER)
|
||||
#define CRYPTOPP_VC6_INT64 (__int64)
|
||||
#else
|
||||
#define CRYPTOPP_VC6_INT64
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define CRYPTOPP_NO_VTABLE __declspec(novtable)
|
||||
#else
|
||||
#define CRYPTOPP_NO_VTABLE
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// 4231: nonstandard extension used : 'extern' before template explicit instantiation
|
||||
// 4250: dominance
|
||||
// 4251: member needs to have dll-interface
|
||||
// 4275: base needs to have dll-interface
|
||||
// 4660: explicitly instantiating a class that's already implicitly instantiated
|
||||
// 4661: no suitable definition provided for explicit template instantiation request
|
||||
// 4786: identifer was truncated in debug information
|
||||
// 4355: 'this' : used in base member initializer list
|
||||
// 4910: '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation
|
||||
# pragma warning(disable: 4231 4250 4251 4275 4660 4661 4786 4355 4910)
|
||||
#endif
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
// 8037: non-const function called for const object. needed to work around BCB2006 bug
|
||||
# pragma warn -8037
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER <= 1300) || defined(__MWERKS__) || defined(_STLPORT_VERSION)
|
||||
#define CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION
|
||||
#endif
|
||||
|
||||
#ifndef CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION
|
||||
#define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTOPP_DISABLE_X86ASM // for backwards compatibility: this macro had both meanings
|
||||
#define CRYPTOPP_DISABLE_ASM
|
||||
#define CRYPTOPP_DISABLE_SSE2
|
||||
#endif
|
||||
|
||||
#if !defined(CRYPTOPP_DISABLE_ASM) && ((defined(_MSC_VER) && defined(_M_IX86)) || (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))))
|
||||
#define CRYPTOPP_X86_ASM_AVAILABLE
|
||||
|
||||
#if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(CRYPTOPP_MSVC6PP_OR_LATER) || CRYPTOPP_GCC_VERSION >= 30300)
|
||||
#define CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE 1
|
||||
#else
|
||||
#define CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE 0
|
||||
#endif
|
||||
|
||||
// SSSE3 was actually introduced in GNU as 2.17, which was released 6/23/2006, but we can't tell what version of binutils is installed.
|
||||
// GCC 4.1.2 was released on 2/13/2007, so we'll use that as a proxy for the binutils version.
|
||||
#if !defined(CRYPTOPP_DISABLE_SSSE3) && (_MSC_VER >= 1400 || CRYPTOPP_GCC_VERSION >= 40102)
|
||||
#define CRYPTOPP_BOOL_SSSE3_ASM_AVAILABLE 1
|
||||
#else
|
||||
#define CRYPTOPP_BOOL_SSSE3_ASM_AVAILABLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(CRYPTOPP_DISABLE_ASM) && defined(_MSC_VER) && defined(_M_X64)
|
||||
#define CRYPTOPP_X64_MASM_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if !defined(CRYPTOPP_DISABLE_ASM) && defined(__GNUC__) && defined(__x86_64__)
|
||||
#define CRYPTOPP_X64_ASM_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(CRYPTOPP_MSVC6PP_OR_LATER) || defined(__SSE2__))
|
||||
#define CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE 1
|
||||
#else
|
||||
#define CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE 0
|
||||
#endif
|
||||
|
||||
#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE || CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE || defined(CRYPTOPP_X64_MASM_AVAILABLE)
|
||||
#define CRYPTOPP_BOOL_ALIGN16_ENABLED 1
|
||||
#else
|
||||
#define CRYPTOPP_BOOL_ALIGN16_ENABLED 0
|
||||
#endif
|
||||
|
||||
// how to allocate 16-byte aligned memory (for SSE2)
|
||||
#if defined(CRYPTOPP_MSVC6PP_OR_LATER)
|
||||
#define CRYPTOPP_MM_MALLOC_AVAILABLE
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#define CRYPTOPP_MALLOC_ALIGNMENT_IS_16
|
||||
#elif defined(__linux__) || defined(__sun__) || defined(__CYGWIN__)
|
||||
#define CRYPTOPP_MEMALIGN_AVAILABLE
|
||||
#else
|
||||
#define CRYPTOPP_NO_ALIGNED_ALLOC
|
||||
#endif
|
||||
|
||||
// how to disable inlining
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1300
|
||||
# define CRYPTOPP_NOINLINE_DOTDOTDOT
|
||||
# define CRYPTOPP_NOINLINE __declspec(noinline)
|
||||
#elif defined(__GNUC__)
|
||||
# define CRYPTOPP_NOINLINE_DOTDOTDOT
|
||||
# define CRYPTOPP_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
# define CRYPTOPP_NOINLINE_DOTDOTDOT ...
|
||||
# define CRYPTOPP_NOINLINE
|
||||
#endif
|
||||
|
||||
// how to declare class constants
|
||||
#if (defined(_MSC_VER) && _MSC_VER <= 1300) || defined(__INTEL_COMPILER)
|
||||
# define CRYPTOPP_CONSTANT(x) enum {x};
|
||||
#else
|
||||
# define CRYPTOPP_CONSTANT(x) static const int x;
|
||||
#endif
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define CRYPTOPP_BOOL_X64 1
|
||||
#else
|
||||
#define CRYPTOPP_BOOL_X64 0
|
||||
#endif
|
||||
|
||||
// see http://predef.sourceforge.net/prearch.html
|
||||
#if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_X86_) || defined(__I86__) || defined(__INTEL__)
|
||||
#define CRYPTOPP_BOOL_X86 1
|
||||
#else
|
||||
#define CRYPTOPP_BOOL_X86 0
|
||||
#endif
|
||||
|
||||
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86 || defined(__powerpc__)
|
||||
#define CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
|
||||
#endif
|
||||
|
||||
#define CRYPTOPP_VERSION 560
|
||||
|
||||
// ***************** determine availability of OS features ********************
|
||||
|
||||
#ifndef NO_OS_DEPENDENCE
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define CRYPTOPP_WIN32_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if defined(__unix__) || defined(__MACH__) || defined(__NetBSD__) || defined(__sun)
|
||||
#define CRYPTOPP_UNIX_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_WIN32_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE)
|
||||
# define HIGHRES_TIMER_AVAILABLE
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTOPP_UNIX_AVAILABLE
|
||||
# define HAS_BERKELEY_STYLE_SOCKETS
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTOPP_WIN32_AVAILABLE
|
||||
# define HAS_WINDOWS_STYLE_SOCKETS
|
||||
#endif
|
||||
|
||||
#if defined(HIGHRES_TIMER_AVAILABLE) && (defined(HAS_BERKELEY_STYLE_SOCKETS) || defined(HAS_WINDOWS_STYLE_SOCKETS))
|
||||
# define SOCKETS_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if defined(HAS_WINDOWS_STYLE_SOCKETS) && (!defined(HAS_BERKELEY_STYLE_SOCKETS) || defined(PREFER_WINDOWS_STYLE_SOCKETS))
|
||||
# define USE_WINDOWS_STYLE_SOCKETS
|
||||
#else
|
||||
# define USE_BERKELEY_STYLE_SOCKETS
|
||||
#endif
|
||||
|
||||
#if defined(HIGHRES_TIMER_AVAILABLE) && defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(USE_BERKELEY_STYLE_SOCKETS)
|
||||
# define WINDOWS_PIPES_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(USE_MS_CRYPTOAPI)
|
||||
# define NONBLOCKING_RNG_AVAILABLE
|
||||
# define OS_RNG_AVAILABLE
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING)
|
||||
# define NONBLOCKING_RNG_AVAILABLE
|
||||
# define BLOCKING_RNG_AVAILABLE
|
||||
# define OS_RNG_AVAILABLE
|
||||
# define HAS_PTHREADS
|
||||
# define THREADS_AVAILABLE
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTOPP_WIN32_AVAILABLE
|
||||
# define HAS_WINTHREADS
|
||||
# define THREADS_AVAILABLE
|
||||
#endif
|
||||
|
||||
#endif // NO_OS_DEPENDENCE
|
||||
|
||||
// ***************** DLL related ********************
|
||||
|
||||
#ifdef CRYPTOPP_WIN32_AVAILABLE
|
||||
|
||||
#ifdef CRYPTOPP_EXPORTS
|
||||
#define CRYPTOPP_IS_DLL
|
||||
#define CRYPTOPP_DLL __declspec(dllexport)
|
||||
#elif defined(CRYPTOPP_IMPORTS)
|
||||
#define CRYPTOPP_IS_DLL
|
||||
#define CRYPTOPP_DLL __declspec(dllimport)
|
||||
#else
|
||||
#define CRYPTOPP_DLL
|
||||
#endif
|
||||
|
||||
#define CRYPTOPP_API __cdecl
|
||||
|
||||
#else // CRYPTOPP_WIN32_AVAILABLE
|
||||
|
||||
#define CRYPTOPP_DLL
|
||||
#define CRYPTOPP_API
|
||||
|
||||
#endif // CRYPTOPP_WIN32_AVAILABLE
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
#define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern class CRYPTOPP_DLL
|
||||
#elif defined(__BORLANDC__) || defined(__SUNPRO_CC)
|
||||
#define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL
|
||||
#else
|
||||
#define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern template class CRYPTOPP_DLL
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_IMPORTS)
|
||||
#define CRYPTOPP_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL
|
||||
#else
|
||||
#define CRYPTOPP_DLL_TEMPLATE_CLASS CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS
|
||||
#endif
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
#define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern class
|
||||
#elif defined(__BORLANDC__) || defined(__SUNPRO_CC)
|
||||
#define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS template class
|
||||
#else
|
||||
#define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern template class
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_EXPORTS)
|
||||
#define CRYPTOPP_STATIC_TEMPLATE_CLASS template class
|
||||
#else
|
||||
#define CRYPTOPP_STATIC_TEMPLATE_CLASS CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
199
src/cryptopp/cpu.cpp
Normal file
199
src/cryptopp/cpu.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
// cpu.cpp - written and placed in the public domain by Wei Dai
|
||||
|
||||
#include "cryptopp/pch.h"
|
||||
|
||||
#ifndef CRYPTOPP_IMPORTS
|
||||
|
||||
#include "cryptopp/cpu.h"
|
||||
#include "cryptopp/misc.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTOPP_MSVC6PP_OR_LATER
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
#ifdef CRYPTOPP_X86_ASM_AVAILABLE
|
||||
|
||||
#ifndef _MSC_VER
|
||||
typedef void (*SigHandler)(int);
|
||||
|
||||
static jmp_buf s_jmpNoCPUID;
|
||||
static void SigIllHandlerCPUID(int)
|
||||
{
|
||||
longjmp(s_jmpNoCPUID, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CpuId(word32 input, word32 *output)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
__try
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, input
|
||||
cpuid
|
||||
mov edi, output
|
||||
mov [edi], eax
|
||||
mov [edi+4], ebx
|
||||
mov [edi+8], ecx
|
||||
mov [edi+12], edx
|
||||
}
|
||||
}
|
||||
__except (1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
|
||||
if (oldHandler == SIG_ERR)
|
||||
return false;
|
||||
|
||||
bool result = true;
|
||||
if (setjmp(s_jmpNoCPUID))
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
// save ebx in case -fPIC is being used
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
"push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
|
||||
#else
|
||||
"pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
|
||||
#endif
|
||||
: "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
|
||||
: "a" (input)
|
||||
);
|
||||
}
|
||||
|
||||
signal(SIGILL, oldHandler);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
static jmp_buf s_jmpNoSSE2;
|
||||
static void SigIllHandlerSSE2(int)
|
||||
{
|
||||
longjmp(s_jmpNoSSE2, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
|
||||
|
||||
bool CpuId(word32 input, word32 *output)
|
||||
{
|
||||
__cpuid((int *)output, input);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTOPP_CPUID_AVAILABLE
|
||||
|
||||
static bool TrySSE2()
|
||||
{
|
||||
#if CRYPTOPP_BOOL_X64
|
||||
return true;
|
||||
#elif defined(_MSC_VER)
|
||||
__try
|
||||
{
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
AS2(por xmm0, xmm0) // executing SSE2 instruction
|
||||
#elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
|
||||
__mm128i x = _mm_setzero_si128();
|
||||
return _mm_cvtsi128_si32(x) == 0;
|
||||
#endif
|
||||
}
|
||||
__except (1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#elif defined(__GNUC__)
|
||||
SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
|
||||
if (oldHandler == SIG_ERR)
|
||||
return false;
|
||||
|
||||
bool result = true;
|
||||
if (setjmp(s_jmpNoSSE2))
|
||||
result = false;
|
||||
else
|
||||
{
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
__asm __volatile ("por %xmm0, %xmm0");
|
||||
#elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
|
||||
__mm128i x = _mm_setzero_si128();
|
||||
result = _mm_cvtsi128_si32(x) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
signal(SIGILL, oldHandler);
|
||||
return result;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool g_x86DetectionDone = false;
|
||||
bool g_hasISSE = false, g_hasSSE2 = false, g_hasSSSE3 = false, g_hasMMX = false, g_isP4 = false;
|
||||
word32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
|
||||
|
||||
void DetectX86Features()
|
||||
{
|
||||
word32 cpuid[4], cpuid1[4];
|
||||
if (!CpuId(0, cpuid))
|
||||
return;
|
||||
if (!CpuId(1, cpuid1))
|
||||
return;
|
||||
|
||||
g_hasMMX = (cpuid1[3] & (1 << 23)) != 0;
|
||||
if ((cpuid1[3] & (1 << 26)) != 0)
|
||||
g_hasSSE2 = TrySSE2();
|
||||
g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9));
|
||||
|
||||
if ((cpuid1[3] & (1 << 25)) != 0)
|
||||
g_hasISSE = true;
|
||||
else
|
||||
{
|
||||
word32 cpuid2[4];
|
||||
CpuId(0x080000000, cpuid2);
|
||||
if (cpuid2[0] >= 0x080000001)
|
||||
{
|
||||
CpuId(0x080000001, cpuid2);
|
||||
g_hasISSE = (cpuid2[3] & (1 << 22)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(cpuid[2], cpuid[3]);
|
||||
if (memcmp(cpuid+1, "GenuineIntel", 12) == 0)
|
||||
{
|
||||
g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
|
||||
g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
|
||||
}
|
||||
else if (memcmp(cpuid+1, "AuthenticAMD", 12) == 0)
|
||||
{
|
||||
CpuId(0x80000005, cpuid);
|
||||
g_cacheLineSize = GETBYTE(cpuid[2], 0);
|
||||
}
|
||||
|
||||
if (!g_cacheLineSize)
|
||||
g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
|
||||
|
||||
g_x86DetectionDone = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
||||
263
src/cryptopp/cpu.h
Normal file
263
src/cryptopp/cpu.h
Normal file
@@ -0,0 +1,263 @@
|
||||
#ifndef CRYPTOPP_CPU_H
|
||||
#define CRYPTOPP_CPU_H
|
||||
|
||||
#ifdef CRYPTOPP_GENERATE_X64_MASM
|
||||
|
||||
#define CRYPTOPP_X86_ASM_AVAILABLE
|
||||
#define CRYPTOPP_BOOL_X64 1
|
||||
#define CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE 1
|
||||
#define NAMESPACE_END
|
||||
|
||||
#else
|
||||
|
||||
#include "cryptopp/config.h"
|
||||
|
||||
#ifdef CRYPTOPP_MSVC6PP_OR_LATER
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
#if defined(CRYPTOPP_X86_ASM_AVAILABLE) || (_MSC_VER >= 1400 && CRYPTOPP_BOOL_X64)
|
||||
|
||||
#define CRYPTOPP_CPUID_AVAILABLE
|
||||
|
||||
// these should not be used directly
|
||||
extern CRYPTOPP_DLL bool g_x86DetectionDone;
|
||||
extern CRYPTOPP_DLL bool g_hasSSE2;
|
||||
extern CRYPTOPP_DLL bool g_hasISSE;
|
||||
extern CRYPTOPP_DLL bool g_hasMMX;
|
||||
extern CRYPTOPP_DLL bool g_hasSSSE3;
|
||||
extern CRYPTOPP_DLL bool g_isP4;
|
||||
extern CRYPTOPP_DLL word32 g_cacheLineSize;
|
||||
CRYPTOPP_DLL void CRYPTOPP_API DetectX86Features();
|
||||
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API CpuId(word32 input, word32 *output);
|
||||
|
||||
#if CRYPTOPP_BOOL_X64
|
||||
inline bool HasSSE2() {return true;}
|
||||
inline bool HasISSE() {return true;}
|
||||
inline bool HasMMX() {return true;}
|
||||
#else
|
||||
|
||||
inline bool HasSSE2()
|
||||
{
|
||||
if (!g_x86DetectionDone)
|
||||
DetectX86Features();
|
||||
return g_hasSSE2;
|
||||
}
|
||||
|
||||
inline bool HasISSE()
|
||||
{
|
||||
if (!g_x86DetectionDone)
|
||||
DetectX86Features();
|
||||
return g_hasISSE;
|
||||
}
|
||||
|
||||
inline bool HasMMX()
|
||||
{
|
||||
if (!g_x86DetectionDone)
|
||||
DetectX86Features();
|
||||
return g_hasMMX;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline bool HasSSSE3()
|
||||
{
|
||||
if (!g_x86DetectionDone)
|
||||
DetectX86Features();
|
||||
return g_hasSSSE3;
|
||||
}
|
||||
|
||||
inline bool IsP4()
|
||||
{
|
||||
if (!g_x86DetectionDone)
|
||||
DetectX86Features();
|
||||
return g_isP4;
|
||||
}
|
||||
|
||||
inline int GetCacheLineSize()
|
||||
{
|
||||
if (!g_x86DetectionDone)
|
||||
DetectX86Features();
|
||||
return g_cacheLineSize;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline int GetCacheLineSize()
|
||||
{
|
||||
return CRYPTOPP_L1_CACHE_LINE_SIZE;
|
||||
}
|
||||
|
||||
inline bool HasSSSE3() {return false;}
|
||||
inline bool IsP4() {return false;}
|
||||
|
||||
// assume MMX and SSE2 if intrinsics are enabled
|
||||
#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE || CRYPTOPP_BOOL_X64
|
||||
inline bool HasSSE2() {return true;}
|
||||
inline bool HasISSE() {return true;}
|
||||
inline bool HasMMX() {return true;}
|
||||
#else
|
||||
inline bool HasSSE2() {return false;}
|
||||
inline bool HasISSE() {return false;}
|
||||
inline bool HasMMX() {return false;}
|
||||
#endif
|
||||
|
||||
#endif // #ifdef CRYPTOPP_X86_ASM_AVAILABLE || _MSC_VER >= 1400
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTOPP_GENERATE_X64_MASM
|
||||
#define AS1(x) x*newline*
|
||||
#define AS2(x, y) x, y*newline*
|
||||
#define AS3(x, y, z) x, y, z*newline*
|
||||
#define ASS(x, y, a, b, c, d) x, y, a*64+b*16+c*4+d*newline*
|
||||
#define ASL(x) label##x:*newline*
|
||||
#define ASJ(x, y, z) x label##y*newline*
|
||||
#define ASC(x, y) x label##y*newline*
|
||||
#define AS_HEX(y) 0##y##h
|
||||
#elif defined(__GNUC__)
|
||||
// define these in two steps to allow arguments to be expanded
|
||||
#define GNU_AS1(x) #x ";"
|
||||
#define GNU_AS2(x, y) #x ", " #y ";"
|
||||
#define GNU_AS3(x, y, z) #x ", " #y ", " #z ";"
|
||||
#define GNU_ASL(x) "\n" #x ":"
|
||||
#define GNU_ASJ(x, y, z) #x " " #y #z ";"
|
||||
#define AS1(x) GNU_AS1(x)
|
||||
#define AS2(x, y) GNU_AS2(x, y)
|
||||
#define AS3(x, y, z) GNU_AS3(x, y, z)
|
||||
#define ASS(x, y, a, b, c, d) #x ", " #y ", " #a "*64+" #b "*16+" #c "*4+" #d ";"
|
||||
#define ASL(x) GNU_ASL(x)
|
||||
#define ASJ(x, y, z) GNU_ASJ(x, y, z)
|
||||
#define ASC(x, y) #x " " #y ";"
|
||||
#define CRYPTOPP_NAKED
|
||||
#define AS_HEX(y) 0x##y
|
||||
#else
|
||||
#define AS1(x) __asm {x}
|
||||
#define AS2(x, y) __asm {x, y}
|
||||
#define AS3(x, y, z) __asm {x, y, z}
|
||||
#define ASS(x, y, a, b, c, d) __asm {x, y, _MM_SHUFFLE(a, b, c, d)}
|
||||
#define ASL(x) __asm {label##x:}
|
||||
#define ASJ(x, y, z) __asm {x label##y}
|
||||
#define ASC(x, y) __asm {x label##y}
|
||||
#define CRYPTOPP_NAKED __declspec(naked)
|
||||
#define AS_HEX(y) 0x##y
|
||||
#endif
|
||||
|
||||
#define IF0(y)
|
||||
#define IF1(y) y
|
||||
|
||||
#ifdef CRYPTOPP_GENERATE_X64_MASM
|
||||
#define ASM_MOD(x, y) ((x) MOD (y))
|
||||
#define XMMWORD_PTR XMMWORD PTR
|
||||
#else
|
||||
// GNU assembler doesn't seem to have mod operator
|
||||
#define ASM_MOD(x, y) ((x)-((x)/(y))*(y))
|
||||
// GAS 2.15 doesn't support XMMWORD PTR. it seems necessary only for MASM
|
||||
#define XMMWORD_PTR
|
||||
#endif
|
||||
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
#define AS_REG_1 ecx
|
||||
#define AS_REG_2 edx
|
||||
#define AS_REG_3 esi
|
||||
#define AS_REG_4 edi
|
||||
#define AS_REG_5 eax
|
||||
#define AS_REG_6 ebx
|
||||
#define AS_REG_7 ebp
|
||||
#define AS_REG_1d ecx
|
||||
#define AS_REG_2d edx
|
||||
#define AS_REG_3d esi
|
||||
#define AS_REG_4d edi
|
||||
#define AS_REG_5d eax
|
||||
#define AS_REG_6d ebx
|
||||
#define AS_REG_7d ebp
|
||||
#define WORD_SZ 4
|
||||
#define WORD_REG(x) e##x
|
||||
#define WORD_PTR DWORD PTR
|
||||
#define AS_PUSH_IF86(x) AS1(push e##x)
|
||||
#define AS_POP_IF86(x) AS1(pop e##x)
|
||||
#define AS_JCXZ jecxz
|
||||
#elif CRYPTOPP_BOOL_X64
|
||||
#ifdef CRYPTOPP_GENERATE_X64_MASM
|
||||
#define AS_REG_1 rcx
|
||||
#define AS_REG_2 rdx
|
||||
#define AS_REG_3 r8
|
||||
#define AS_REG_4 r9
|
||||
#define AS_REG_5 rax
|
||||
#define AS_REG_6 r10
|
||||
#define AS_REG_7 r11
|
||||
#define AS_REG_1d ecx
|
||||
#define AS_REG_2d edx
|
||||
#define AS_REG_3d r8d
|
||||
#define AS_REG_4d r9d
|
||||
#define AS_REG_5d eax
|
||||
#define AS_REG_6d r10d
|
||||
#define AS_REG_7d r11d
|
||||
#else
|
||||
#define AS_REG_1 rdi
|
||||
#define AS_REG_2 rsi
|
||||
#define AS_REG_3 rdx
|
||||
#define AS_REG_4 rcx
|
||||
#define AS_REG_5 r8
|
||||
#define AS_REG_6 r9
|
||||
#define AS_REG_7 r10
|
||||
#define AS_REG_1d edi
|
||||
#define AS_REG_2d esi
|
||||
#define AS_REG_3d edx
|
||||
#define AS_REG_4d ecx
|
||||
#define AS_REG_5d r8d
|
||||
#define AS_REG_6d r9d
|
||||
#define AS_REG_7d r10d
|
||||
#endif
|
||||
#define WORD_SZ 8
|
||||
#define WORD_REG(x) r##x
|
||||
#define WORD_PTR QWORD PTR
|
||||
#define AS_PUSH_IF86(x)
|
||||
#define AS_POP_IF86(x)
|
||||
#define AS_JCXZ jrcxz
|
||||
#endif
|
||||
|
||||
// helper macro for stream cipher output
|
||||
#define AS_XMM_OUTPUT4(labelPrefix, inputPtr, outputPtr, x0, x1, x2, x3, t, p0, p1, p2, p3, increment)\
|
||||
AS2( test inputPtr, inputPtr)\
|
||||
ASC( jz, labelPrefix##3)\
|
||||
AS2( test inputPtr, 15)\
|
||||
ASC( jnz, labelPrefix##7)\
|
||||
AS2( pxor xmm##x0, [inputPtr+p0*16])\
|
||||
AS2( pxor xmm##x1, [inputPtr+p1*16])\
|
||||
AS2( pxor xmm##x2, [inputPtr+p2*16])\
|
||||
AS2( pxor xmm##x3, [inputPtr+p3*16])\
|
||||
AS2( add inputPtr, increment*16)\
|
||||
ASC( jmp, labelPrefix##3)\
|
||||
ASL(labelPrefix##7)\
|
||||
AS2( movdqu xmm##t, [inputPtr+p0*16])\
|
||||
AS2( pxor xmm##x0, xmm##t)\
|
||||
AS2( movdqu xmm##t, [inputPtr+p1*16])\
|
||||
AS2( pxor xmm##x1, xmm##t)\
|
||||
AS2( movdqu xmm##t, [inputPtr+p2*16])\
|
||||
AS2( pxor xmm##x2, xmm##t)\
|
||||
AS2( movdqu xmm##t, [inputPtr+p3*16])\
|
||||
AS2( pxor xmm##x3, xmm##t)\
|
||||
AS2( add inputPtr, increment*16)\
|
||||
ASL(labelPrefix##3)\
|
||||
AS2( test outputPtr, 15)\
|
||||
ASC( jnz, labelPrefix##8)\
|
||||
AS2( movdqa [outputPtr+p0*16], xmm##x0)\
|
||||
AS2( movdqa [outputPtr+p1*16], xmm##x1)\
|
||||
AS2( movdqa [outputPtr+p2*16], xmm##x2)\
|
||||
AS2( movdqa [outputPtr+p3*16], xmm##x3)\
|
||||
ASC( jmp, labelPrefix##9)\
|
||||
ASL(labelPrefix##8)\
|
||||
AS2( movdqu [outputPtr+p0*16], xmm##x0)\
|
||||
AS2( movdqu [outputPtr+p1*16], xmm##x1)\
|
||||
AS2( movdqu [outputPtr+p2*16], xmm##x2)\
|
||||
AS2( movdqu [outputPtr+p3*16], xmm##x3)\
|
||||
ASL(labelPrefix##9)\
|
||||
AS2( add outputPtr, increment*16)
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
||||
1668
src/cryptopp/cryptlib.h
Normal file
1668
src/cryptopp/cryptlib.h
Normal file
File diff suppressed because it is too large
Load Diff
29
src/cryptopp/iterhash.h
Normal file
29
src/cryptopp/iterhash.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef CRYPTOPP_ITERHASH_H
|
||||
#define CRYPTOPP_ITERHASH_H
|
||||
|
||||
#include "cryptopp/secblock.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
// *** trimmed down dependency from iterhash.h ***
|
||||
template <class T_HashWordType, class T_Endianness, unsigned int T_BlockSize, unsigned int T_StateSize, class T_Transform, unsigned int T_DigestSize = 0, bool T_StateAligned = false>
|
||||
class CRYPTOPP_NO_VTABLE IteratedHashWithStaticTransform
|
||||
{
|
||||
public:
|
||||
CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize ? T_DigestSize : T_StateSize)
|
||||
unsigned int DigestSize() const {return DIGESTSIZE;};
|
||||
typedef T_HashWordType HashWordType;
|
||||
CRYPTOPP_CONSTANT(BLOCKSIZE = T_BlockSize)
|
||||
|
||||
protected:
|
||||
IteratedHashWithStaticTransform() {this->Init();}
|
||||
void HashEndianCorrectedBlock(const T_HashWordType *data) {T_Transform::Transform(this->m_state, data);}
|
||||
void Init() {T_Transform::InitState(this->m_state);}
|
||||
|
||||
T_HashWordType* StateBuf() {return this->m_state;}
|
||||
FixedSizeAlignedSecBlock<T_HashWordType, T_BlockSize/sizeof(T_HashWordType), T_StateAligned> m_state;
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
||||
1134
src/cryptopp/misc.h
Normal file
1134
src/cryptopp/misc.h
Normal file
File diff suppressed because it is too large
Load Diff
21
src/cryptopp/pch.h
Normal file
21
src/cryptopp/pch.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef CRYPTOPP_PCH_H
|
||||
#define CRYPTOPP_PCH_H
|
||||
|
||||
#ifdef CRYPTOPP_GENERATE_X64_MASM
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#else
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef USE_PRECOMPILED_HEADERS
|
||||
#include "simple.h"
|
||||
#include "secblock.h"
|
||||
#include "misc.h"
|
||||
#include "smartptr.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
501
src/cryptopp/secblock.h
Normal file
501
src/cryptopp/secblock.h
Normal file
@@ -0,0 +1,501 @@
|
||||
// secblock.h - written and placed in the public domain by Wei Dai
|
||||
|
||||
#ifndef CRYPTOPP_SECBLOCK_H
|
||||
#define CRYPTOPP_SECBLOCK_H
|
||||
|
||||
#include "cryptopp/config.h"
|
||||
#include "cryptopp/misc.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX)
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
// ************** secure memory allocation ***************
|
||||
|
||||
template<class T>
|
||||
class AllocatorBase
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef size_t size_type;
|
||||
#ifdef CRYPTOPP_MSVCRT6
|
||||
typedef ptrdiff_t difference_type;
|
||||
#else
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
#endif
|
||||
typedef T * pointer;
|
||||
typedef const T * const_pointer;
|
||||
typedef T & reference;
|
||||
typedef const T & const_reference;
|
||||
|
||||
pointer address(reference r) const {return (&r);}
|
||||
const_pointer address(const_reference r) const {return (&r); }
|
||||
void construct(pointer p, const T& val) {new (p) T(val);}
|
||||
void destroy(pointer p) {p->~T();}
|
||||
size_type max_size() const {return ~size_type(0)/sizeof(T);} // switch to std::numeric_limits<T>::max later
|
||||
|
||||
protected:
|
||||
static void CheckSize(size_t n)
|
||||
{
|
||||
if (n > ~size_t(0) / sizeof(T))
|
||||
throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
|
||||
}
|
||||
};
|
||||
|
||||
#define CRYPTOPP_INHERIT_ALLOCATOR_TYPES \
|
||||
typedef typename AllocatorBase<T>::value_type value_type;\
|
||||
typedef typename AllocatorBase<T>::size_type size_type;\
|
||||
typedef typename AllocatorBase<T>::difference_type difference_type;\
|
||||
typedef typename AllocatorBase<T>::pointer pointer;\
|
||||
typedef typename AllocatorBase<T>::const_pointer const_pointer;\
|
||||
typedef typename AllocatorBase<T>::reference reference;\
|
||||
typedef typename AllocatorBase<T>::const_reference const_reference;
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1300)
|
||||
// this pragma causes an internal compiler error if placed immediately before std::swap(a, b)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4700) // VC60 workaround: don't know how to get rid of this warning
|
||||
#endif
|
||||
|
||||
template <class T, class A>
|
||||
typename A::pointer StandardReallocate(A& a, T *p, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
|
||||
{
|
||||
if (oldSize == newSize)
|
||||
return p;
|
||||
|
||||
if (preserve)
|
||||
{
|
||||
typename A::pointer newPointer = a.allocate(newSize, NULL);
|
||||
memcpy_s(newPointer, sizeof(T)*newSize, p, sizeof(T)*STDMIN(oldSize, newSize));
|
||||
a.deallocate(p, oldSize);
|
||||
return newPointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
a.deallocate(p, oldSize);
|
||||
return a.allocate(newSize, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1300)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class T, bool T_Align16 = false>
|
||||
class AllocatorWithCleanup : public AllocatorBase<T>
|
||||
{
|
||||
public:
|
||||
CRYPTOPP_INHERIT_ALLOCATOR_TYPES
|
||||
|
||||
pointer allocate(size_type n, const void * = NULL)
|
||||
{
|
||||
CheckSize(n);
|
||||
if (n == 0)
|
||||
return NULL;
|
||||
|
||||
if (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16 && n*sizeof(T) >= 16)
|
||||
{
|
||||
byte *p;
|
||||
#ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
|
||||
while (!(p = (byte *)_mm_malloc(sizeof(T)*n, 16)))
|
||||
#elif defined(CRYPTOPP_MEMALIGN_AVAILABLE)
|
||||
while (!(p = (byte *)memalign(16, sizeof(T)*n)))
|
||||
#elif defined(CRYPTOPP_MALLOC_ALIGNMENT_IS_16)
|
||||
while (!(p = (byte *)malloc(sizeof(T)*n)))
|
||||
#else
|
||||
while (!(p = (byte *)malloc(sizeof(T)*n + 16)))
|
||||
#endif
|
||||
CallNewHandler();
|
||||
|
||||
#ifdef CRYPTOPP_NO_ALIGNED_ALLOC
|
||||
size_t adjustment = 16-((size_t)p%16);
|
||||
p += adjustment;
|
||||
p[-1] = (byte)adjustment;
|
||||
#endif
|
||||
|
||||
assert(IsAlignedOn(p, 16));
|
||||
return (pointer)p;
|
||||
}
|
||||
|
||||
pointer p;
|
||||
while (!(p = (pointer)malloc(sizeof(T)*n)))
|
||||
CallNewHandler();
|
||||
return p;
|
||||
}
|
||||
|
||||
void deallocate(void *p, size_type n)
|
||||
{
|
||||
memset_z(p, 0, n*sizeof(T));
|
||||
|
||||
if (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16 && n*sizeof(T) >= 16)
|
||||
{
|
||||
#ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
|
||||
_mm_free(p);
|
||||
#elif defined(CRYPTOPP_NO_ALIGNED_ALLOC)
|
||||
p = (byte *)p - ((byte *)p)[-1];
|
||||
free(p);
|
||||
#else
|
||||
free(p);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve)
|
||||
{
|
||||
return StandardReallocate(*this, p, oldSize, newSize, preserve);
|
||||
}
|
||||
|
||||
// VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a
|
||||
// template class member called rebind".
|
||||
template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
|
||||
#if _MSC_VER >= 1500
|
||||
AllocatorWithCleanup() {}
|
||||
template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
|
||||
CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
|
||||
CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
|
||||
CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
class NullAllocator : public AllocatorBase<T>
|
||||
{
|
||||
public:
|
||||
CRYPTOPP_INHERIT_ALLOCATOR_TYPES
|
||||
|
||||
pointer allocate(size_type n, const void * = NULL)
|
||||
{
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void deallocate(void *p, size_type n)
|
||||
{
|
||||
//// Bitcoin: don't know why this trips, probably a false alarm, depends on the compiler used.
|
||||
//assert(false);
|
||||
}
|
||||
|
||||
size_type max_size() const {return 0;}
|
||||
};
|
||||
|
||||
// This allocator can't be used with standard collections because
|
||||
// they require that all objects of the same allocator type are equivalent.
|
||||
// So this is for use with SecBlock only.
|
||||
template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
|
||||
class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
|
||||
{
|
||||
public:
|
||||
CRYPTOPP_INHERIT_ALLOCATOR_TYPES
|
||||
|
||||
FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
|
||||
|
||||
pointer allocate(size_type n)
|
||||
{
|
||||
assert(IsAlignedOn(m_array, 8));
|
||||
|
||||
if (n <= S && !m_allocated)
|
||||
{
|
||||
m_allocated = true;
|
||||
return GetAlignedArray();
|
||||
}
|
||||
else
|
||||
return m_fallbackAllocator.allocate(n);
|
||||
}
|
||||
|
||||
pointer allocate(size_type n, const void *hint)
|
||||
{
|
||||
if (n <= S && !m_allocated)
|
||||
{
|
||||
m_allocated = true;
|
||||
return GetAlignedArray();
|
||||
}
|
||||
else
|
||||
return m_fallbackAllocator.allocate(n, hint);
|
||||
}
|
||||
|
||||
void deallocate(void *p, size_type n)
|
||||
{
|
||||
if (p == GetAlignedArray())
|
||||
{
|
||||
assert(n <= S);
|
||||
assert(m_allocated);
|
||||
m_allocated = false;
|
||||
memset(p, 0, n*sizeof(T));
|
||||
}
|
||||
else
|
||||
m_fallbackAllocator.deallocate(p, n);
|
||||
}
|
||||
|
||||
pointer reallocate(pointer p, size_type oldSize, size_type newSize, bool preserve)
|
||||
{
|
||||
if (p == GetAlignedArray() && newSize <= S)
|
||||
{
|
||||
assert(oldSize <= S);
|
||||
if (oldSize > newSize)
|
||||
memset(p + newSize, 0, (oldSize-newSize)*sizeof(T));
|
||||
return p;
|
||||
}
|
||||
|
||||
pointer newPointer = allocate(newSize, NULL);
|
||||
if (preserve)
|
||||
memcpy(newPointer, p, sizeof(T)*STDMIN(oldSize, newSize));
|
||||
deallocate(p, oldSize);
|
||||
return newPointer;
|
||||
}
|
||||
|
||||
size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
|
||||
|
||||
private:
|
||||
#ifdef __BORLANDC__
|
||||
T* GetAlignedArray() {return m_array;}
|
||||
T m_array[S];
|
||||
#else
|
||||
T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
|
||||
CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? S+8/sizeof(T) : S];
|
||||
#endif
|
||||
A m_fallbackAllocator;
|
||||
bool m_allocated;
|
||||
};
|
||||
|
||||
//! a block of memory allocated using A
|
||||
template <class T, class A = AllocatorWithCleanup<T> >
|
||||
class SecBlock
|
||||
{
|
||||
public:
|
||||
typedef typename A::value_type value_type;
|
||||
typedef typename A::pointer iterator;
|
||||
typedef typename A::const_pointer const_iterator;
|
||||
typedef typename A::size_type size_type;
|
||||
|
||||
explicit SecBlock(size_type size=0)
|
||||
: m_size(size) {m_ptr = m_alloc.allocate(size, NULL);}
|
||||
SecBlock(const SecBlock<T, A> &t)
|
||||
: m_size(t.m_size) {m_ptr = m_alloc.allocate(m_size, NULL); memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));}
|
||||
SecBlock(const T *t, size_type len)
|
||||
: m_size(len)
|
||||
{
|
||||
m_ptr = m_alloc.allocate(len, NULL);
|
||||
if (t == NULL)
|
||||
memset_z(m_ptr, 0, len*sizeof(T));
|
||||
else
|
||||
memcpy(m_ptr, t, len*sizeof(T));
|
||||
}
|
||||
|
||||
~SecBlock()
|
||||
{m_alloc.deallocate(m_ptr, m_size);}
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
operator T *() const
|
||||
{return (T*)m_ptr;}
|
||||
#else
|
||||
operator const void *() const
|
||||
{return m_ptr;}
|
||||
operator void *()
|
||||
{return m_ptr;}
|
||||
|
||||
operator const T *() const
|
||||
{return m_ptr;}
|
||||
operator T *()
|
||||
{return m_ptr;}
|
||||
#endif
|
||||
|
||||
// T *operator +(size_type offset)
|
||||
// {return m_ptr+offset;}
|
||||
|
||||
// const T *operator +(size_type offset) const
|
||||
// {return m_ptr+offset;}
|
||||
|
||||
// T& operator[](size_type index)
|
||||
// {assert(index >= 0 && index < m_size); return m_ptr[index];}
|
||||
|
||||
// const T& operator[](size_type index) const
|
||||
// {assert(index >= 0 && index < m_size); return m_ptr[index];}
|
||||
|
||||
iterator begin()
|
||||
{return m_ptr;}
|
||||
const_iterator begin() const
|
||||
{return m_ptr;}
|
||||
iterator end()
|
||||
{return m_ptr+m_size;}
|
||||
const_iterator end() const
|
||||
{return m_ptr+m_size;}
|
||||
|
||||
typename A::pointer data() {return m_ptr;}
|
||||
typename A::const_pointer data() const {return m_ptr;}
|
||||
|
||||
size_type size() const {return m_size;}
|
||||
bool empty() const {return m_size == 0;}
|
||||
|
||||
byte * BytePtr() {return (byte *)m_ptr;}
|
||||
const byte * BytePtr() const {return (const byte *)m_ptr;}
|
||||
size_type SizeInBytes() const {return m_size*sizeof(T);}
|
||||
|
||||
//! set contents and size
|
||||
void Assign(const T *t, size_type len)
|
||||
{
|
||||
New(len);
|
||||
memcpy_s(m_ptr, m_size*sizeof(T), t, len*sizeof(T));
|
||||
}
|
||||
|
||||
//! copy contents and size from another SecBlock
|
||||
void Assign(const SecBlock<T, A> &t)
|
||||
{
|
||||
New(t.m_size);
|
||||
memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));
|
||||
}
|
||||
|
||||
SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
|
||||
{
|
||||
Assign(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// append to this object
|
||||
SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
|
||||
{
|
||||
size_type oldSize = m_size;
|
||||
Grow(m_size+t.m_size);
|
||||
memcpy_s(m_ptr+oldSize, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// append operator
|
||||
SecBlock<T, A> operator+(const SecBlock<T, A> &t)
|
||||
{
|
||||
SecBlock<T, A> result(m_size+t.m_size);
|
||||
memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
|
||||
memcpy_s(result.m_ptr+m_size, t.m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const SecBlock<T, A> &t) const
|
||||
{
|
||||
return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
|
||||
}
|
||||
|
||||
bool operator!=(const SecBlock<T, A> &t) const
|
||||
{
|
||||
return !operator==(t);
|
||||
}
|
||||
|
||||
//! change size, without preserving contents
|
||||
void New(size_type newSize)
|
||||
{
|
||||
m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
|
||||
m_size = newSize;
|
||||
}
|
||||
|
||||
//! change size and set contents to 0
|
||||
void CleanNew(size_type newSize)
|
||||
{
|
||||
New(newSize);
|
||||
memset_z(m_ptr, 0, m_size*sizeof(T));
|
||||
}
|
||||
|
||||
//! change size only if newSize > current size. contents are preserved
|
||||
void Grow(size_type newSize)
|
||||
{
|
||||
if (newSize > m_size)
|
||||
{
|
||||
m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
|
||||
m_size = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
//! change size only if newSize > current size. contents are preserved and additional area is set to 0
|
||||
void CleanGrow(size_type newSize)
|
||||
{
|
||||
if (newSize > m_size)
|
||||
{
|
||||
m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
|
||||
memset(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
|
||||
m_size = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
//! change size and preserve contents
|
||||
void resize(size_type newSize)
|
||||
{
|
||||
m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
|
||||
m_size = newSize;
|
||||
}
|
||||
|
||||
//! swap contents and size with another SecBlock
|
||||
void swap(SecBlock<T, A> &b)
|
||||
{
|
||||
std::swap(m_alloc, b.m_alloc);
|
||||
std::swap(m_size, b.m_size);
|
||||
std::swap(m_ptr, b.m_ptr);
|
||||
}
|
||||
|
||||
//private:
|
||||
A m_alloc;
|
||||
size_type m_size;
|
||||
T *m_ptr;
|
||||
};
|
||||
|
||||
typedef SecBlock<byte> SecByteBlock;
|
||||
typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
|
||||
typedef SecBlock<word> SecWordBlock;
|
||||
|
||||
//! a SecBlock with fixed size, allocated statically
|
||||
template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
|
||||
class FixedSizeSecBlock : public SecBlock<T, A>
|
||||
{
|
||||
public:
|
||||
explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
|
||||
};
|
||||
|
||||
template <class T, unsigned int S, bool T_Align16 = true>
|
||||
class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
|
||||
{
|
||||
};
|
||||
|
||||
//! a SecBlock that preallocates size S statically, and uses the heap when this size is exceeded
|
||||
template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
|
||||
class SecBlockWithHint : public SecBlock<T, A>
|
||||
{
|
||||
public:
|
||||
explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
|
||||
};
|
||||
|
||||
template<class T, bool A, class U, bool B>
|
||||
inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
|
||||
template<class T, bool A, class U, bool B>
|
||||
inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
NAMESPACE_BEGIN(std)
|
||||
template <class T, class A>
|
||||
inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
#if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
|
||||
// working for STLport 5.1.3 and MSVC 6 SP5
|
||||
template <class _Tp1, class _Tp2>
|
||||
inline CryptoPP::AllocatorWithCleanup<_Tp2>&
|
||||
__stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
|
||||
{
|
||||
return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
|
||||
}
|
||||
#endif
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
||||
899
src/cryptopp/sha.cpp
Normal file
899
src/cryptopp/sha.cpp
Normal file
@@ -0,0 +1,899 @@
|
||||
// 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.
|
||||
|
||||
// use "cl /EP /P /DCRYPTOPP_GENERATE_X64_MASM sha.cpp" to generate MASM code
|
||||
|
||||
#include "cryptopp/pch.h"
|
||||
|
||||
#ifndef CRYPTOPP_IMPORTS
|
||||
#ifndef CRYPTOPP_GENERATE_X64_MASM
|
||||
|
||||
#include "cryptopp/sha.h"
|
||||
#include "cryptopp/misc.h"
|
||||
#include "cryptopp/cpu.h"
|
||||
|
||||
NAMESPACE_BEGIN(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));
|
||||
}
|
||||
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
CRYPTOPP_ALIGN_DATA(16) extern const word32 SHA256_K[64] CRYPTOPP_SECTION_ALIGN16 = {
|
||||
#else
|
||||
extern const word32 SHA256_K[64] = {
|
||||
#endif
|
||||
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
|
||||
};
|
||||
|
||||
#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM
|
||||
|
||||
#if defined(CRYPTOPP_X86_ASM_AVAILABLE) || defined(CRYPTOPP_GENERATE_X64_MASM)
|
||||
|
||||
#pragma warning(disable: 4731) // frame pointer register 'ebp' modified by inline assembly code
|
||||
|
||||
static void CRYPTOPP_FASTCALL X86_SHA256_HashBlocks(word32 *state, const word32 *data, size_t len
|
||||
#if defined(_MSC_VER) && (_MSC_VER == 1200)
|
||||
, ... // VC60 workaround: prevent VC 6 from inlining this function
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if defined(_MSC_VER) && (_MSC_VER == 1200)
|
||||
AS2(mov ecx, [state])
|
||||
AS2(mov edx, [data])
|
||||
#endif
|
||||
|
||||
#define LOCALS_SIZE 8*4 + 16*4 + 4*WORD_SZ
|
||||
#define H(i) [BASE+ASM_MOD(1024+7-(i),8)*4]
|
||||
#define G(i) H(i+1)
|
||||
#define F(i) H(i+2)
|
||||
#define E(i) H(i+3)
|
||||
#define D(i) H(i+4)
|
||||
#define C(i) H(i+5)
|
||||
#define B(i) H(i+6)
|
||||
#define A(i) H(i+7)
|
||||
#define Wt(i) BASE+8*4+ASM_MOD(1024+15-(i),16)*4
|
||||
#define Wt_2(i) Wt((i)-2)
|
||||
#define Wt_15(i) Wt((i)-15)
|
||||
#define Wt_7(i) Wt((i)-7)
|
||||
#define K_END [BASE+8*4+16*4+0*WORD_SZ]
|
||||
#define STATE_SAVE [BASE+8*4+16*4+1*WORD_SZ]
|
||||
#define DATA_SAVE [BASE+8*4+16*4+2*WORD_SZ]
|
||||
#define DATA_END [BASE+8*4+16*4+3*WORD_SZ]
|
||||
#define Kt(i) WORD_REG(si)+(i)*4
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
#define BASE esp+4
|
||||
#elif defined(__GNUC__)
|
||||
#define BASE r8
|
||||
#else
|
||||
#define BASE rsp
|
||||
#endif
|
||||
|
||||
#define RA0(i, edx, edi) \
|
||||
AS2( add edx, [Kt(i)] )\
|
||||
AS2( add edx, [Wt(i)] )\
|
||||
AS2( add edx, H(i) )\
|
||||
|
||||
#define RA1(i, edx, edi)
|
||||
|
||||
#define RB0(i, edx, edi)
|
||||
|
||||
#define RB1(i, edx, edi) \
|
||||
AS2( mov AS_REG_7d, [Wt_2(i)] )\
|
||||
AS2( mov edi, [Wt_15(i)])\
|
||||
AS2( mov ebx, AS_REG_7d )\
|
||||
AS2( shr AS_REG_7d, 10 )\
|
||||
AS2( ror ebx, 17 )\
|
||||
AS2( xor AS_REG_7d, ebx )\
|
||||
AS2( ror ebx, 2 )\
|
||||
AS2( xor ebx, AS_REG_7d )/* s1(W_t-2) */\
|
||||
AS2( add ebx, [Wt_7(i)])\
|
||||
AS2( mov AS_REG_7d, edi )\
|
||||
AS2( shr AS_REG_7d, 3 )\
|
||||
AS2( ror edi, 7 )\
|
||||
AS2( add ebx, [Wt(i)])/* s1(W_t-2) + W_t-7 + W_t-16 */\
|
||||
AS2( xor AS_REG_7d, edi )\
|
||||
AS2( add edx, [Kt(i)])\
|
||||
AS2( ror edi, 11 )\
|
||||
AS2( add edx, H(i) )\
|
||||
AS2( xor AS_REG_7d, edi )/* s0(W_t-15) */\
|
||||
AS2( add AS_REG_7d, ebx )/* W_t = s1(W_t-2) + W_t-7 + s0(W_t-15) W_t-16*/\
|
||||
AS2( mov [Wt(i)], AS_REG_7d)\
|
||||
AS2( add edx, AS_REG_7d )\
|
||||
|
||||
#define ROUND(i, r, eax, ecx, edi, edx)\
|
||||
/* in: edi = E */\
|
||||
/* unused: eax, ecx, temp: ebx, AS_REG_7d, out: edx = T1 */\
|
||||
AS2( mov edx, F(i) )\
|
||||
AS2( xor edx, G(i) )\
|
||||
AS2( and edx, edi )\
|
||||
AS2( xor edx, G(i) )/* Ch(E,F,G) = (G^(E&(F^G))) */\
|
||||
AS2( mov AS_REG_7d, edi )\
|
||||
AS2( ror edi, 6 )\
|
||||
AS2( ror AS_REG_7d, 25 )\
|
||||
RA##r(i, edx, edi )/* H + Wt + Kt + Ch(E,F,G) */\
|
||||
AS2( xor AS_REG_7d, edi )\
|
||||
AS2( ror edi, 5 )\
|
||||
AS2( xor AS_REG_7d, edi )/* S1(E) */\
|
||||
AS2( add edx, AS_REG_7d )/* T1 = S1(E) + Ch(E,F,G) + H + Wt + Kt */\
|
||||
RB##r(i, edx, edi )/* H + Wt + Kt + Ch(E,F,G) */\
|
||||
/* in: ecx = A, eax = B^C, edx = T1 */\
|
||||
/* unused: edx, temp: ebx, AS_REG_7d, out: eax = A, ecx = B^C, edx = E */\
|
||||
AS2( mov ebx, ecx )\
|
||||
AS2( xor ecx, B(i) )/* A^B */\
|
||||
AS2( and eax, ecx )\
|
||||
AS2( xor eax, B(i) )/* Maj(A,B,C) = B^((A^B)&(B^C) */\
|
||||
AS2( mov AS_REG_7d, ebx )\
|
||||
AS2( ror ebx, 2 )\
|
||||
AS2( add eax, edx )/* T1 + Maj(A,B,C) */\
|
||||
AS2( add edx, D(i) )\
|
||||
AS2( mov D(i), edx )\
|
||||
AS2( ror AS_REG_7d, 22 )\
|
||||
AS2( xor AS_REG_7d, ebx )\
|
||||
AS2( ror ebx, 11 )\
|
||||
AS2( xor AS_REG_7d, ebx )\
|
||||
AS2( add eax, AS_REG_7d )/* T1 + S0(A) + Maj(A,B,C) */\
|
||||
AS2( mov H(i), eax )\
|
||||
|
||||
#define SWAP_COPY(i) \
|
||||
AS2( mov WORD_REG(bx), [WORD_REG(dx)+i*WORD_SZ])\
|
||||
AS1( bswap WORD_REG(bx))\
|
||||
AS2( mov [Wt(i*(1+CRYPTOPP_BOOL_X64)+CRYPTOPP_BOOL_X64)], WORD_REG(bx))
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if CRYPTOPP_BOOL_X64
|
||||
FixedSizeAlignedSecBlock<byte, LOCALS_SIZE> workspace;
|
||||
#endif
|
||||
__asm__ __volatile__
|
||||
(
|
||||
#if CRYPTOPP_BOOL_X64
|
||||
"lea %4, %%r8;"
|
||||
#endif
|
||||
".intel_syntax noprefix;"
|
||||
#elif defined(CRYPTOPP_GENERATE_X64_MASM)
|
||||
ALIGN 8
|
||||
X86_SHA256_HashBlocks PROC FRAME
|
||||
rex_push_reg rsi
|
||||
push_reg rdi
|
||||
push_reg rbx
|
||||
push_reg rbp
|
||||
alloc_stack(LOCALS_SIZE+8)
|
||||
.endprolog
|
||||
mov rdi, r8
|
||||
lea rsi, [?SHA256_K@CryptoPP@@3QBIB + 48*4]
|
||||
#endif
|
||||
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
#ifndef __GNUC__
|
||||
AS2( mov edi, [len])
|
||||
AS2( lea WORD_REG(si), [SHA256_K+48*4])
|
||||
#endif
|
||||
#if !defined(_MSC_VER) || (_MSC_VER < 1400)
|
||||
AS_PUSH_IF86(bx)
|
||||
#endif
|
||||
|
||||
AS_PUSH_IF86(bp)
|
||||
AS2( mov ebx, esp)
|
||||
AS2( and esp, -16)
|
||||
AS2( sub WORD_REG(sp), LOCALS_SIZE)
|
||||
AS_PUSH_IF86(bx)
|
||||
#endif
|
||||
AS2( mov STATE_SAVE, WORD_REG(cx))
|
||||
AS2( mov DATA_SAVE, WORD_REG(dx))
|
||||
AS2( add WORD_REG(di), WORD_REG(dx))
|
||||
AS2( mov DATA_END, WORD_REG(di))
|
||||
AS2( mov K_END, WORD_REG(si))
|
||||
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
AS2( test edi, 1)
|
||||
ASJ( jnz, 2, f)
|
||||
#endif
|
||||
AS2( movdqa xmm0, XMMWORD_PTR [WORD_REG(cx)+0*16])
|
||||
AS2( movdqa xmm1, XMMWORD_PTR [WORD_REG(cx)+1*16])
|
||||
#endif
|
||||
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
ASJ( jmp, 0, f)
|
||||
#endif
|
||||
ASL(2) // non-SSE2
|
||||
AS2( mov esi, ecx)
|
||||
AS2( lea edi, A(0))
|
||||
AS2( mov ecx, 8)
|
||||
AS1( rep movsd)
|
||||
AS2( mov esi, K_END)
|
||||
ASJ( jmp, 3, f)
|
||||
#endif
|
||||
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
ASL(0)
|
||||
AS2( movdqa E(0), xmm1)
|
||||
AS2( movdqa A(0), xmm0)
|
||||
#endif
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
ASL(3)
|
||||
#endif
|
||||
AS2( sub WORD_REG(si), 48*4)
|
||||
SWAP_COPY(0) SWAP_COPY(1) SWAP_COPY(2) SWAP_COPY(3)
|
||||
SWAP_COPY(4) SWAP_COPY(5) SWAP_COPY(6) SWAP_COPY(7)
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
SWAP_COPY(8) SWAP_COPY(9) SWAP_COPY(10) SWAP_COPY(11)
|
||||
SWAP_COPY(12) SWAP_COPY(13) SWAP_COPY(14) SWAP_COPY(15)
|
||||
#endif
|
||||
AS2( mov edi, E(0)) // E
|
||||
AS2( mov eax, B(0)) // B
|
||||
AS2( xor eax, C(0)) // B^C
|
||||
AS2( mov ecx, A(0)) // A
|
||||
|
||||
ROUND(0, 0, eax, ecx, edi, edx)
|
||||
ROUND(1, 0, ecx, eax, edx, edi)
|
||||
ROUND(2, 0, eax, ecx, edi, edx)
|
||||
ROUND(3, 0, ecx, eax, edx, edi)
|
||||
ROUND(4, 0, eax, ecx, edi, edx)
|
||||
ROUND(5, 0, ecx, eax, edx, edi)
|
||||
ROUND(6, 0, eax, ecx, edi, edx)
|
||||
ROUND(7, 0, ecx, eax, edx, edi)
|
||||
ROUND(8, 0, eax, ecx, edi, edx)
|
||||
ROUND(9, 0, ecx, eax, edx, edi)
|
||||
ROUND(10, 0, eax, ecx, edi, edx)
|
||||
ROUND(11, 0, ecx, eax, edx, edi)
|
||||
ROUND(12, 0, eax, ecx, edi, edx)
|
||||
ROUND(13, 0, ecx, eax, edx, edi)
|
||||
ROUND(14, 0, eax, ecx, edi, edx)
|
||||
ROUND(15, 0, ecx, eax, edx, edi)
|
||||
|
||||
ASL(1)
|
||||
AS2(add WORD_REG(si), 4*16)
|
||||
ROUND(0, 1, eax, ecx, edi, edx)
|
||||
ROUND(1, 1, ecx, eax, edx, edi)
|
||||
ROUND(2, 1, eax, ecx, edi, edx)
|
||||
ROUND(3, 1, ecx, eax, edx, edi)
|
||||
ROUND(4, 1, eax, ecx, edi, edx)
|
||||
ROUND(5, 1, ecx, eax, edx, edi)
|
||||
ROUND(6, 1, eax, ecx, edi, edx)
|
||||
ROUND(7, 1, ecx, eax, edx, edi)
|
||||
ROUND(8, 1, eax, ecx, edi, edx)
|
||||
ROUND(9, 1, ecx, eax, edx, edi)
|
||||
ROUND(10, 1, eax, ecx, edi, edx)
|
||||
ROUND(11, 1, ecx, eax, edx, edi)
|
||||
ROUND(12, 1, eax, ecx, edi, edx)
|
||||
ROUND(13, 1, ecx, eax, edx, edi)
|
||||
ROUND(14, 1, eax, ecx, edi, edx)
|
||||
ROUND(15, 1, ecx, eax, edx, edi)
|
||||
AS2( cmp WORD_REG(si), K_END)
|
||||
ASJ( jne, 1, b)
|
||||
|
||||
AS2( mov WORD_REG(dx), DATA_SAVE)
|
||||
AS2( add WORD_REG(dx), 64)
|
||||
AS2( mov AS_REG_7, STATE_SAVE)
|
||||
AS2( mov DATA_SAVE, WORD_REG(dx))
|
||||
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
AS2( test DWORD PTR DATA_END, 1)
|
||||
ASJ( jnz, 4, f)
|
||||
#endif
|
||||
AS2( movdqa xmm1, XMMWORD_PTR [AS_REG_7+1*16])
|
||||
AS2( movdqa xmm0, XMMWORD_PTR [AS_REG_7+0*16])
|
||||
AS2( paddd xmm1, E(0))
|
||||
AS2( paddd xmm0, A(0))
|
||||
AS2( movdqa [AS_REG_7+1*16], xmm1)
|
||||
AS2( movdqa [AS_REG_7+0*16], xmm0)
|
||||
AS2( cmp WORD_REG(dx), DATA_END)
|
||||
ASJ( jl, 0, b)
|
||||
#endif
|
||||
|
||||
#if CRYPTOPP_BOOL_X86
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
ASJ( jmp, 5, f)
|
||||
ASL(4) // non-SSE2
|
||||
#endif
|
||||
AS2( add [AS_REG_7+0*4], ecx) // A
|
||||
AS2( add [AS_REG_7+4*4], edi) // E
|
||||
AS2( mov eax, B(0))
|
||||
AS2( mov ebx, C(0))
|
||||
AS2( mov ecx, D(0))
|
||||
AS2( add [AS_REG_7+1*4], eax)
|
||||
AS2( add [AS_REG_7+2*4], ebx)
|
||||
AS2( add [AS_REG_7+3*4], ecx)
|
||||
AS2( mov eax, F(0))
|
||||
AS2( mov ebx, G(0))
|
||||
AS2( mov ecx, H(0))
|
||||
AS2( add [AS_REG_7+5*4], eax)
|
||||
AS2( add [AS_REG_7+6*4], ebx)
|
||||
AS2( add [AS_REG_7+7*4], ecx)
|
||||
AS2( mov ecx, AS_REG_7d)
|
||||
AS2( cmp WORD_REG(dx), DATA_END)
|
||||
ASJ( jl, 2, b)
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
|
||||
ASL(5)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
AS_POP_IF86(sp)
|
||||
AS_POP_IF86(bp)
|
||||
#if !defined(_MSC_VER) || (_MSC_VER < 1400)
|
||||
AS_POP_IF86(bx)
|
||||
#endif
|
||||
|
||||
#ifdef CRYPTOPP_GENERATE_X64_MASM
|
||||
add rsp, LOCALS_SIZE+8
|
||||
pop rbp
|
||||
pop rbx
|
||||
pop rdi
|
||||
pop rsi
|
||||
ret
|
||||
X86_SHA256_HashBlocks ENDP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
".att_syntax prefix;"
|
||||
:
|
||||
: "c" (state), "d" (data), "S" (SHA256_K+48), "D" (len)
|
||||
#if CRYPTOPP_BOOL_X64
|
||||
, "m" (workspace[0])
|
||||
#endif
|
||||
: "memory", "cc", "%eax"
|
||||
#if CRYPTOPP_BOOL_X64
|
||||
, "%rbx", "%r8"
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // #if defined(CRYPTOPP_X86_ASM_AVAILABLE) || defined(CRYPTOPP_GENERATE_X64_MASM)
|
||||
|
||||
#ifndef CRYPTOPP_GENERATE_X64_MASM
|
||||
|
||||
#ifdef CRYPTOPP_X64_MASM_AVAILABLE
|
||||
extern "C" {
|
||||
void CRYPTOPP_FASTCALL X86_SHA256_HashBlocks(word32 *state, const word32 *data, size_t len);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_X86_ASM_AVAILABLE) || defined(CRYPTOPP_X64_MASM_AVAILABLE)
|
||||
|
||||
size_t SHA256::HashMultipleBlocks(const word32 *input, size_t length)
|
||||
{
|
||||
X86_SHA256_HashBlocks(m_state, input, (length&(size_t(0)-BLOCKSIZE)) - !HasSSE2());
|
||||
return length % BLOCKSIZE;
|
||||
}
|
||||
|
||||
size_t SHA224::HashMultipleBlocks(const word32 *input, size_t length)
|
||||
{
|
||||
X86_SHA256_HashBlocks(m_state, input, (length&(size_t(0)-BLOCKSIZE)) - !HasSSE2());
|
||||
return length % BLOCKSIZE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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) (y^((x^y)&(y^z)))
|
||||
|
||||
#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];
|
||||
#if defined(CRYPTOPP_X86_ASM_AVAILABLE) || defined(CRYPTOPP_X64_MASM_AVAILABLE)
|
||||
// this byte reverse is a waste of time, but this function is only called by MDC
|
||||
ByteReverse(W, data, BLOCKSIZE);
|
||||
X86_SHA256_HashBlocks(state, W, BLOCKSIZE - !HasSSE2());
|
||||
#else
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
// 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 += SHA256_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 += SHA256_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 += SHA256_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
|
||||
|
||||
// *************************************************************
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE && CRYPTOPP_BOOL_X86
|
||||
CRYPTOPP_ALIGN_DATA(16) static const word64 SHA512_K[80] CRYPTOPP_SECTION_ALIGN16 = {
|
||||
#else
|
||||
static const word64 SHA512_K[80] = {
|
||||
#endif
|
||||
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( movdqa xmm0, [ecx+0*16])
|
||||
AS2( movdq2q mm4, xmm0)
|
||||
AS2( movdqa [edi+0*16], xmm0)
|
||||
AS2( movdqa xmm0, [ecx+1*16])
|
||||
AS2( movdqa [edi+1*16], xmm0)
|
||||
AS2( movdqa xmm0, [ecx+2*16])
|
||||
AS2( movdq2q mm5, xmm0)
|
||||
AS2( movdqa [edi+2*16], xmm0)
|
||||
AS2( movdqa xmm0, [ecx+3*16])
|
||||
AS2( movdqa [edi+3*16], xmm0)
|
||||
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( movdqa xmm0, [edi+i*16])\
|
||||
AS2( paddq xmm0, [ecx+i*16])\
|
||||
AS2( movdqa [ecx+i*16], xmm0)
|
||||
|
||||
SSE2_CombineState(0)
|
||||
SSE2_CombineState(1)
|
||||
SSE2_CombineState(2)
|
||||
SSE2_CombineState(3)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif // #ifndef CRYPTOPP_GENERATE_X64_MASM
|
||||
#endif // #ifndef CRYPTOPP_IMPORTS
|
||||
63
src/cryptopp/sha.h
Normal file
63
src/cryptopp/sha.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef CRYPTOPP_SHA_H
|
||||
#define CRYPTOPP_SHA_H
|
||||
|
||||
#include "cryptopp/iterhash.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
/// <a href="http://www.weidai.com/scan-mirror/md.html#SHA-1">SHA-1</a>
|
||||
class CRYPTOPP_DLL SHA1 : public IteratedHashWithStaticTransform<word32, BigEndian, 64, 20, SHA1>
|
||||
{
|
||||
public:
|
||||
static void CRYPTOPP_API InitState(HashWordType *state);
|
||||
static void CRYPTOPP_API Transform(word32 *digest, const word32 *data);
|
||||
static const char * CRYPTOPP_API StaticAlgorithmName() {return "SHA-1";}
|
||||
};
|
||||
|
||||
typedef SHA1 SHA; // for backwards compatibility
|
||||
|
||||
//! implements the SHA-256 standard
|
||||
class CRYPTOPP_DLL SHA256 : public IteratedHashWithStaticTransform<word32, BigEndian, 64, 32, SHA256, 32, true>
|
||||
{
|
||||
public:
|
||||
#if defined(CRYPTOPP_X86_ASM_AVAILABLE) || defined(CRYPTOPP_X64_MASM_AVAILABLE)
|
||||
size_t HashMultipleBlocks(const word32 *input, size_t length);
|
||||
#endif
|
||||
static void CRYPTOPP_API InitState(HashWordType *state);
|
||||
static void CRYPTOPP_API Transform(word32 *digest, const word32 *data);
|
||||
static const char * CRYPTOPP_API StaticAlgorithmName() {return "SHA-256";}
|
||||
};
|
||||
|
||||
//! implements the SHA-224 standard
|
||||
class CRYPTOPP_DLL SHA224 : public IteratedHashWithStaticTransform<word32, BigEndian, 64, 32, SHA224, 28, true>
|
||||
{
|
||||
public:
|
||||
#if defined(CRYPTOPP_X86_ASM_AVAILABLE) || defined(CRYPTOPP_X64_MASM_AVAILABLE)
|
||||
size_t HashMultipleBlocks(const word32 *input, size_t length);
|
||||
#endif
|
||||
static void CRYPTOPP_API InitState(HashWordType *state);
|
||||
static void CRYPTOPP_API Transform(word32 *digest, const word32 *data) {SHA256::Transform(digest, data);}
|
||||
static const char * CRYPTOPP_API StaticAlgorithmName() {return "SHA-224";}
|
||||
};
|
||||
|
||||
//! implements the SHA-512 standard
|
||||
class CRYPTOPP_DLL SHA512 : public IteratedHashWithStaticTransform<word64, BigEndian, 128, 64, SHA512, 64, CRYPTOPP_BOOL_X86>
|
||||
{
|
||||
public:
|
||||
static void CRYPTOPP_API InitState(HashWordType *state);
|
||||
static void CRYPTOPP_API Transform(word64 *digest, const word64 *data);
|
||||
static const char * CRYPTOPP_API StaticAlgorithmName() {return "SHA-512";}
|
||||
};
|
||||
|
||||
//! implements the SHA-384 standard
|
||||
class CRYPTOPP_DLL SHA384 : public IteratedHashWithStaticTransform<word64, BigEndian, 128, 64, SHA384, 48, CRYPTOPP_BOOL_X86>
|
||||
{
|
||||
public:
|
||||
static void CRYPTOPP_API InitState(HashWordType *state);
|
||||
static void CRYPTOPP_API Transform(word64 *digest, const word64 *data) {SHA512::Transform(digest, data);}
|
||||
static const char * CRYPTOPP_API StaticAlgorithmName() {return "SHA-384";}
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
||||
1
src/cryptopp/simple.h
Normal file
1
src/cryptopp/simple.h
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
223
src/cryptopp/smartptr.h
Normal file
223
src/cryptopp/smartptr.h
Normal file
@@ -0,0 +1,223 @@
|
||||
#ifndef CRYPTOPP_SMARTPTR_H
|
||||
#define CRYPTOPP_SMARTPTR_H
|
||||
|
||||
#include "cryptopp/config.h"
|
||||
#include <algorithm>
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
template <class T> class simple_ptr
|
||||
{
|
||||
public:
|
||||
simple_ptr() : m_p(NULL) {}
|
||||
~simple_ptr() {delete m_p;}
|
||||
T *m_p;
|
||||
};
|
||||
|
||||
template <class T> class member_ptr
|
||||
{
|
||||
public:
|
||||
explicit member_ptr(T *p = NULL) : m_p(p) {}
|
||||
|
||||
~member_ptr();
|
||||
|
||||
const T& operator*() const { return *m_p; }
|
||||
T& operator*() { return *m_p; }
|
||||
|
||||
const T* operator->() const { return m_p; }
|
||||
T* operator->() { return m_p; }
|
||||
|
||||
const T* get() const { return m_p; }
|
||||
T* get() { return m_p; }
|
||||
|
||||
T* release()
|
||||
{
|
||||
T *old_p = m_p;
|
||||
m_p = 0;
|
||||
return old_p;
|
||||
}
|
||||
|
||||
void reset(T *p = 0);
|
||||
|
||||
protected:
|
||||
member_ptr(const member_ptr<T>& rhs); // copy not allowed
|
||||
void operator=(const member_ptr<T>& rhs); // assignment not allowed
|
||||
|
||||
T *m_p;
|
||||
};
|
||||
|
||||
template <class T> member_ptr<T>::~member_ptr() {delete m_p;}
|
||||
template <class T> void member_ptr<T>::reset(T *p) {delete m_p; m_p = p;}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
template<class T> class value_ptr : public member_ptr<T>
|
||||
{
|
||||
public:
|
||||
value_ptr(const T &obj) : member_ptr<T>(new T(obj)) {}
|
||||
value_ptr(T *p = NULL) : member_ptr<T>(p) {}
|
||||
value_ptr(const value_ptr<T>& rhs)
|
||||
: member_ptr<T>(rhs.m_p ? new T(*rhs.m_p) : NULL) {}
|
||||
|
||||
value_ptr<T>& operator=(const value_ptr<T>& rhs);
|
||||
bool operator==(const value_ptr<T>& rhs)
|
||||
{
|
||||
return (!this->m_p && !rhs.m_p) || (this->m_p && rhs.m_p && *this->m_p == *rhs.m_p);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> value_ptr<T>& value_ptr<T>::operator=(const value_ptr<T>& rhs)
|
||||
{
|
||||
T *old_p = this->m_p;
|
||||
this->m_p = rhs.m_p ? new T(*rhs.m_p) : NULL;
|
||||
delete old_p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
template<class T> class clonable_ptr : public member_ptr<T>
|
||||
{
|
||||
public:
|
||||
clonable_ptr(const T &obj) : member_ptr<T>(obj.Clone()) {}
|
||||
clonable_ptr(T *p = NULL) : member_ptr<T>(p) {}
|
||||
clonable_ptr(const clonable_ptr<T>& rhs)
|
||||
: member_ptr<T>(rhs.m_p ? rhs.m_p->Clone() : NULL) {}
|
||||
|
||||
clonable_ptr<T>& operator=(const clonable_ptr<T>& rhs);
|
||||
};
|
||||
|
||||
template <class T> clonable_ptr<T>& clonable_ptr<T>::operator=(const clonable_ptr<T>& rhs)
|
||||
{
|
||||
T *old_p = this->m_p;
|
||||
this->m_p = rhs.m_p ? rhs.m_p->Clone() : NULL;
|
||||
delete old_p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
template<class T> class counted_ptr
|
||||
{
|
||||
public:
|
||||
explicit counted_ptr(T *p = 0);
|
||||
counted_ptr(const T &r) : m_p(0) {attach(r);}
|
||||
counted_ptr(const counted_ptr<T>& rhs);
|
||||
|
||||
~counted_ptr();
|
||||
|
||||
const T& operator*() const { return *m_p; }
|
||||
T& operator*() { return *m_p; }
|
||||
|
||||
const T* operator->() const { return m_p; }
|
||||
T* operator->() { return get(); }
|
||||
|
||||
const T* get() const { return m_p; }
|
||||
T* get();
|
||||
|
||||
void attach(const T &p);
|
||||
|
||||
counted_ptr<T> & operator=(const counted_ptr<T>& rhs);
|
||||
|
||||
private:
|
||||
T *m_p;
|
||||
};
|
||||
|
||||
template <class T> counted_ptr<T>::counted_ptr(T *p)
|
||||
: m_p(p)
|
||||
{
|
||||
if (m_p)
|
||||
m_p->m_referenceCount = 1;
|
||||
}
|
||||
|
||||
template <class T> counted_ptr<T>::counted_ptr(const counted_ptr<T>& rhs)
|
||||
: m_p(rhs.m_p)
|
||||
{
|
||||
if (m_p)
|
||||
m_p->m_referenceCount++;
|
||||
}
|
||||
|
||||
template <class T> counted_ptr<T>::~counted_ptr()
|
||||
{
|
||||
if (m_p && --m_p->m_referenceCount == 0)
|
||||
delete m_p;
|
||||
}
|
||||
|
||||
template <class T> void counted_ptr<T>::attach(const T &r)
|
||||
{
|
||||
if (m_p && --m_p->m_referenceCount == 0)
|
||||
delete m_p;
|
||||
if (r.m_referenceCount == 0)
|
||||
{
|
||||
m_p = r.clone();
|
||||
m_p->m_referenceCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_p = const_cast<T *>(&r);
|
||||
m_p->m_referenceCount++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> T* counted_ptr<T>::get()
|
||||
{
|
||||
if (m_p && m_p->m_referenceCount > 1)
|
||||
{
|
||||
T *temp = m_p->clone();
|
||||
m_p->m_referenceCount--;
|
||||
m_p = temp;
|
||||
m_p->m_referenceCount = 1;
|
||||
}
|
||||
return m_p;
|
||||
}
|
||||
|
||||
template <class T> counted_ptr<T> & counted_ptr<T>::operator=(const counted_ptr<T>& rhs)
|
||||
{
|
||||
if (m_p != rhs.m_p)
|
||||
{
|
||||
if (m_p && --m_p->m_referenceCount == 0)
|
||||
delete m_p;
|
||||
m_p = rhs.m_p;
|
||||
if (m_p)
|
||||
m_p->m_referenceCount++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
template <class T> class vector_member_ptrs
|
||||
{
|
||||
public:
|
||||
vector_member_ptrs(size_t size=0)
|
||||
: m_size(size), m_ptr(new member_ptr<T>[size]) {}
|
||||
~vector_member_ptrs()
|
||||
{delete [] this->m_ptr;}
|
||||
|
||||
member_ptr<T>& operator[](size_t index)
|
||||
{assert(index<this->m_size); return this->m_ptr[index];}
|
||||
const member_ptr<T>& operator[](size_t index) const
|
||||
{assert(index<this->m_size); return this->m_ptr[index];}
|
||||
|
||||
size_t size() const {return this->m_size;}
|
||||
void resize(size_t newSize)
|
||||
{
|
||||
member_ptr<T> *newPtr = new member_ptr<T>[newSize];
|
||||
for (size_t i=0; i<this->m_size && i<newSize; i++)
|
||||
newPtr[i].reset(this->m_ptr[i].release());
|
||||
delete [] this->m_ptr;
|
||||
this->m_size = newSize;
|
||||
this->m_ptr = newPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
vector_member_ptrs(const vector_member_ptrs<T> &c); // copy not allowed
|
||||
void operator=(const vector_member_ptrs<T> &x); // assignment not allowed
|
||||
|
||||
size_t m_size;
|
||||
member_ptr<T> *m_ptr;
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
||||
27
src/cryptopp/stdcpp.h
Normal file
27
src/cryptopp/stdcpp.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef CRYPTOPP_STDCPP_H
|
||||
#define CRYPTOPP_STDCPP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <typeinfo>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <string.h> // CodeWarrior doesn't have memory.h
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
// re-disable this
|
||||
#pragma warning(disable: 4231)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && defined(_CRTAPI1)
|
||||
#define CRYPTOPP_MSVCRT6
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1026
src/db.cpp
Normal file
1026
src/db.cpp
Normal file
File diff suppressed because it is too large
Load Diff
526
src/db.h
Normal file
526
src/db.h
Normal file
@@ -0,0 +1,526 @@
|
||||
// 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.
|
||||
#ifndef BITCOIN_DB_H
|
||||
#define BITCOIN_DB_H
|
||||
|
||||
#include "key.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <db_cxx.h>
|
||||
|
||||
class CTransaction;
|
||||
class CTxIndex;
|
||||
class CDiskBlockIndex;
|
||||
class CDiskTxPos;
|
||||
class COutPoint;
|
||||
class CUser;
|
||||
class CReview;
|
||||
class CAddress;
|
||||
class CWalletTx;
|
||||
class CAccount;
|
||||
class CAccountingEntry;
|
||||
class CBlockLocator;
|
||||
|
||||
extern std::map<std::string, std::string> mapAddressBook;
|
||||
extern CCriticalSection cs_mapAddressBook;
|
||||
extern std::vector<unsigned char> vchDefaultKey;
|
||||
extern bool fClient;
|
||||
extern int nBestHeight;
|
||||
|
||||
|
||||
extern unsigned int nWalletDBUpdated;
|
||||
extern DbEnv dbenv;
|
||||
|
||||
|
||||
extern void DBFlush(bool fShutdown);
|
||||
extern std::vector<unsigned char> GetKeyFromKeyPool();
|
||||
extern int64 GetOldestKeyPoolTime();
|
||||
|
||||
|
||||
|
||||
|
||||
class CDB
|
||||
{
|
||||
protected:
|
||||
Db* pdb;
|
||||
std::string strFile;
|
||||
std::vector<DbTxn*> vTxn;
|
||||
bool fReadOnly;
|
||||
|
||||
explicit CDB(const char* pszFile, const char* pszMode="r+");
|
||||
~CDB() { Close(); }
|
||||
public:
|
||||
void Close();
|
||||
private:
|
||||
CDB(const CDB&);
|
||||
void operator=(const CDB&);
|
||||
|
||||
protected:
|
||||
template<typename K, typename T>
|
||||
bool Read(const K& key, T& value)
|
||||
{
|
||||
if (!pdb)
|
||||
return false;
|
||||
|
||||
// Key
|
||||
CDataStream ssKey(SER_DISK);
|
||||
ssKey.reserve(1000);
|
||||
ssKey << key;
|
||||
Dbt datKey(&ssKey[0], ssKey.size());
|
||||
|
||||
// Read
|
||||
Dbt datValue;
|
||||
datValue.set_flags(DB_DBT_MALLOC);
|
||||
int ret = pdb->get(GetTxn(), &datKey, &datValue, 0);
|
||||
memset(datKey.get_data(), 0, datKey.get_size());
|
||||
if (datValue.get_data() == NULL)
|
||||
return false;
|
||||
|
||||
// Unserialize value
|
||||
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
|
||||
ssValue >> value;
|
||||
|
||||
// Clear and free memory
|
||||
memset(datValue.get_data(), 0, datValue.get_size());
|
||||
free(datValue.get_data());
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool Write(const K& key, const T& value, bool fOverwrite=true)
|
||||
{
|
||||
if (!pdb)
|
||||
return false;
|
||||
if (fReadOnly)
|
||||
assert(("Write called on database in read-only mode", 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, DB_TXN_NOSYNC);
|
||||
if (!ptxn || ret != 0)
|
||||
return false;
|
||||
vTxn.push_back(ptxn);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TxnCommit()
|
||||
{
|
||||
if (!pdb)
|
||||
return false;
|
||||
if (vTxn.empty())
|
||||
return false;
|
||||
int ret = vTxn.back()->commit(0);
|
||||
vTxn.pop_back();
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
bool TxnAbort()
|
||||
{
|
||||
if (!pdb)
|
||||
return false;
|
||||
if (vTxn.empty())
|
||||
return false;
|
||||
int ret = vTxn.back()->abort();
|
||||
vTxn.pop_back();
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
bool ReadVersion(int& nVersion)
|
||||
{
|
||||
nVersion = 0;
|
||||
return Read(std::string("version"), nVersion);
|
||||
}
|
||||
|
||||
bool WriteVersion(int nVersion)
|
||||
{
|
||||
return Write(std::string("version"), nVersion);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CTxDB : public CDB
|
||||
{
|
||||
public:
|
||||
CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { }
|
||||
private:
|
||||
CTxDB(const CTxDB&);
|
||||
void operator=(const CTxDB&);
|
||||
public:
|
||||
bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
|
||||
bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
|
||||
bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
|
||||
bool EraseTxIndex(const CTransaction& tx);
|
||||
bool ContainsTx(uint256 hash);
|
||||
bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx);
|
||||
bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
|
||||
bool ReadDiskTx(uint256 hash, CTransaction& tx);
|
||||
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
|
||||
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
|
||||
bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
|
||||
bool EraseBlockIndex(uint256 hash);
|
||||
bool ReadHashBestChain(uint256& hashBestChain);
|
||||
bool WriteHashBestChain(uint256 hashBestChain);
|
||||
bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
|
||||
bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
|
||||
bool LoadBlockIndex();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CAddrDB : public CDB
|
||||
{
|
||||
public:
|
||||
CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
|
||||
private:
|
||||
CAddrDB(const CAddrDB&);
|
||||
void operator=(const CAddrDB&);
|
||||
public:
|
||||
bool WriteAddress(const CAddress& addr);
|
||||
bool EraseAddress(const CAddress& addr);
|
||||
bool LoadAddresses();
|
||||
};
|
||||
|
||||
bool LoadAddresses();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CKeyPool
|
||||
{
|
||||
public:
|
||||
int64 nTime;
|
||||
std::vector<unsigned char> vchPubKey;
|
||||
|
||||
CKeyPool()
|
||||
{
|
||||
nTime = GetTime();
|
||||
}
|
||||
|
||||
CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
|
||||
{
|
||||
nTime = GetTime();
|
||||
vchPubKey = vchPubKeyIn;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
if (!(nType & SER_GETHASH))
|
||||
READWRITE(nVersion);
|
||||
READWRITE(nTime);
|
||||
READWRITE(vchPubKey);
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
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 std::string& strAddress, std::string& strName)
|
||||
{
|
||||
strName = "";
|
||||
return Read(std::make_pair(std::string("name"), strAddress), strName);
|
||||
}
|
||||
|
||||
bool WriteName(const std::string& strAddress, const std::string& strName)
|
||||
{
|
||||
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||
mapAddressBook[strAddress] = strName;
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::make_pair(std::string("name"), strAddress), strName);
|
||||
}
|
||||
|
||||
bool EraseName(const std::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(std::make_pair(std::string("name"), strAddress));
|
||||
}
|
||||
|
||||
bool ReadTx(uint256 hash, CWalletTx& wtx)
|
||||
{
|
||||
return Read(std::make_pair(std::string("tx"), hash), wtx);
|
||||
}
|
||||
|
||||
bool WriteTx(uint256 hash, const CWalletTx& wtx)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::make_pair(std::string("tx"), hash), wtx);
|
||||
}
|
||||
|
||||
bool EraseTx(uint256 hash)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Erase(std::make_pair(std::string("tx"), hash));
|
||||
}
|
||||
|
||||
bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
|
||||
{
|
||||
vchPrivKey.clear();
|
||||
return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey);
|
||||
}
|
||||
|
||||
bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
|
||||
}
|
||||
|
||||
bool WriteBestBlock(const CBlockLocator& locator)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::string("bestblock"), locator);
|
||||
}
|
||||
|
||||
bool ReadBestBlock(CBlockLocator& locator)
|
||||
{
|
||||
return Read(std::string("bestblock"), locator);
|
||||
}
|
||||
|
||||
bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey)
|
||||
{
|
||||
vchPubKey.clear();
|
||||
return Read(std::string("defaultkey"), vchPubKey);
|
||||
}
|
||||
|
||||
bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
|
||||
{
|
||||
vchDefaultKey = vchPubKey;
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::string("defaultkey"), vchPubKey);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool ReadSetting(const std::string& strKey, T& value)
|
||||
{
|
||||
return Read(std::make_pair(std::string("setting"), strKey), value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool WriteSetting(const std::string& strKey, const T& value)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::make_pair(std::string("setting"), strKey), value);
|
||||
}
|
||||
|
||||
bool ReadAccount(const std::string& strAccount, CAccount& account);
|
||||
bool WriteAccount(const std::string& strAccount, const CAccount& account);
|
||||
bool WriteAccountingEntry(const CAccountingEntry& acentry);
|
||||
int64 GetAccountCreditDebit(const std::string& strAccount);
|
||||
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
|
||||
|
||||
bool LoadWallet();
|
||||
protected:
|
||||
void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
|
||||
void KeepKey(int64 nIndex);
|
||||
static void ReturnKey(int64 nIndex);
|
||||
friend class CReserveKey;
|
||||
friend std::vector<unsigned char> GetKeyFromKeyPool();
|
||||
friend int64 GetOldestKeyPoolTime();
|
||||
};
|
||||
|
||||
bool LoadWallet(bool& fFirstRunRet);
|
||||
void BackupWallet(const std::string& strDest);
|
||||
|
||||
inline bool SetAddressBookName(const std::string& strAddress, const std::string& strName)
|
||||
{
|
||||
return CWalletDB().WriteName(strAddress, strName);
|
||||
}
|
||||
|
||||
class CReserveKey
|
||||
{
|
||||
protected:
|
||||
int64 nIndex;
|
||||
std::vector<unsigned char> vchPubKey;
|
||||
public:
|
||||
CReserveKey()
|
||||
{
|
||||
nIndex = -1;
|
||||
}
|
||||
|
||||
~CReserveKey()
|
||||
{
|
||||
if (!fShutdown)
|
||||
ReturnKey();
|
||||
}
|
||||
|
||||
std::vector<unsigned char> GetReservedKey()
|
||||
{
|
||||
if (nIndex == -1)
|
||||
{
|
||||
CKeyPool keypool;
|
||||
CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool);
|
||||
vchPubKey = keypool.vchPubKey;
|
||||
}
|
||||
assert(!vchPubKey.empty());
|
||||
return vchPubKey;
|
||||
}
|
||||
|
||||
void KeepKey()
|
||||
{
|
||||
if (nIndex != -1)
|
||||
CWalletDB().KeepKey(nIndex);
|
||||
nIndex = -1;
|
||||
vchPubKey.clear();
|
||||
}
|
||||
|
||||
void ReturnKey()
|
||||
{
|
||||
if (nIndex != -1)
|
||||
CWalletDB::ReturnKey(nIndex);
|
||||
nIndex = -1;
|
||||
vchPubKey.clear();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
45
src/externui.h
Normal file
45
src/externui.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2010 Satoshi Nakamoto
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef BITCOIN_EXTERNUI_H
|
||||
#define BITCOIN_EXTERNUI_H
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef void wxWindow;
|
||||
#define wxYES 0x00000002
|
||||
#define wxOK 0x00000004
|
||||
#define wxNO 0x00000008
|
||||
#define wxYES_NO (wxYES|wxNO)
|
||||
#define wxCANCEL 0x00000010
|
||||
#define wxAPPLY 0x00000020
|
||||
#define wxCLOSE 0x00000040
|
||||
#define wxOK_DEFAULT 0x00000000
|
||||
#define wxYES_DEFAULT 0x00000000
|
||||
#define wxNO_DEFAULT 0x00000080
|
||||
#define wxCANCEL_DEFAULT 0x80000000
|
||||
#define wxICON_EXCLAMATION 0x00000100
|
||||
#define wxICON_HAND 0x00000200
|
||||
#define wxICON_WARNING wxICON_EXCLAMATION
|
||||
#define wxICON_ERROR wxICON_HAND
|
||||
#define wxICON_QUESTION 0x00000400
|
||||
#define wxICON_INFORMATION 0x00000800
|
||||
#define wxICON_STOP wxICON_HAND
|
||||
#define wxICON_ASTERISK wxICON_INFORMATION
|
||||
#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800)
|
||||
#define wxFORWARD 0x00001000
|
||||
#define wxBACKWARD 0x00002000
|
||||
#define wxRESET 0x00004000
|
||||
#define wxHELP 0x00008000
|
||||
#define wxMORE 0x00010000
|
||||
#define wxSETUP 0x00020000
|
||||
|
||||
extern int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
|
||||
#define wxMessageBox MyMessageBox
|
||||
extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
|
||||
extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent);
|
||||
extern void CalledSetStatusBar(const std::string& strText, int nField);
|
||||
extern void UIThreadCall(boost::function0<void> fn);
|
||||
extern void MainFrameRepaint();
|
||||
|
||||
#endif
|
||||
147
src/headers.h
Normal file
147
src/headers.h
Normal file
@@ -0,0 +1,147 @@
|
||||
// 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 0x0500
|
||||
#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
|
||||
#if (defined(__unix__) || defined(unix)) && !defined(USG)
|
||||
#include <sys/param.h> // to get BSD define
|
||||
#endif
|
||||
#ifdef __WXMAC_OSX__
|
||||
#ifndef BSD
|
||||
#define BSD 1
|
||||
#endif
|
||||
#endif
|
||||
#ifdef GUI
|
||||
#include <wx/wx.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/snglinst.h>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/taskbar.h>
|
||||
#endif
|
||||
#include <openssl/buffer.h>
|
||||
#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 <time.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/filesystem/fstream.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/interprocess/sync/file_lock.hpp>
|
||||
#include <boost/interprocess/sync/interprocess_mutex.hpp>
|
||||
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian_types.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/program_options/detail/config_file.hpp>
|
||||
#include <boost/program_options/parsers.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 <sys/stat.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#ifdef BSD
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
|
||||
#pragma hdrstop
|
||||
|
||||
#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"
|
||||
#ifdef GUI
|
||||
#include "uibase.h"
|
||||
#include "ui.h"
|
||||
#else
|
||||
#include "externui.h"
|
||||
#endif
|
||||
#include "init.h"
|
||||
|
||||
#ifdef GUI
|
||||
#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/bitcoin80.xpm"
|
||||
#include "xpm/check.xpm"
|
||||
#include "xpm/send16.xpm"
|
||||
#include "xpm/send16noshadow.xpm"
|
||||
#include "xpm/send20.xpm"
|
||||
#include "xpm/about.xpm"
|
||||
#endif
|
||||
525
src/init.cpp
Normal file
525
src/init.cpp
Normal file
@@ -0,0 +1,525 @@
|
||||
// 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"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Shutdown
|
||||
//
|
||||
|
||||
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);
|
||||
boost::filesystem::remove(GetPidFile());
|
||||
CreateThread(ExitTimeout, NULL);
|
||||
Sleep(50);
|
||||
printf("Bitcoin exiting\n\n");
|
||||
fExit = true;
|
||||
exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!fExit)
|
||||
Sleep(500);
|
||||
Sleep(100);
|
||||
ExitThread(0);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleSIGTERM(int)
|
||||
{
|
||||
fRequestShutdown = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Start
|
||||
//
|
||||
#if 0
|
||||
#ifndef GUI
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
bool fRet = false;
|
||||
fRet = AppInit(argc, argv);
|
||||
|
||||
if (fRet && fDaemon)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool AppInit(int argc, char* argv[])
|
||||
{
|
||||
bool fRet = false;
|
||||
try
|
||||
{
|
||||
fRet = AppInit2(argc, argv);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
PrintException(&e, "AppInit()");
|
||||
} catch (...) {
|
||||
PrintException(NULL, "AppInit()");
|
||||
}
|
||||
if (!fRet)
|
||||
Shutdown(NULL);
|
||||
return fRet;
|
||||
}
|
||||
|
||||
bool AppInit2(int argc, char* argv[])
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
// Turn off microsoft heap dump noise
|
||||
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
|
||||
_CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
|
||||
#endif
|
||||
#if _MSC_VER >= 1400
|
||||
// Disable confusing "helpful" text message on abort, ctrl-c
|
||||
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
||||
#endif
|
||||
#ifndef __WXMSW__
|
||||
umask(077);
|
||||
#endif
|
||||
#ifndef __WXMSW__
|
||||
// Clean shutdown on SIGTERM
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = HandleSIGTERM;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Parameters
|
||||
//
|
||||
ParseParameters(argc, argv);
|
||||
|
||||
if (mapArgs.count("-datadir"))
|
||||
{
|
||||
filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
|
||||
strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
|
||||
}
|
||||
|
||||
ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
|
||||
|
||||
if (mapArgs.count("-?") || mapArgs.count("--help"))
|
||||
{
|
||||
string beta = VERSION_IS_BETA ? _(" beta") : "";
|
||||
string strUsage = string() +
|
||||
_("Bitcoin version") + " " + FormatFullVersion() + "\n\n" +
|
||||
_("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
|
||||
" bitcoin [options] \t " + "\n" +
|
||||
" bitcoin [options] <command> [params]\t " + _("Send command to -server or bitcoind\n") +
|
||||
" bitcoin [options] help \t\t " + _("List commands\n") +
|
||||
" bitcoin [options] help <command> \t\t " + _("Get help for a command\n") +
|
||||
_("Options:\n") +
|
||||
" -conf=<file> \t\t " + _("Specify configuration file (default: bitcoin.conf)\n") +
|
||||
" -pid=<file> \t\t " + _("Specify pid file (default: bitcoind.pid)\n") +
|
||||
" -gen \t\t " + _("Generate coins\n") +
|
||||
" -gen=0 \t\t " + _("Don't generate coins\n") +
|
||||
" -min \t\t " + _("Start minimized\n") +
|
||||
" -datadir=<dir> \t\t " + _("Specify data directory\n") +
|
||||
" -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") +
|
||||
" -dns \t " + _("Allow DNS lookups for addnode and connect\n") +
|
||||
" -addnode=<ip> \t " + _("Add a node to connect to\n") +
|
||||
" -connect=<ip> \t\t " + _("Connect only to the specified node\n") +
|
||||
" -nolisten \t " + _("Don't accept connections from outside\n") +
|
||||
#ifdef USE_UPNP
|
||||
#if USE_UPNP
|
||||
" -noupnp \t " + _("Don't attempt to use UPnP to map the listening port\n") +
|
||||
#else
|
||||
" -upnp \t " + _("Attempt to use UPnP to map the listening port\n") +
|
||||
#endif
|
||||
#endif
|
||||
" -paytxfee=<amt> \t " + _("Fee per KB to add to transactions you send\n") +
|
||||
#ifdef GUI
|
||||
" -server \t\t " + _("Accept command line and JSON-RPC commands\n") +
|
||||
#endif
|
||||
#ifndef __WXMSW__
|
||||
" -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") +
|
||||
#endif
|
||||
" -testnet \t\t " + _("Use the test network\n") +
|
||||
" -rpcuser=<user> \t " + _("Username for JSON-RPC connections\n") +
|
||||
" -rpcpassword=<pw>\t " + _("Password for JSON-RPC connections\n") +
|
||||
" -rpcport=<port> \t\t " + _("Listen for JSON-RPC connections on <port> (default: 8332)\n") +
|
||||
" -rpcallowip=<ip> \t\t " + _("Allow JSON-RPC connections from specified IP address\n") +
|
||||
" -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)\n") +
|
||||
" -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)\n") +
|
||||
" -rescan \t " + _("Rescan the block chain for missing wallet transactions\n");
|
||||
|
||||
#ifdef USE_SSL
|
||||
strUsage += string() +
|
||||
_("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)\n") +
|
||||
" -rpcssl \t " + _("Use OpenSSL (https) for JSON-RPC connections\n") +
|
||||
" -rpcsslcertificatechainfile=<file.cert>\t " + _("Server certificate file (default: server.cert)\n") +
|
||||
" -rpcsslprivatekeyfile=<file.pem> \t " + _("Server private key (default: server.pem)\n") +
|
||||
" -rpcsslciphers=<ciphers> \t " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)\n");
|
||||
#endif
|
||||
|
||||
strUsage += string() +
|
||||
" -? \t\t " + _("This help message\n");
|
||||
|
||||
#if defined(__WXMSW__) && defined(GUI)
|
||||
// Tabs make the columns line up in the message box
|
||||
wxMessageBox(strUsage, "Bitcoin", wxOK);
|
||||
#else
|
||||
// Remove tabs
|
||||
strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
|
||||
fprintf(stderr, "%s", strUsage.c_str());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
fDebug = GetBoolArg("-debug");
|
||||
fAllowDNS = GetBoolArg("-dns");
|
||||
|
||||
#ifndef __WXMSW__
|
||||
fDaemon = GetBoolArg("-daemon");
|
||||
#else
|
||||
fDaemon = false;
|
||||
#endif
|
||||
|
||||
if (fDaemon)
|
||||
fServer = true;
|
||||
else
|
||||
fServer = GetBoolArg("-server");
|
||||
|
||||
/* force fServer when running without GUI */
|
||||
#if 0
|
||||
#ifndef GUI
|
||||
fServer = true;
|
||||
#endif
|
||||
#endif
|
||||
fPrintToConsole = GetBoolArg("-printtoconsole");
|
||||
fPrintToDebugger = GetBoolArg("-printtodebugger");
|
||||
|
||||
fTestNet = GetBoolArg("-testnet");
|
||||
fNoListen = GetBoolArg("-nolisten");
|
||||
fLogTimestamps = GetBoolArg("-logtimestamps");
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
if (!IsSwitchChar(argv[i][0]))
|
||||
fCommandLine = true;
|
||||
|
||||
if (fCommandLine)
|
||||
{
|
||||
int ret = CommandLineRPC(argc, argv);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
#ifndef __WXMSW__
|
||||
if (fDaemon)
|
||||
{
|
||||
// Daemonize
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
|
||||
return false;
|
||||
}
|
||||
if (pid > 0)
|
||||
{
|
||||
CreatePidFile(GetPidFile(), pid);
|
||||
return true;
|
||||
}
|
||||
|
||||
pid_t sid = setsid();
|
||||
if (sid < 0)
|
||||
fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!fDebug && !pszSetDataDir[0])
|
||||
ShrinkDebugFile();
|
||||
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||
printf("Bitcoin version %s\n", FormatFullVersion().c_str());
|
||||
#ifdef GUI
|
||||
printf("OS version %s\n", ((string)wxGetOsDescription()).c_str());
|
||||
printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str());
|
||||
printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str());
|
||||
#endif
|
||||
printf("Default data directory %s\n", GetDefaultDataDir().c_str());
|
||||
|
||||
if (GetBoolArg("-loadblockindextest"))
|
||||
{
|
||||
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.*
|
||||
//
|
||||
#if defined(__WXMSW__) && defined(GUI)
|
||||
// wxSingleInstanceChecker doesn't work on Linux
|
||||
wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
|
||||
for (int i = 0; i < strMutexName.size(); i++)
|
||||
if (!isalnum(strMutexName[i]))
|
||||
strMutexName[i] = '.';
|
||||
wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
|
||||
if (psingleinstancechecker->IsAnotherRunning())
|
||||
{
|
||||
printf("Existing instance found\n");
|
||||
unsigned int nStart = GetTime();
|
||||
loop
|
||||
{
|
||||
// Show the previous instance and exit
|
||||
HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
|
||||
if (hwndPrev)
|
||||
{
|
||||
if (IsIconic(hwndPrev))
|
||||
ShowWindow(hwndPrev, SW_RESTORE);
|
||||
SetForegroundWindow(hwndPrev);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetTime() > nStart + 60)
|
||||
return false;
|
||||
|
||||
// Resume this instance if the other exits
|
||||
delete psingleinstancechecker;
|
||||
Sleep(1000);
|
||||
psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
|
||||
if (!psingleinstancechecker->IsAnotherRunning())
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Make sure only a single bitcoin process is using the data directory.
|
||||
string strLockFile = GetDataDir() + "/.lock";
|
||||
FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
|
||||
if (file) fclose(file);
|
||||
static boost::interprocess::file_lock lock(strLockFile.c_str());
|
||||
if (!lock.try_lock())
|
||||
{
|
||||
wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bind to the port early so we can tell if another instance is already running.
|
||||
string strErrors;
|
||||
if (!fNoListen)
|
||||
{
|
||||
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);
|
||||
|
||||
CBlockIndex *pindexRescan = pindexBest;
|
||||
if (GetBoolArg("-rescan"))
|
||||
pindexRescan = pindexGenesisBlock;
|
||||
else
|
||||
{
|
||||
CWalletDB walletdb;
|
||||
CBlockLocator locator;
|
||||
if (walletdb.ReadBestBlock(locator))
|
||||
pindexRescan = locator.GetBlockIndex();
|
||||
}
|
||||
if (pindexBest != pindexRescan)
|
||||
{
|
||||
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
|
||||
nStart = GetTimeMillis();
|
||||
ScanForWalletTransactions(pindexRescan, true);
|
||||
printf(" rescan %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", wxOK | wxICON_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add wallet transactions that aren't already in a block to mapTransactions
|
||||
ReacceptWalletTransactions();
|
||||
|
||||
//
|
||||
// Parameters
|
||||
//
|
||||
if (GetBoolArg("-printblockindex") || GetBoolArg("-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;
|
||||
}
|
||||
|
||||
fGenerateBitcoins = GetBoolArg("-gen");
|
||||
|
||||
if (mapArgs.count("-proxy"))
|
||||
{
|
||||
fUseProxy = true;
|
||||
addrProxy = CAddress(mapArgs["-proxy"]);
|
||||
if (!addrProxy.IsValid())
|
||||
{
|
||||
wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapArgs.count("-addnode"))
|
||||
{
|
||||
BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
|
||||
{
|
||||
CAddress addr(strAddr, fAllowDNS);
|
||||
addr.nTime = 0; // so it won't relay unless successfully connected
|
||||
if (addr.IsValid())
|
||||
AddAddress(addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (mapArgs.count("-dnsseed"))
|
||||
DNSAddressSeed();
|
||||
|
||||
if (mapArgs.count("-paytxfee"))
|
||||
{
|
||||
if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
|
||||
{
|
||||
wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
|
||||
return false;
|
||||
}
|
||||
if (nTransactionFee > 0.25 * COIN)
|
||||
wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
|
||||
}
|
||||
|
||||
if (fHaveUPnP)
|
||||
{
|
||||
#if USE_UPNP
|
||||
if (GetBoolArg("-noupnp"))
|
||||
fUseUPnP = false;
|
||||
#else
|
||||
if (GetBoolArg("-upnp"))
|
||||
fUseUPnP = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Create the main window and start the node
|
||||
//
|
||||
#ifdef GUI
|
||||
if (!fDaemon)
|
||||
CreateMainWindow();
|
||||
#endif
|
||||
|
||||
if (!CheckDiskSpace())
|
||||
return false;
|
||||
|
||||
RandAddSeedPerfmon();
|
||||
|
||||
if (!CreateThread(StartNode, NULL))
|
||||
wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
|
||||
|
||||
if (fServer)
|
||||
CreateThread(ThreadRPCServer, NULL);
|
||||
|
||||
#if defined(__WXMSW__) && defined(GUI)
|
||||
if (fFirstRun)
|
||||
SetStartOnSystemStartup(true);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifndef GUI
|
||||
while (1)
|
||||
Sleep(5000);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
11
src/init.h
Normal file
11
src/init.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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.
|
||||
#ifndef BITCOIN_INIT_H
|
||||
#define BITCOIN_INIT_H
|
||||
|
||||
void Shutdown(void* parg);
|
||||
bool AppInit(int argc, char* argv[]);
|
||||
bool AppInit2(int argc, char* argv[]);
|
||||
|
||||
#endif
|
||||
445
src/irc.cpp
Normal file
445
src/irc.cpp
Normal file
@@ -0,0 +1,445 @@
|
||||
// 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"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
int nGotIRCAddresses = 0;
|
||||
bool fGotExternalIP = false;
|
||||
|
||||
void ThreadIRCSeed2(void* parg);
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ircaddr
|
||||
{
|
||||
int ip;
|
||||
short port;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
string EncodeAddress(const CAddress& addr)
|
||||
{
|
||||
struct ircaddr tmp;
|
||||
tmp.ip = addr.ip;
|
||||
tmp.port = addr.port;
|
||||
|
||||
vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
|
||||
return string("u") + EncodeBase58Check(vch);
|
||||
}
|
||||
|
||||
bool DecodeAddress(string str, CAddress& addr)
|
||||
{
|
||||
vector<unsigned char> vch;
|
||||
if (!DecodeBase58Check(str.substr(1), vch))
|
||||
return false;
|
||||
|
||||
struct ircaddr tmp;
|
||||
if (vch.size() != sizeof(tmp))
|
||||
return false;
|
||||
memcpy(&tmp, &vch[0], sizeof(tmp));
|
||||
|
||||
addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static bool Send(SOCKET hSocket, const char* pszSend)
|
||||
{
|
||||
if (strstr(pszSend, "PONG") != pszSend)
|
||||
printf("IRC SENDING: %s\n", pszSend);
|
||||
const char* psz = pszSend;
|
||||
const char* pszEnd = psz + strlen(psz);
|
||||
while (psz < pszEnd)
|
||||
{
|
||||
int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
psz += ret;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecvLine(SOCKET hSocket, string& strLine)
|
||||
{
|
||||
strLine = "";
|
||||
loop
|
||||
{
|
||||
char c;
|
||||
int nBytes = recv(hSocket, &c, 1, 0);
|
||||
if (nBytes > 0)
|
||||
{
|
||||
if (c == '\n')
|
||||
continue;
|
||||
if (c == '\r')
|
||||
return true;
|
||||
strLine += c;
|
||||
if (strLine.size() >= 9000)
|
||||
return true;
|
||||
}
|
||||
else if (nBytes <= 0)
|
||||
{
|
||||
if (fShutdown)
|
||||
return false;
|
||||
if (nBytes < 0)
|
||||
{
|
||||
int nErr = WSAGetLastError();
|
||||
if (nErr == WSAEMSGSIZE)
|
||||
continue;
|
||||
if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
|
||||
{
|
||||
Sleep(10);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!strLine.empty())
|
||||
return true;
|
||||
if (nBytes == 0)
|
||||
{
|
||||
// socket closed
|
||||
printf("IRC socket closed\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// socket error
|
||||
int nErr = WSAGetLastError();
|
||||
printf("IRC recv failed: %d\n", nErr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RecvLineIRC(SOCKET hSocket, string& strLine)
|
||||
{
|
||||
loop
|
||||
{
|
||||
bool fRet = RecvLine(hSocket, strLine);
|
||||
if (fRet)
|
||||
{
|
||||
if (fShutdown)
|
||||
return false;
|
||||
vector<string> vWords;
|
||||
ParseString(strLine, ' ', vWords);
|
||||
if (vWords.size() >= 1 && vWords[0] == "PING")
|
||||
{
|
||||
strLine[1] = 'O';
|
||||
strLine += '\r';
|
||||
Send(hSocket, strLine.c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return fRet;
|
||||
}
|
||||
}
|
||||
|
||||
int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
|
||||
{
|
||||
loop
|
||||
{
|
||||
string strLine;
|
||||
strLine.reserve(10000);
|
||||
if (!RecvLineIRC(hSocket, strLine))
|
||||
return 0;
|
||||
printf("IRC %s\n", strLine.c_str());
|
||||
if (psz1 && strLine.find(psz1) != -1)
|
||||
return 1;
|
||||
if (psz2 && strLine.find(psz2) != -1)
|
||||
return 2;
|
||||
if (psz3 && strLine.find(psz3) != -1)
|
||||
return 3;
|
||||
if (psz4 && strLine.find(psz4) != -1)
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
bool Wait(int nSeconds)
|
||||
{
|
||||
if (fShutdown)
|
||||
return false;
|
||||
printf("IRC waiting %d seconds to reconnect\n", nSeconds);
|
||||
for (int i = 0; i < nSeconds; i++)
|
||||
{
|
||||
if (fShutdown)
|
||||
return false;
|
||||
Sleep(1000);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
|
||||
{
|
||||
strRet.clear();
|
||||
loop
|
||||
{
|
||||
string strLine;
|
||||
if (!RecvLineIRC(hSocket, strLine))
|
||||
return false;
|
||||
|
||||
vector<string> vWords;
|
||||
ParseString(strLine, ' ', vWords);
|
||||
if (vWords.size() < 2)
|
||||
continue;
|
||||
|
||||
if (vWords[1] == psz1)
|
||||
{
|
||||
printf("IRC %s\n", strLine.c_str());
|
||||
strRet = strLine;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
|
||||
{
|
||||
Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
|
||||
|
||||
string strLine;
|
||||
if (!RecvCodeLine(hSocket, "302", strLine))
|
||||
return false;
|
||||
|
||||
vector<string> vWords;
|
||||
ParseString(strLine, ' ', vWords);
|
||||
if (vWords.size() < 4)
|
||||
return false;
|
||||
|
||||
string str = vWords[3];
|
||||
if (str.rfind("@") == string::npos)
|
||||
return false;
|
||||
string strHost = str.substr(str.rfind("@")+1);
|
||||
|
||||
// Hybrid IRC used by lfnet always returns IP when you userhost yourself,
|
||||
// but in case another IRC is ever used this should work.
|
||||
printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
|
||||
if (fUseProxy)
|
||||
return false;
|
||||
CAddress addr(strHost, 0, true);
|
||||
if (!addr.IsValid())
|
||||
return false;
|
||||
ipRet = addr.ip;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ThreadIRCSeed(void* parg)
|
||||
{
|
||||
IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
|
||||
try
|
||||
{
|
||||
ThreadIRCSeed2(parg);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
PrintExceptionContinue(&e, "ThreadIRCSeed()");
|
||||
} catch (...) {
|
||||
PrintExceptionContinue(NULL, "ThreadIRCSeed()");
|
||||
}
|
||||
printf("ThreadIRCSeed exiting\n");
|
||||
}
|
||||
|
||||
void ThreadIRCSeed2(void* parg)
|
||||
{
|
||||
/* Dont advertise on IRC if we don't allow incoming connections */
|
||||
if (mapArgs.count("-connect") || fNoListen)
|
||||
return;
|
||||
|
||||
if (GetBoolArg("-noirc"))
|
||||
return;
|
||||
printf("ThreadIRCSeed started\n");
|
||||
int nErrorWait = 10;
|
||||
int nRetryWait = 10;
|
||||
bool fNameInUse = false;
|
||||
bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
|
||||
|
||||
while (!fShutdown)
|
||||
{
|
||||
//CAddress addrConnect("216.155.130.130:6667"); // chat.freenode.net
|
||||
CAddress addrConnect("92.243.23.21", 6667); // irc.lfnet.org
|
||||
if (!fTOR)
|
||||
{
|
||||
//struct hostent* phostent = gethostbyname("chat.freenode.net");
|
||||
CAddress addrIRC("irc.lfnet.org", 6667, true);
|
||||
if (addrIRC.IsValid())
|
||||
addrConnect = addrIRC;
|
||||
}
|
||||
|
||||
SOCKET hSocket;
|
||||
if (!ConnectSocket(addrConnect, hSocket))
|
||||
{
|
||||
printf("IRC connect failed\n");
|
||||
nErrorWait = nErrorWait * 11 / 10;
|
||||
if (Wait(nErrorWait += 60))
|
||||
continue;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
|
||||
{
|
||||
closesocket(hSocket);
|
||||
hSocket = INVALID_SOCKET;
|
||||
nErrorWait = nErrorWait * 11 / 10;
|
||||
if (Wait(nErrorWait += 60))
|
||||
continue;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
string strMyName;
|
||||
if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
|
||||
strMyName = EncodeAddress(addrLocalHost);
|
||||
else
|
||||
strMyName = strprintf("x%u", GetRand(1000000000));
|
||||
|
||||
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
|
||||
Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
|
||||
|
||||
int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
|
||||
if (nRet != 1)
|
||||
{
|
||||
closesocket(hSocket);
|
||||
hSocket = INVALID_SOCKET;
|
||||
if (nRet == 2)
|
||||
{
|
||||
printf("IRC name already in use\n");
|
||||
fNameInUse = true;
|
||||
Wait(10);
|
||||
continue;
|
||||
}
|
||||
nErrorWait = nErrorWait * 11 / 10;
|
||||
if (Wait(nErrorWait += 60))
|
||||
continue;
|
||||
else
|
||||
return;
|
||||
}
|
||||
Sleep(500);
|
||||
|
||||
// Get our external IP from the IRC server and re-nick before joining the channel
|
||||
CAddress addrFromIRC;
|
||||
if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
|
||||
{
|
||||
printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
|
||||
if (!fUseProxy && addrFromIRC.IsRoutable())
|
||||
{
|
||||
// IRC lets you to re-nick
|
||||
fGotExternalIP = true;
|
||||
addrLocalHost.ip = addrFromIRC.ip;
|
||||
strMyName = EncodeAddress(addrLocalHost);
|
||||
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (fTestNet) {
|
||||
Send(hSocket, "JOIN #bitcoinTEST\r");
|
||||
Send(hSocket, "WHO #bitcoinTEST\r");
|
||||
} else {
|
||||
// randomly join #bitcoin00-#bitcoin99
|
||||
int channel_number = GetRandInt(100);
|
||||
Send(hSocket, strprintf("JOIN #bitcoin%02d\r", channel_number).c_str());
|
||||
Send(hSocket, strprintf("WHO #bitcoin%02d\r", channel_number).c_str());
|
||||
}
|
||||
|
||||
int64 nStart = GetTime();
|
||||
string strLine;
|
||||
strLine.reserve(10000);
|
||||
while (!fShutdown && RecvLineIRC(hSocket, strLine))
|
||||
{
|
||||
if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
|
||||
continue;
|
||||
|
||||
vector<string> vWords;
|
||||
ParseString(strLine, ' ', vWords);
|
||||
if (vWords.size() < 2)
|
||||
continue;
|
||||
|
||||
char pszName[10000];
|
||||
pszName[0] = '\0';
|
||||
|
||||
if (vWords[1] == "352" && vWords.size() >= 8)
|
||||
{
|
||||
// index 7 is limited to 16 characters
|
||||
// could get full length name at index 10, but would be different from join messages
|
||||
strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
|
||||
printf("IRC got who\n");
|
||||
}
|
||||
|
||||
if (vWords[1] == "JOIN" && vWords[0].size() > 1)
|
||||
{
|
||||
// :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
|
||||
strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
|
||||
if (strchr(pszName, '!'))
|
||||
*strchr(pszName, '!') = '\0';
|
||||
printf("IRC got join\n");
|
||||
}
|
||||
|
||||
if (pszName[0] == 'u')
|
||||
{
|
||||
CAddress addr;
|
||||
if (DecodeAddress(pszName, addr))
|
||||
{
|
||||
addr.nTime = GetAdjustedTime();
|
||||
if (AddAddress(addr, 51 * 60))
|
||||
printf("IRC got new address: %s\n", addr.ToString().c_str());
|
||||
nGotIRCAddresses++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("IRC decode failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
closesocket(hSocket);
|
||||
hSocket = INVALID_SOCKET;
|
||||
|
||||
// IRC usually blocks TOR, so only try once
|
||||
if (fTOR)
|
||||
return;
|
||||
|
||||
if (GetTime() - nStart > 20 * 60)
|
||||
{
|
||||
nErrorWait /= 3;
|
||||
nRetryWait /= 3;
|
||||
}
|
||||
|
||||
nRetryWait = nRetryWait * 11 / 10;
|
||||
if (!Wait(nRetryWait += 60))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
WSADATA wsadata;
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
|
||||
{
|
||||
printf("Error at WSAStartup()\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ThreadIRCSeed(NULL);
|
||||
|
||||
WSACleanup();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
13
src/irc.h
Normal file
13
src/irc.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// 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.
|
||||
#ifndef BITCOIN_IRC_H
|
||||
#define BITCOIN_IRC_H
|
||||
|
||||
bool RecvLine(SOCKET hSocket, std::string& strLine);
|
||||
void ThreadIRCSeed(void* parg);
|
||||
|
||||
extern int nGotIRCAddresses;
|
||||
extern bool fGotExternalIP;
|
||||
|
||||
#endif
|
||||
18
src/json/json_spirit.h
Normal file
18
src/json/json_spirit.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#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
|
||||
54
src/json/json_spirit_error_position.h
Normal file
54
src/json/json_spirit_error_position.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#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
|
||||
137
src/json/json_spirit_reader.cpp
Normal file
137
src/json/json_spirit_reader.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#include "json/json_spirit_reader.h"
|
||||
#include "json/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
|
||||
62
src/json/json_spirit_reader.h
Normal file
62
src/json/json_spirit_reader.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#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
|
||||
612
src/json/json_spirit_reader_template.h
Normal file
612
src/json/json_spirit_reader_template.h
Normal file
@@ -0,0 +1,612 @@
|
||||
#ifndef JSON_SPIRIT_READER_TEMPLATE
|
||||
#define JSON_SPIRIT_READER_TEMPLATE
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
#include "json_spirit_error_position.h"
|
||||
|
||||
//#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 103800
|
||||
#include <boost/spirit/include/classic_core.hpp>
|
||||
#include <boost/spirit/include/classic_confix.hpp>
|
||||
#include <boost/spirit/include/classic_escape_char.hpp>
|
||||
#include <boost/spirit/include/classic_multi_pass.hpp>
|
||||
#include <boost/spirit/include/classic_position_iterator.hpp>
|
||||
#define spirit_namespace boost::spirit::classic
|
||||
#else
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/utility/confix.hpp>
|
||||
#include <boost/spirit/utility/escape_char.hpp>
|
||||
#include <boost/spirit/iterator/multi_pass.hpp>
|
||||
#include <boost/spirit/iterator/position_iterator.hpp>
|
||||
#define spirit_namespace boost::spirit
|
||||
#endif
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >();
|
||||
const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >();
|
||||
|
||||
template< class Iter_type >
|
||||
bool is_eq( Iter_type first, Iter_type last, const char* c_str )
|
||||
{
|
||||
for( Iter_type i = first; i != last; ++i, ++c_str )
|
||||
{
|
||||
if( *c_str == 0 ) return false;
|
||||
|
||||
if( *i != *c_str ) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Char_type >
|
||||
Char_type hex_to_num( const Char_type c )
|
||||
{
|
||||
if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0';
|
||||
if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10;
|
||||
if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template< class Char_type, class Iter_type >
|
||||
Char_type hex_str_to_char( Iter_type& begin )
|
||||
{
|
||||
const Char_type c1( *( ++begin ) );
|
||||
const Char_type c2( *( ++begin ) );
|
||||
|
||||
return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 );
|
||||
}
|
||||
|
||||
template< class Char_type, class Iter_type >
|
||||
Char_type unicode_str_to_char( Iter_type& begin )
|
||||
{
|
||||
const Char_type c1( *( ++begin ) );
|
||||
const Char_type c2( *( ++begin ) );
|
||||
const Char_type c3( *( ++begin ) );
|
||||
const Char_type c4( *( ++begin ) );
|
||||
|
||||
return ( hex_to_num( c1 ) << 12 ) +
|
||||
( hex_to_num( c2 ) << 8 ) +
|
||||
( hex_to_num( c3 ) << 4 ) +
|
||||
hex_to_num( c4 );
|
||||
}
|
||||
|
||||
template< class String_type >
|
||||
void append_esc_char_and_incr_iter( String_type& s,
|
||||
typename String_type::const_iterator& begin,
|
||||
typename String_type::const_iterator end )
|
||||
{
|
||||
typedef typename String_type::value_type Char_type;
|
||||
|
||||
const Char_type c2( *begin );
|
||||
|
||||
switch( c2 )
|
||||
{
|
||||
case 't': s += '\t'; break;
|
||||
case 'b': s += '\b'; break;
|
||||
case 'f': s += '\f'; break;
|
||||
case 'n': s += '\n'; break;
|
||||
case 'r': s += '\r'; break;
|
||||
case '\\': s += '\\'; break;
|
||||
case '/': s += '/'; break;
|
||||
case '"': s += '"'; break;
|
||||
case 'x':
|
||||
{
|
||||
if( end - begin >= 3 ) // expecting "xHH..."
|
||||
{
|
||||
s += hex_str_to_char< Char_type >( begin );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
{
|
||||
if( end - begin >= 5 ) // expecting "uHHHH..."
|
||||
{
|
||||
s += unicode_str_to_char< Char_type >( begin );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< class String_type >
|
||||
String_type substitute_esc_chars( typename String_type::const_iterator begin,
|
||||
typename String_type::const_iterator end )
|
||||
{
|
||||
typedef typename String_type::const_iterator Iter_type;
|
||||
|
||||
if( end - begin < 2 ) return String_type( begin, end );
|
||||
|
||||
String_type result;
|
||||
|
||||
result.reserve( end - begin );
|
||||
|
||||
const Iter_type end_minus_1( end - 1 );
|
||||
|
||||
Iter_type substr_start = begin;
|
||||
Iter_type i = begin;
|
||||
|
||||
for( ; i < end_minus_1; ++i )
|
||||
{
|
||||
if( *i == '\\' )
|
||||
{
|
||||
result.append( substr_start, i );
|
||||
|
||||
++i; // skip the '\'
|
||||
|
||||
append_esc_char_and_incr_iter( result, i, end );
|
||||
|
||||
substr_start = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.append( substr_start, end );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template< class String_type >
|
||||
String_type get_str_( typename String_type::const_iterator begin,
|
||||
typename String_type::const_iterator end )
|
||||
{
|
||||
assert( end - begin >= 2 );
|
||||
|
||||
typedef typename String_type::const_iterator Iter_type;
|
||||
|
||||
Iter_type str_without_quotes( ++begin );
|
||||
Iter_type end_without_quotes( --end );
|
||||
|
||||
return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes );
|
||||
}
|
||||
|
||||
inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end )
|
||||
{
|
||||
return get_str_< std::string >( begin, end );
|
||||
}
|
||||
|
||||
inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end )
|
||||
{
|
||||
return get_str_< std::wstring >( begin, end );
|
||||
}
|
||||
|
||||
template< class String_type, class Iter_type >
|
||||
String_type get_str( Iter_type begin, Iter_type end )
|
||||
{
|
||||
const String_type tmp( begin, end ); // convert multipass iterators to string iterators
|
||||
|
||||
return get_str( tmp.begin(), tmp.end() );
|
||||
}
|
||||
|
||||
// this class's methods get called by the spirit parse resulting
|
||||
// in the creation of a JSON object or array
|
||||
//
|
||||
// NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator
|
||||
//
|
||||
template< class Value_type, class Iter_type >
|
||||
class Semantic_actions
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename Value_type::Config_type Config_type;
|
||||
typedef typename Config_type::String_type String_type;
|
||||
typedef typename Config_type::Object_type Object_type;
|
||||
typedef typename Config_type::Array_type Array_type;
|
||||
typedef typename String_type::value_type Char_type;
|
||||
|
||||
Semantic_actions( Value_type& value )
|
||||
: value_( value )
|
||||
, current_p_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void begin_obj( Char_type c )
|
||||
{
|
||||
assert( c == '{' );
|
||||
|
||||
begin_compound< Object_type >();
|
||||
}
|
||||
|
||||
void end_obj( Char_type c )
|
||||
{
|
||||
assert( c == '}' );
|
||||
|
||||
end_compound();
|
||||
}
|
||||
|
||||
void begin_array( Char_type c )
|
||||
{
|
||||
assert( c == '[' );
|
||||
|
||||
begin_compound< Array_type >();
|
||||
}
|
||||
|
||||
void end_array( Char_type c )
|
||||
{
|
||||
assert( c == ']' );
|
||||
|
||||
end_compound();
|
||||
}
|
||||
|
||||
void new_name( Iter_type begin, Iter_type end )
|
||||
{
|
||||
assert( current_p_->type() == obj_type );
|
||||
|
||||
name_ = get_str< String_type >( begin, end );
|
||||
}
|
||||
|
||||
void new_str( Iter_type begin, Iter_type end )
|
||||
{
|
||||
add_to_current( get_str< String_type >( begin, end ) );
|
||||
}
|
||||
|
||||
void new_true( Iter_type begin, Iter_type end )
|
||||
{
|
||||
assert( is_eq( begin, end, "true" ) );
|
||||
|
||||
add_to_current( true );
|
||||
}
|
||||
|
||||
void new_false( Iter_type begin, Iter_type end )
|
||||
{
|
||||
assert( is_eq( begin, end, "false" ) );
|
||||
|
||||
add_to_current( false );
|
||||
}
|
||||
|
||||
void new_null( Iter_type begin, Iter_type end )
|
||||
{
|
||||
assert( is_eq( begin, end, "null" ) );
|
||||
|
||||
add_to_current( Value_type() );
|
||||
}
|
||||
|
||||
void new_int( boost::int64_t i )
|
||||
{
|
||||
add_to_current( i );
|
||||
}
|
||||
|
||||
void new_uint64( boost::uint64_t ui )
|
||||
{
|
||||
add_to_current( ui );
|
||||
}
|
||||
|
||||
void new_real( double d )
|
||||
{
|
||||
add_to_current( d );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Semantic_actions& operator=( const Semantic_actions& );
|
||||
// to prevent "assignment operator could not be generated" warning
|
||||
|
||||
Value_type* add_first( const Value_type& value )
|
||||
{
|
||||
assert( current_p_ == 0 );
|
||||
|
||||
value_ = value;
|
||||
current_p_ = &value_;
|
||||
return current_p_;
|
||||
}
|
||||
|
||||
template< class Array_or_obj >
|
||||
void begin_compound()
|
||||
{
|
||||
if( current_p_ == 0 )
|
||||
{
|
||||
add_first( Array_or_obj() );
|
||||
}
|
||||
else
|
||||
{
|
||||
stack_.push_back( current_p_ );
|
||||
|
||||
Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place
|
||||
|
||||
current_p_ = add_to_current( new_array_or_obj );
|
||||
}
|
||||
}
|
||||
|
||||
void end_compound()
|
||||
{
|
||||
if( current_p_ != &value_ )
|
||||
{
|
||||
current_p_ = stack_.back();
|
||||
|
||||
stack_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
Value_type* add_to_current( const Value_type& value )
|
||||
{
|
||||
if( current_p_ == 0 )
|
||||
{
|
||||
return add_first( value );
|
||||
}
|
||||
else if( current_p_->type() == array_type )
|
||||
{
|
||||
current_p_->get_array().push_back( value );
|
||||
|
||||
return ¤t_p_->get_array().back();
|
||||
}
|
||||
|
||||
assert( current_p_->type() == obj_type );
|
||||
|
||||
return &Config_type::add( current_p_->get_obj(), name_, value );
|
||||
}
|
||||
|
||||
Value_type& value_; // this is the object or array that is being created
|
||||
Value_type* current_p_; // the child object or array that is currently being constructed
|
||||
|
||||
std::vector< Value_type* > stack_; // previous child objects and arrays
|
||||
|
||||
String_type name_; // of current name/value pair
|
||||
};
|
||||
|
||||
template< typename Iter_type >
|
||||
void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason )
|
||||
{
|
||||
throw Error_position( i.get_position().line, i.get_position().column, reason );
|
||||
}
|
||||
|
||||
template< typename Iter_type >
|
||||
void throw_error( Iter_type i, const std::string& reason )
|
||||
{
|
||||
throw reason;
|
||||
}
|
||||
|
||||
// the spirit grammer
|
||||
//
|
||||
template< class Value_type, class Iter_type >
|
||||
class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t;
|
||||
|
||||
Json_grammer( Semantic_actions_t& semantic_actions )
|
||||
: actions_( semantic_actions )
|
||||
{
|
||||
}
|
||||
|
||||
static void throw_not_value( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not a value" );
|
||||
}
|
||||
|
||||
static void throw_not_array( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not an array" );
|
||||
}
|
||||
|
||||
static void throw_not_object( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not an object" );
|
||||
}
|
||||
|
||||
static void throw_not_pair( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not a pair" );
|
||||
}
|
||||
|
||||
static void throw_not_colon( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "no colon in pair" );
|
||||
}
|
||||
|
||||
static void throw_not_string( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not a string" );
|
||||
}
|
||||
|
||||
template< typename ScannerT >
|
||||
class definition
|
||||
{
|
||||
public:
|
||||
|
||||
definition( const Json_grammer& self )
|
||||
{
|
||||
using namespace spirit_namespace;
|
||||
|
||||
typedef typename Value_type::String_type::value_type Char_type;
|
||||
|
||||
// first we convert the semantic action class methods to functors with the
|
||||
// parameter signature expected by spirit
|
||||
|
||||
typedef boost::function< void( Char_type ) > Char_action;
|
||||
typedef boost::function< void( Iter_type, Iter_type ) > Str_action;
|
||||
typedef boost::function< void( double ) > Real_action;
|
||||
typedef boost::function< void( boost::int64_t ) > Int_action;
|
||||
typedef boost::function< void( boost::uint64_t ) > Uint64_action;
|
||||
|
||||
Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) );
|
||||
Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) );
|
||||
Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) );
|
||||
Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) );
|
||||
Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) );
|
||||
Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) );
|
||||
Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) );
|
||||
Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) );
|
||||
Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) );
|
||||
Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) );
|
||||
Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) );
|
||||
Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) );
|
||||
|
||||
// actual grammer
|
||||
|
||||
json_
|
||||
= value_ | eps_p[ &throw_not_value ]
|
||||
;
|
||||
|
||||
value_
|
||||
= string_[ new_str ]
|
||||
| number_
|
||||
| object_
|
||||
| array_
|
||||
| str_p( "true" ) [ new_true ]
|
||||
| str_p( "false" )[ new_false ]
|
||||
| str_p( "null" ) [ new_null ]
|
||||
;
|
||||
|
||||
object_
|
||||
= ch_p('{')[ begin_obj ]
|
||||
>> !members_
|
||||
>> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] )
|
||||
;
|
||||
|
||||
members_
|
||||
= pair_ >> *( ',' >> pair_ )
|
||||
;
|
||||
|
||||
pair_
|
||||
= string_[ new_name ]
|
||||
>> ( ':' | eps_p[ &throw_not_colon ] )
|
||||
>> ( value_ | eps_p[ &throw_not_value ] )
|
||||
;
|
||||
|
||||
array_
|
||||
= ch_p('[')[ begin_array ]
|
||||
>> !elements_
|
||||
>> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] )
|
||||
;
|
||||
|
||||
elements_
|
||||
= value_ >> *( ',' >> value_ )
|
||||
;
|
||||
|
||||
string_
|
||||
= lexeme_d // this causes white space inside a string to be retained
|
||||
[
|
||||
confix_p
|
||||
(
|
||||
'"',
|
||||
*lex_escape_ch_p,
|
||||
'"'
|
||||
)
|
||||
]
|
||||
;
|
||||
|
||||
number_
|
||||
= strict_real_p[ new_real ]
|
||||
| int64_p [ new_int ]
|
||||
| uint64_p [ new_uint64 ]
|
||||
;
|
||||
}
|
||||
|
||||
spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_;
|
||||
|
||||
const spirit_namespace::rule< ScannerT >& start() const { return json_; }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning
|
||||
|
||||
Semantic_actions_t& actions_;
|
||||
};
|
||||
|
||||
template< class Iter_type, class Value_type >
|
||||
Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
|
||||
{
|
||||
Semantic_actions< Value_type, Iter_type > semantic_actions( value );
|
||||
|
||||
const spirit_namespace::parse_info< Iter_type > info =
|
||||
spirit_namespace::parse( begin, end,
|
||||
Json_grammer< Value_type, Iter_type >( semantic_actions ),
|
||||
spirit_namespace::space_p );
|
||||
|
||||
if( !info.hit )
|
||||
{
|
||||
assert( false ); // in theory exception should already have been thrown
|
||||
throw_error( info.stop, "error" );
|
||||
}
|
||||
|
||||
return info.stop;
|
||||
}
|
||||
|
||||
template< class Iter_type, class Value_type >
|
||||
void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
|
||||
{
|
||||
typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t;
|
||||
|
||||
const Posn_iter_t posn_begin( begin, end );
|
||||
const Posn_iter_t posn_end( end, end );
|
||||
|
||||
read_range_or_throw( posn_begin, posn_end, value );
|
||||
}
|
||||
|
||||
template< class Iter_type, class Value_type >
|
||||
bool read_range( Iter_type& begin, Iter_type end, Value_type& value )
|
||||
{
|
||||
try
|
||||
{
|
||||
begin = read_range_or_throw( begin, end, value );
|
||||
|
||||
return true;
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template< class String_type, class Value_type >
|
||||
void read_string_or_throw( const String_type& s, Value_type& value )
|
||||
{
|
||||
add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value );
|
||||
}
|
||||
|
||||
template< class String_type, class Value_type >
|
||||
bool read_string( const String_type& s, Value_type& value )
|
||||
{
|
||||
typename String_type::const_iterator begin = s.begin();
|
||||
|
||||
return read_range( begin, s.end(), value );
|
||||
}
|
||||
|
||||
template< class Istream_type >
|
||||
struct Multi_pass_iters
|
||||
{
|
||||
typedef typename Istream_type::char_type Char_type;
|
||||
typedef std::istream_iterator< Char_type, Char_type > istream_iter;
|
||||
typedef spirit_namespace::multi_pass< istream_iter > Mp_iter;
|
||||
|
||||
Multi_pass_iters( Istream_type& is )
|
||||
{
|
||||
is.unsetf( std::ios::skipws );
|
||||
|
||||
begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) );
|
||||
end_ = spirit_namespace::make_multi_pass( istream_iter() );
|
||||
}
|
||||
|
||||
Mp_iter begin_;
|
||||
Mp_iter end_;
|
||||
};
|
||||
|
||||
template< class Istream_type, class Value_type >
|
||||
bool read_stream( Istream_type& is, Value_type& value )
|
||||
{
|
||||
Multi_pass_iters< Istream_type > mp_iters( is );
|
||||
|
||||
return read_range( mp_iters.begin_, mp_iters.end_, value );
|
||||
}
|
||||
|
||||
template< class Istream_type, class Value_type >
|
||||
void read_stream_or_throw( Istream_type& is, Value_type& value )
|
||||
{
|
||||
const Multi_pass_iters< Istream_type > mp_iters( is );
|
||||
|
||||
add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
70
src/json/json_spirit_stream_reader.h
Normal file
70
src/json/json_spirit_stream_reader.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#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
|
||||
61
src/json/json_spirit_utils.h
Normal file
61
src/json/json_spirit_utils.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#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
|
||||
8
src/json/json_spirit_value.cpp
Normal file
8
src/json/json_spirit_value.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
/* 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/json_spirit_value.h"
|
||||
534
src/json/json_spirit_value.h
Normal file
534
src/json/json_spirit_value.h
Normal file
@@ -0,0 +1,534 @@
|
||||
#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;
|
||||
|
||||
///// Bitcoin: 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
|
||||
95
src/json/json_spirit_writer.cpp
Normal file
95
src/json/json_spirit_writer.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#include "json/json_spirit_writer.h"
|
||||
#include "json/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
|
||||
50
src/json/json_spirit_writer.h
Normal file
50
src/json/json_spirit_writer.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#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
|
||||
248
src/json/json_spirit_writer_template.h
Normal file
248
src/json/json_spirit_writer_template.h
Normal file
@@ -0,0 +1,248 @@
|
||||
#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;
|
||||
|
||||
/// Bitcoin: Added std::fixed and changed precision from 16 to 8
|
||||
case real_type: os_ << std::showpoint << std::fixed << std::setprecision(8)
|
||||
<< 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
|
||||
175
src/key.h
Normal file
175
src/key.h
Normal file
@@ -0,0 +1,175 @@
|
||||
// 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.
|
||||
#ifndef BITCOIN_KEY_H
|
||||
#define BITCOIN_KEY_H
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
// 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 std::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 std::vector<unsigned char>& vchPubKey)
|
||||
{
|
||||
const unsigned char* pbegin = &vchPubKey[0];
|
||||
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
|
||||
return false;
|
||||
fSet = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> GetPubKey() const
|
||||
{
|
||||
unsigned int nSize = i2o_ECPublicKey(pkey, NULL);
|
||||
if (!nSize)
|
||||
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
|
||||
std::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, std::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 std::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, std::vector<unsigned char>& vchSig)
|
||||
{
|
||||
CKey key;
|
||||
if (!key.SetPrivKey(vchPrivKey))
|
||||
return false;
|
||||
return key.Sign(hash, vchSig);
|
||||
}
|
||||
|
||||
static bool Verify(const std::vector<unsigned char>& vchPubKey, uint256 hash, const std::vector<unsigned char>& vchSig)
|
||||
{
|
||||
CKey key;
|
||||
if (!key.SetPubKey(vchPubKey))
|
||||
return false;
|
||||
return key.Verify(hash, vchSig);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
4033
src/main.cpp
Normal file
4033
src/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2066
src/main.h
Normal file
2066
src/main.h
Normal file
File diff suppressed because it is too large
Load Diff
1667
src/net.cpp
Normal file
1667
src/net.cpp
Normal file
File diff suppressed because it is too large
Load Diff
67
src/noui.h
Normal file
67
src/noui.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2010 Satoshi Nakamoto
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef BITCOIN_NOUI_H
|
||||
#define BITCOIN_NOUI_H
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef void wxWindow;
|
||||
#define wxYES 0x00000002
|
||||
#define wxOK 0x00000004
|
||||
#define wxNO 0x00000008
|
||||
#define wxYES_NO (wxYES|wxNO)
|
||||
#define wxCANCEL 0x00000010
|
||||
#define wxAPPLY 0x00000020
|
||||
#define wxCLOSE 0x00000040
|
||||
#define wxOK_DEFAULT 0x00000000
|
||||
#define wxYES_DEFAULT 0x00000000
|
||||
#define wxNO_DEFAULT 0x00000080
|
||||
#define wxCANCEL_DEFAULT 0x80000000
|
||||
#define wxICON_EXCLAMATION 0x00000100
|
||||
#define wxICON_HAND 0x00000200
|
||||
#define wxICON_WARNING wxICON_EXCLAMATION
|
||||
#define wxICON_ERROR wxICON_HAND
|
||||
#define wxICON_QUESTION 0x00000400
|
||||
#define wxICON_INFORMATION 0x00000800
|
||||
#define wxICON_STOP wxICON_HAND
|
||||
#define wxICON_ASTERISK wxICON_INFORMATION
|
||||
#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800)
|
||||
#define wxFORWARD 0x00001000
|
||||
#define wxBACKWARD 0x00002000
|
||||
#define wxRESET 0x00004000
|
||||
#define wxHELP 0x00008000
|
||||
#define wxMORE 0x00010000
|
||||
#define wxSETUP 0x00020000
|
||||
|
||||
inline int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
|
||||
{
|
||||
printf("%s: %s\n", caption.c_str(), message.c_str());
|
||||
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
|
||||
return 4;
|
||||
}
|
||||
#define wxMessageBox MyMessageBox
|
||||
|
||||
inline int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
|
||||
{
|
||||
return MyMessageBox(message, caption, style, parent, x, y);
|
||||
}
|
||||
|
||||
inline bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void CalledSetStatusBar(const std::string& strText, int nField)
|
||||
{
|
||||
}
|
||||
|
||||
inline void UIThreadCall(boost::function0<void> fn)
|
||||
{
|
||||
}
|
||||
|
||||
inline void MainFrameRepaint()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
22
src/qt/aboutdialog.cpp
Normal file
22
src/qt/aboutdialog.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "aboutdialog.h"
|
||||
#include "ui_aboutdialog.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
AboutDialog::AboutDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AboutDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->versionLabel->setText(QString::fromStdString(FormatFullVersion()));
|
||||
}
|
||||
|
||||
AboutDialog::~AboutDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void AboutDialog::on_buttonBox_accepted()
|
||||
{
|
||||
close();
|
||||
}
|
||||
25
src/qt/aboutdialog.h
Normal file
25
src/qt/aboutdialog.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef ABOUTDIALOG_H
|
||||
#define ABOUTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class AboutDialog;
|
||||
}
|
||||
|
||||
class AboutDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AboutDialog(QWidget *parent = 0);
|
||||
~AboutDialog();
|
||||
|
||||
private:
|
||||
Ui::AboutDialog *ui;
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
};
|
||||
|
||||
#endif // ABOUTDIALOG_H
|
||||
168
src/qt/addressbookdialog.cpp
Normal file
168
src/qt/addressbookdialog.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "addressbookdialog.h"
|
||||
#include "ui_addressbookdialog.h"
|
||||
|
||||
#include "addresstablemodel.h"
|
||||
#include "editaddressdialog.h"
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QClipboard>
|
||||
#include <QDebug>
|
||||
|
||||
AddressBookDialog::AddressBookDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AddressBookDialog),
|
||||
model(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
AddressBookDialog::~AddressBookDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void AddressBookDialog::setModel(AddressTableModel *model)
|
||||
{
|
||||
this->model = model;
|
||||
/* Refresh list from core */
|
||||
model->updateList();
|
||||
|
||||
/* Receive filter */
|
||||
QSortFilterProxyModel *receive_model = new QSortFilterProxyModel(this);
|
||||
receive_model->setSourceModel(model);
|
||||
receive_model->setDynamicSortFilter(true);
|
||||
receive_model->setFilterRole(AddressTableModel::TypeRole);
|
||||
receive_model->setFilterFixedString(AddressTableModel::Receive);
|
||||
ui->receiveTableView->setModel(receive_model);
|
||||
|
||||
/* Send filter */
|
||||
QSortFilterProxyModel *send_model = new QSortFilterProxyModel(this);
|
||||
send_model->setSourceModel(model);
|
||||
send_model->setDynamicSortFilter(true);
|
||||
send_model->setFilterRole(AddressTableModel::TypeRole);
|
||||
send_model->setFilterFixedString(AddressTableModel::Send);
|
||||
ui->sendTableView->setModel(send_model);
|
||||
|
||||
/* Set column widths */
|
||||
ui->receiveTableView->horizontalHeader()->resizeSection(
|
||||
AddressTableModel::Address, 320);
|
||||
ui->receiveTableView->horizontalHeader()->setResizeMode(
|
||||
AddressTableModel::Label, QHeaderView::Stretch);
|
||||
ui->sendTableView->horizontalHeader()->resizeSection(
|
||||
AddressTableModel::Address, 320);
|
||||
ui->sendTableView->horizontalHeader()->setResizeMode(
|
||||
AddressTableModel::Label, QHeaderView::Stretch);
|
||||
}
|
||||
|
||||
void AddressBookDialog::setTab(int tab)
|
||||
{
|
||||
ui->tabWidget->setCurrentIndex(tab);
|
||||
}
|
||||
|
||||
QTableView *AddressBookDialog::getCurrentTable()
|
||||
{
|
||||
switch(ui->tabWidget->currentIndex())
|
||||
{
|
||||
case SendingTab:
|
||||
return ui->sendTableView;
|
||||
case ReceivingTab:
|
||||
return ui->receiveTableView;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBookDialog::on_copyToClipboard_clicked()
|
||||
{
|
||||
/* Copy currently selected address to clipboard
|
||||
(or nothing, if nothing selected)
|
||||
*/
|
||||
QTableView *table = getCurrentTable();
|
||||
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
|
||||
|
||||
foreach (QModelIndex index, indexes)
|
||||
{
|
||||
QVariant address = index.data();
|
||||
QApplication::clipboard()->setText(address.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBookDialog::on_editButton_clicked()
|
||||
{
|
||||
QModelIndexList indexes = getCurrentTable()->selectionModel()->selectedRows();
|
||||
if(indexes.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* Map selected index to source address book model */
|
||||
QAbstractProxyModel *proxy_model = static_cast<QAbstractProxyModel*>(getCurrentTable()->model());
|
||||
QModelIndex selected = proxy_model->mapToSource(indexes.at(0));
|
||||
|
||||
/* Double click also triggers edit button */
|
||||
EditAddressDialog dlg(
|
||||
ui->tabWidget->currentIndex() == SendingTab ?
|
||||
EditAddressDialog::EditSendingAddress :
|
||||
EditAddressDialog::EditReceivingAddress);
|
||||
dlg.setModel(model);
|
||||
dlg.loadRow(selected.row());
|
||||
if(dlg.exec())
|
||||
{
|
||||
dlg.saveCurrentRow();
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBookDialog::on_newAddressButton_clicked()
|
||||
{
|
||||
EditAddressDialog dlg(
|
||||
ui->tabWidget->currentIndex() == SendingTab ?
|
||||
EditAddressDialog::NewSendingAddress :
|
||||
EditAddressDialog::NewReceivingAddress);
|
||||
dlg.setModel(model);
|
||||
if(dlg.exec())
|
||||
{
|
||||
dlg.saveCurrentRow();
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBookDialog::on_tabWidget_currentChanged(int index)
|
||||
{
|
||||
switch(index)
|
||||
{
|
||||
case SendingTab:
|
||||
ui->deleteButton->setEnabled(true);
|
||||
break;
|
||||
case ReceivingTab:
|
||||
ui->deleteButton->setEnabled(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBookDialog::on_deleteButton_clicked()
|
||||
{
|
||||
QTableView *table = getCurrentTable();
|
||||
QModelIndexList indexes = table->selectionModel()->selectedRows();
|
||||
if(!indexes.isEmpty())
|
||||
{
|
||||
table->model()->removeRow(indexes.at(0).row());
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBookDialog::on_buttonBox_accepted()
|
||||
{
|
||||
QTableView *table = getCurrentTable();
|
||||
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
|
||||
|
||||
foreach (QModelIndex index, indexes)
|
||||
{
|
||||
QVariant address = table->model()->data(index);
|
||||
returnValue = address.toString();
|
||||
}
|
||||
if(!returnValue.isEmpty())
|
||||
{
|
||||
accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
reject();
|
||||
}
|
||||
}
|
||||
47
src/qt/addressbookdialog.h
Normal file
47
src/qt/addressbookdialog.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef ADDRESSBOOKDIALOG_H
|
||||
#define ADDRESSBOOKDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class AddressBookDialog;
|
||||
}
|
||||
class AddressTableModel;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QTableView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class AddressBookDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AddressBookDialog(QWidget *parent = 0);
|
||||
~AddressBookDialog();
|
||||
|
||||
enum {
|
||||
SendingTab = 0,
|
||||
ReceivingTab = 1
|
||||
} Tabs;
|
||||
|
||||
void setModel(AddressTableModel *model);
|
||||
void setTab(int tab);
|
||||
const QString &getReturnValue() const { return returnValue; }
|
||||
private:
|
||||
Ui::AddressBookDialog *ui;
|
||||
AddressTableModel *model;
|
||||
QString returnValue;
|
||||
|
||||
QTableView *getCurrentTable();
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
void on_deleteButton_clicked();
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
void on_newAddressButton_clicked();
|
||||
void on_editButton_clicked();
|
||||
void on_copyToClipboard_clicked();
|
||||
};
|
||||
|
||||
#endif // ADDRESSBOOKDIALOG_H
|
||||
245
src/qt/addresstablemodel.cpp
Normal file
245
src/qt/addresstablemodel.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
#include "addresstablemodel.h"
|
||||
#include "guiutil.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <QFont>
|
||||
|
||||
const QString AddressTableModel::Send = "S";
|
||||
const QString AddressTableModel::Receive = "R";
|
||||
|
||||
struct AddressTableEntry
|
||||
{
|
||||
enum Type {
|
||||
Sending,
|
||||
Receiving
|
||||
};
|
||||
|
||||
Type type;
|
||||
QString label;
|
||||
QString address;
|
||||
|
||||
AddressTableEntry() {}
|
||||
AddressTableEntry(Type type, const QString &label, const QString &address):
|
||||
type(type), label(label), address(address) {}
|
||||
};
|
||||
|
||||
/* Private implementation */
|
||||
struct AddressTablePriv
|
||||
{
|
||||
QList<AddressTableEntry> cachedAddressTable;
|
||||
|
||||
void refreshAddressTable()
|
||||
{
|
||||
cachedAddressTable.clear();
|
||||
|
||||
CRITICAL_BLOCK(cs_mapKeys)
|
||||
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||
{
|
||||
BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, mapAddressBook)
|
||||
{
|
||||
std::string strAddress = item.first;
|
||||
std::string strName = item.second;
|
||||
uint160 hash160;
|
||||
bool fMine = (AddressToHash160(strAddress, hash160) && mapPubKeys.count(hash160));
|
||||
cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending,
|
||||
QString::fromStdString(strName),
|
||||
QString::fromStdString(strAddress)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int size()
|
||||
{
|
||||
return cachedAddressTable.size();
|
||||
}
|
||||
|
||||
AddressTableEntry *index(int idx)
|
||||
{
|
||||
if(idx >= 0 && idx < cachedAddressTable.size())
|
||||
{
|
||||
return &cachedAddressTable[idx];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AddressTableModel::AddressTableModel(QObject *parent) :
|
||||
QAbstractTableModel(parent),priv(0)
|
||||
{
|
||||
columns << tr("Label") << tr("Address");
|
||||
priv = new AddressTablePriv();
|
||||
priv->refreshAddressTable();
|
||||
}
|
||||
|
||||
AddressTableModel::~AddressTableModel()
|
||||
{
|
||||
delete priv;
|
||||
}
|
||||
|
||||
int AddressTableModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return priv->size();
|
||||
}
|
||||
|
||||
int AddressTableModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return columns.length();
|
||||
}
|
||||
|
||||
QVariant AddressTableModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if(!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
|
||||
|
||||
if(role == Qt::DisplayRole || role == Qt::EditRole)
|
||||
{
|
||||
switch(index.column())
|
||||
{
|
||||
case Label:
|
||||
return rec->label;
|
||||
case Address:
|
||||
return rec->address;
|
||||
}
|
||||
}
|
||||
else if (role == Qt::FontRole)
|
||||
{
|
||||
if(index.column() == Address)
|
||||
{
|
||||
return GUIUtil::bitcoinAddressFont();
|
||||
}
|
||||
}
|
||||
else if (role == TypeRole)
|
||||
{
|
||||
switch(rec->type)
|
||||
{
|
||||
case AddressTableEntry::Sending:
|
||||
return Send;
|
||||
case AddressTableEntry::Receiving:
|
||||
return Receive;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool AddressTableModel::setData(const QModelIndex & index, const QVariant & value, int role)
|
||||
{
|
||||
if(!index.isValid())
|
||||
return false;
|
||||
AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
|
||||
|
||||
if(role == Qt::EditRole)
|
||||
{
|
||||
switch(index.column())
|
||||
{
|
||||
case Label:
|
||||
SetAddressBookName(rec->address.toStdString(), value.toString().toStdString());
|
||||
rec->label = value.toString();
|
||||
break;
|
||||
case Address:
|
||||
/* Double-check that we're not overwriting receiving address */
|
||||
if(rec->type == AddressTableEntry::Sending)
|
||||
{
|
||||
/* Remove old entry */
|
||||
CWalletDB().EraseName(rec->address.toStdString());
|
||||
/* Add new entry with new address */
|
||||
SetAddressBookName(value.toString().toStdString(), rec->label.toStdString());
|
||||
|
||||
rec->address = value.toString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
emit dataChanged(index, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if(orientation == Qt::Horizontal)
|
||||
{
|
||||
if(role == Qt::DisplayRole)
|
||||
{
|
||||
return columns[section];
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
AddressTableEntry *data = priv->index(row);
|
||||
if(data)
|
||||
{
|
||||
return createIndex(row, column, priv->index(row));
|
||||
}
|
||||
else
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
void AddressTableModel::updateList()
|
||||
{
|
||||
/* Update internal model from Bitcoin core */
|
||||
beginResetModel();
|
||||
priv->refreshAddressTable();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address)
|
||||
{
|
||||
std::string strLabel = label.toStdString();
|
||||
std::string strAddress = address.toStdString();
|
||||
|
||||
if(type == Send)
|
||||
{
|
||||
/* Check for duplicate */
|
||||
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||
{
|
||||
if(mapAddressBook.count(strAddress))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(type == Receive)
|
||||
{
|
||||
/* Generate a new address to associate with given label */
|
||||
strAddress = PubKeyToAddress(GetKeyFromKeyPool());
|
||||
}
|
||||
else
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
/* Add entry and update list */
|
||||
SetAddressBookName(strAddress, strLabel);
|
||||
updateList();
|
||||
return QString::fromStdString(strAddress);
|
||||
}
|
||||
|
||||
bool AddressTableModel::removeRows(int row, int count, const QModelIndex & parent)
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
AddressTableEntry *rec = priv->index(row);
|
||||
if(count != 1 || !rec || rec->type == AddressTableEntry::Receiving)
|
||||
{
|
||||
/* Can only remove one row at a time, and cannot remove rows not in model.
|
||||
Also refuse to remove receiving addresses.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
CWalletDB().EraseName(rec->address.toStdString());
|
||||
updateList();
|
||||
return true;
|
||||
}
|
||||
54
src/qt/addresstablemodel.h
Normal file
54
src/qt/addresstablemodel.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef ADDRESSTABLEMODEL_H
|
||||
#define ADDRESSTABLEMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStringList>
|
||||
|
||||
class AddressTablePriv;
|
||||
|
||||
class AddressTableModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AddressTableModel(QObject *parent = 0);
|
||||
~AddressTableModel();
|
||||
|
||||
enum ColumnIndex {
|
||||
Label = 0, /* User specified label */
|
||||
Address = 1 /* Bitcoin address */
|
||||
};
|
||||
|
||||
enum {
|
||||
TypeRole = Qt::UserRole
|
||||
} RoleIndex;
|
||||
|
||||
static const QString Send; /* Send addres */
|
||||
static const QString Receive; /* Receive address */
|
||||
|
||||
/* Overridden methods from QAbstractTableModel */
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
int columnCount(const QModelIndex &parent) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
bool setData(const QModelIndex & index, const QVariant & value, int role);
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
QModelIndex index(int row, int column, const QModelIndex & parent) const;
|
||||
bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex());
|
||||
|
||||
/* Add an address to the model.
|
||||
Returns the added address on success, and an empty string otherwise.
|
||||
*/
|
||||
QString addRow(const QString &type, const QString &label, const QString &address);
|
||||
|
||||
/* Update address list from core. Invalidates any indices.
|
||||
*/
|
||||
void updateList();
|
||||
private:
|
||||
AddressTablePriv *priv;
|
||||
QStringList columns;
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
#endif // ADDRESSTABLEMODEL_H
|
||||
122
src/qt/bitcoin.cpp
Normal file
122
src/qt/bitcoin.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* W.J. van der Laan 2011
|
||||
*/
|
||||
#include "bitcoingui.h"
|
||||
#include "clientmodel.h"
|
||||
#include "util.h"
|
||||
#include "init.h"
|
||||
#include "main.h"
|
||||
#include "externui.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QThread>
|
||||
|
||||
// Need a global reference for the notifications to find the GUI
|
||||
BitcoinGUI *guiref;
|
||||
|
||||
int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
|
||||
{
|
||||
// Message from main thread
|
||||
if(guiref)
|
||||
{
|
||||
guiref->error(QString::fromStdString(caption),
|
||||
QString::fromStdString(message));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(0, QString::fromStdString(caption),
|
||||
QString::fromStdString(message),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
|
||||
{
|
||||
// Message from network thread
|
||||
if(guiref)
|
||||
{
|
||||
QMetaObject::invokeMethod(guiref, "error", Qt::QueuedConnection,
|
||||
Q_ARG(QString, QString::fromStdString(caption)),
|
||||
Q_ARG(QString, QString::fromStdString(message)));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: %s\n", caption.c_str(), message.c_str());
|
||||
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
|
||||
{
|
||||
if(!guiref)
|
||||
return false;
|
||||
if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
|
||||
return true;
|
||||
bool payFee = false;
|
||||
|
||||
/* Call slot on GUI thread.
|
||||
If called from another thread, use a blocking QueuedConnection.
|
||||
*/
|
||||
Qt::ConnectionType connectionType = Qt::DirectConnection;
|
||||
if(QThread::currentThread() != QCoreApplication::instance()->thread())
|
||||
{
|
||||
connectionType = Qt::BlockingQueuedConnection;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(guiref, "askFee", connectionType,
|
||||
Q_ARG(qint64, nFeeRequired),
|
||||
Q_ARG(bool*, &payFee));
|
||||
|
||||
return payFee;
|
||||
}
|
||||
|
||||
void CalledSetStatusBar(const std::string& strText, int nField)
|
||||
{
|
||||
// Only used for built-in mining, which is disabled, simple ignore
|
||||
}
|
||||
|
||||
void UIThreadCall(boost::function0<void> fn)
|
||||
{
|
||||
// Only used for built-in mining, which is disabled, simple ignore
|
||||
}
|
||||
|
||||
void MainFrameRepaint()
|
||||
{
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
|
||||
try
|
||||
{
|
||||
if(AppInit2(argc, argv))
|
||||
{
|
||||
BitcoinGUI window;
|
||||
ClientModel model;
|
||||
guiref = &window;
|
||||
window.setModel(&model);
|
||||
|
||||
window.show();
|
||||
|
||||
int retval = app.exec();
|
||||
|
||||
guiref = 0;
|
||||
Shutdown(NULL);
|
||||
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
PrintException(&e, "Runaway exception");
|
||||
} catch (...) {
|
||||
PrintException(NULL, "Runaway exception");
|
||||
}
|
||||
}
|
||||
12
src/qt/bitcoin.qrc
Normal file
12
src/qt/bitcoin.qrc
Normal file
@@ -0,0 +1,12 @@
|
||||
<RCC>
|
||||
<qresource prefix="/icons">
|
||||
<file alias="address-book">res/icons/address-book.png</file>
|
||||
<file alias="bitcoin">res/icons/bitcoin.png</file>
|
||||
<file alias="quit">res/icons/quit.png</file>
|
||||
<file alias="send">res/icons/send.png</file>
|
||||
<file alias="toolbar">res/icons/toolbar.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/images">
|
||||
<file alias="about">res/images/about.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
63
src/qt/bitcoinaddressvalidator.cpp
Normal file
63
src/qt/bitcoinaddressvalidator.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "bitcoinaddressvalidator.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
/* Base58 characters are:
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
|
||||
This is:
|
||||
- All numbers except for '0'
|
||||
- All uppercase letters except for 'I' and 'O'
|
||||
- All lowercase letters except for 'l'
|
||||
|
||||
User friendly Base58 input can map
|
||||
- 'l' and 'I' to '1'
|
||||
- '0' and 'O' to 'o'
|
||||
*/
|
||||
|
||||
BitcoinAddressValidator::BitcoinAddressValidator(QObject *parent) :
|
||||
QValidator(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) const
|
||||
{
|
||||
/* Correction */
|
||||
for(int idx=0; idx<input.size(); ++idx)
|
||||
{
|
||||
switch(input.at(idx).unicode())
|
||||
{
|
||||
case 'l':
|
||||
case 'I':
|
||||
input[idx] = QChar('1');
|
||||
break;
|
||||
case '0':
|
||||
case 'O':
|
||||
input[idx] = QChar('o');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Validation */
|
||||
QValidator::State state = QValidator::Acceptable;
|
||||
for(int idx=0; idx<input.size(); ++idx)
|
||||
{
|
||||
int ch = input.at(idx).unicode();
|
||||
|
||||
if(((ch >= '0' && ch<='9') ||
|
||||
(ch >= 'a' && ch<='z') ||
|
||||
(ch >= 'A' && ch<='Z')) &&
|
||||
ch != 'l' && ch != 'I' && ch != '0' && ch != 'O')
|
||||
{
|
||||
/* Alphanumeric and not a 'forbidden' character */
|
||||
}
|
||||
else
|
||||
{
|
||||
state = QValidator::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
24
src/qt/bitcoinaddressvalidator.h
Normal file
24
src/qt/bitcoinaddressvalidator.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef BITCOINADDRESSVALIDATOR_H
|
||||
#define BITCOINADDRESSVALIDATOR_H
|
||||
|
||||
#include <QRegExpValidator>
|
||||
|
||||
/* Base48 entry widget validator.
|
||||
Corrects near-miss characters and refuses characters that are no part of base48.
|
||||
*/
|
||||
class BitcoinAddressValidator : public QValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BitcoinAddressValidator(QObject *parent = 0);
|
||||
|
||||
State validate(QString &input, int &pos) const;
|
||||
|
||||
static const int MaxAddressLength = 34;
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
#endif // BITCOINADDRESSVALIDATOR_H
|
||||
448
src/qt/bitcoingui.cpp
Normal file
448
src/qt/bitcoingui.cpp
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Qt4 bitcoin GUI.
|
||||
*
|
||||
* W.J. van der Laan 2011
|
||||
*/
|
||||
#include "bitcoingui.h"
|
||||
#include "transactiontablemodel.h"
|
||||
#include "addressbookdialog.h"
|
||||
#include "sendcoinsdialog.h"
|
||||
#include "optionsdialog.h"
|
||||
#include "aboutdialog.h"
|
||||
#include "clientmodel.h"
|
||||
#include "guiutil.h"
|
||||
#include "editaddressdialog.h"
|
||||
#include "optionsmodel.h"
|
||||
#include "transactiondescdialog.h"
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
#include <QMenuBar>
|
||||
#include <QMenu>
|
||||
#include <QIcon>
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QToolBar>
|
||||
#include <QStatusBar>
|
||||
#include <QLabel>
|
||||
#include <QTableView>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QHeaderView>
|
||||
#include <QLocale>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QClipboard>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
BitcoinGUI::BitcoinGUI(QWidget *parent):
|
||||
QMainWindow(parent), trayIcon(0)
|
||||
{
|
||||
resize(850, 550);
|
||||
setWindowTitle(tr("Bitcoin"));
|
||||
setWindowIcon(QIcon(":icons/bitcoin"));
|
||||
|
||||
createActions();
|
||||
|
||||
// Menus
|
||||
QMenu *file = menuBar()->addMenu("&File");
|
||||
file->addAction(sendcoins);
|
||||
file->addSeparator();
|
||||
file->addAction(quit);
|
||||
|
||||
QMenu *settings = menuBar()->addMenu("&Settings");
|
||||
settings->addAction(receivingAddresses);
|
||||
settings->addAction(options);
|
||||
|
||||
QMenu *help = menuBar()->addMenu("&Help");
|
||||
help->addAction(about);
|
||||
|
||||
// Toolbar
|
||||
QToolBar *toolbar = addToolBar("Main toolbar");
|
||||
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
toolbar->addAction(sendcoins);
|
||||
toolbar->addAction(addressbook);
|
||||
|
||||
// Address: <address>: New... : Paste to clipboard
|
||||
QHBoxLayout *hbox_address = new QHBoxLayout();
|
||||
hbox_address->addWidget(new QLabel(tr("Your Bitcoin Address:")));
|
||||
address = new QLineEdit();
|
||||
address->setReadOnly(true);
|
||||
address->setFont(GUIUtil::bitcoinAddressFont());
|
||||
address->setToolTip(tr("Your current default receiving address"));
|
||||
hbox_address->addWidget(address);
|
||||
|
||||
QPushButton *button_new = new QPushButton(tr("&New..."));
|
||||
button_new->setToolTip(tr("Create new receiving address"));
|
||||
QPushButton *button_clipboard = new QPushButton(tr("&Copy to clipboard"));
|
||||
button_clipboard->setToolTip(tr("Copy current receiving address to the system clipboard"));
|
||||
hbox_address->addWidget(button_new);
|
||||
hbox_address->addWidget(button_clipboard);
|
||||
|
||||
// Balance: <balance>
|
||||
QHBoxLayout *hbox_balance = new QHBoxLayout();
|
||||
hbox_balance->addWidget(new QLabel(tr("Balance:")));
|
||||
hbox_balance->addSpacing(5);/* Add some spacing between the label and the text */
|
||||
|
||||
labelBalance = new QLabel();
|
||||
labelBalance->setFont(QFont("Monospace"));
|
||||
labelBalance->setToolTip(tr("Your current balance"));
|
||||
hbox_balance->addWidget(labelBalance);
|
||||
hbox_balance->addStretch(1);
|
||||
|
||||
QVBoxLayout *vbox = new QVBoxLayout();
|
||||
vbox->addLayout(hbox_address);
|
||||
vbox->addLayout(hbox_balance);
|
||||
|
||||
vbox->addWidget(createTabs());
|
||||
|
||||
QWidget *centralwidget = new QWidget(this);
|
||||
centralwidget->setLayout(vbox);
|
||||
setCentralWidget(centralwidget);
|
||||
|
||||
// Create status bar
|
||||
statusBar();
|
||||
|
||||
labelConnections = new QLabel();
|
||||
labelConnections->setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
||||
labelConnections->setMinimumWidth(130);
|
||||
labelConnections->setToolTip(tr("Number of connections to other clients"));
|
||||
|
||||
labelBlocks = new QLabel();
|
||||
labelBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
||||
labelBlocks->setMinimumWidth(130);
|
||||
labelBlocks->setToolTip(tr("Number of blocks in the block chain"));
|
||||
|
||||
labelTransactions = new QLabel();
|
||||
labelTransactions->setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
||||
labelTransactions->setMinimumWidth(130);
|
||||
labelTransactions->setToolTip(tr("Number of transactions in your wallet"));
|
||||
|
||||
statusBar()->addPermanentWidget(labelConnections);
|
||||
statusBar()->addPermanentWidget(labelBlocks);
|
||||
statusBar()->addPermanentWidget(labelTransactions);
|
||||
|
||||
// Action bindings
|
||||
connect(button_new, SIGNAL(clicked()), this, SLOT(newAddressClicked()));
|
||||
connect(button_clipboard, SIGNAL(clicked()), this, SLOT(copyClipboardClicked()));
|
||||
|
||||
createTrayIcon();
|
||||
}
|
||||
|
||||
void BitcoinGUI::createActions()
|
||||
{
|
||||
quit = new QAction(QIcon(":/icons/quit"), tr("&Exit"), this);
|
||||
quit->setToolTip(tr("Quit application"));
|
||||
sendcoins = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
|
||||
sendcoins->setToolTip(tr("Send coins to a bitcoin address"));
|
||||
addressbook = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
|
||||
addressbook->setToolTip(tr("Edit the list of stored addresses and labels"));
|
||||
about = new QAction(QIcon(":/icons/bitcoin"), tr("&About"), this);
|
||||
about->setToolTip(tr("Show information about Bitcoin"));
|
||||
receivingAddresses = new QAction(QIcon(":/icons/receiving-addresses"), tr("Your &Receiving Addresses..."), this);
|
||||
receivingAddresses->setToolTip(tr("Show the list of receiving addresses and edit their labels"));
|
||||
options = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
|
||||
options->setToolTip(tr("Modify configuration options for bitcoin"));
|
||||
openBitcoin = new QAction(QIcon(":/icons/bitcoin"), "Open &Bitcoin", this);
|
||||
openBitcoin->setToolTip(tr("Show the Bitcoin window"));
|
||||
|
||||
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||
connect(sendcoins, SIGNAL(triggered()), this, SLOT(sendcoinsClicked()));
|
||||
connect(addressbook, SIGNAL(triggered()), this, SLOT(addressbookClicked()));
|
||||
connect(receivingAddresses, SIGNAL(triggered()), this, SLOT(receivingAddressesClicked()));
|
||||
connect(options, SIGNAL(triggered()), this, SLOT(optionsClicked()));
|
||||
connect(about, SIGNAL(triggered()), this, SLOT(aboutClicked()));
|
||||
connect(openBitcoin, SIGNAL(triggered()), this, SLOT(show()));
|
||||
}
|
||||
|
||||
void BitcoinGUI::setModel(ClientModel *model)
|
||||
{
|
||||
this->model = model;
|
||||
|
||||
// Keep up to date with client
|
||||
setBalance(model->getBalance());
|
||||
connect(model, SIGNAL(balanceChanged(qint64)), this, SLOT(setBalance(qint64)));
|
||||
|
||||
setNumConnections(model->getNumConnections());
|
||||
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
|
||||
|
||||
setNumTransactions(model->getNumTransactions());
|
||||
connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
|
||||
|
||||
setNumBlocks(model->getNumBlocks());
|
||||
connect(model, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
|
||||
|
||||
setAddress(model->getAddress());
|
||||
connect(model, SIGNAL(addressChanged(QString)), this, SLOT(setAddress(QString)));
|
||||
|
||||
// Report errors from network/worker thread
|
||||
connect(model, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
|
||||
|
||||
// Put transaction list in tabs
|
||||
setTabsModel(model->getTransactionTableModel());
|
||||
}
|
||||
|
||||
void BitcoinGUI::createTrayIcon()
|
||||
{
|
||||
QMenu *trayIconMenu = new QMenu(this);
|
||||
trayIconMenu->addAction(openBitcoin);
|
||||
trayIconMenu->addAction(sendcoins);
|
||||
trayIconMenu->addAction(options);
|
||||
trayIconMenu->addSeparator();
|
||||
trayIconMenu->addAction(quit);
|
||||
|
||||
trayIcon = new QSystemTrayIcon(this);
|
||||
trayIcon->setContextMenu(trayIconMenu);
|
||||
trayIcon->setIcon(QIcon(":/icons/toolbar"));
|
||||
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
||||
this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
|
||||
trayIcon->show();
|
||||
}
|
||||
|
||||
void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
{
|
||||
if(reason == QSystemTrayIcon::DoubleClick)
|
||||
{
|
||||
// Doubleclick on system tray icon triggers "open bitcoin"
|
||||
openBitcoin->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
QWidget *BitcoinGUI::createTabs()
|
||||
{
|
||||
QStringList tab_labels;
|
||||
tab_labels << tr("All transactions")
|
||||
<< tr("Sent/Received")
|
||||
<< tr("Sent")
|
||||
<< tr("Received");
|
||||
|
||||
QTabWidget *tabs = new QTabWidget(this);
|
||||
for(int i = 0; i < tab_labels.size(); ++i)
|
||||
{
|
||||
QTableView *view = new QTableView(this);
|
||||
tabs->addTab(view, tab_labels.at(i));
|
||||
|
||||
connect(view, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(transactionDetails(const QModelIndex&)));
|
||||
transactionViews.append(view);
|
||||
}
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
void BitcoinGUI::setTabsModel(QAbstractItemModel *transaction_model)
|
||||
{
|
||||
QStringList tab_filters;
|
||||
tab_filters << "^."
|
||||
<< "^["+TransactionTableModel::Sent+TransactionTableModel::Received+"]"
|
||||
<< "^["+TransactionTableModel::Sent+"]"
|
||||
<< "^["+TransactionTableModel::Received+"]";
|
||||
|
||||
for(int i = 0; i < transactionViews.size(); ++i)
|
||||
{
|
||||
QSortFilterProxyModel *proxy_model = new QSortFilterProxyModel(this);
|
||||
proxy_model->setSourceModel(transaction_model);
|
||||
proxy_model->setDynamicSortFilter(true);
|
||||
proxy_model->setFilterRole(TransactionTableModel::TypeRole);
|
||||
proxy_model->setFilterRegExp(QRegExp(tab_filters.at(i)));
|
||||
proxy_model->setSortRole(Qt::EditRole);
|
||||
|
||||
QTableView *transaction_table = transactionViews.at(i);
|
||||
transaction_table->setModel(proxy_model);
|
||||
transaction_table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
transaction_table->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
transaction_table->setSortingEnabled(true);
|
||||
transaction_table->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
|
||||
transaction_table->verticalHeader()->hide();
|
||||
|
||||
transaction_table->horizontalHeader()->resizeSection(
|
||||
TransactionTableModel::Status, 120);
|
||||
transaction_table->horizontalHeader()->resizeSection(
|
||||
TransactionTableModel::Date, 120);
|
||||
transaction_table->horizontalHeader()->setResizeMode(
|
||||
TransactionTableModel::Description, QHeaderView::Stretch);
|
||||
transaction_table->horizontalHeader()->resizeSection(
|
||||
TransactionTableModel::Debit, 79);
|
||||
transaction_table->horizontalHeader()->resizeSection(
|
||||
TransactionTableModel::Credit, 79);
|
||||
}
|
||||
|
||||
connect(transaction_model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(incomingTransaction(const QModelIndex &, int, int)));
|
||||
}
|
||||
|
||||
void BitcoinGUI::sendcoinsClicked()
|
||||
{
|
||||
SendCoinsDialog dlg;
|
||||
dlg.setModel(model);
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void BitcoinGUI::addressbookClicked()
|
||||
{
|
||||
AddressBookDialog dlg;
|
||||
dlg.setModel(model->getAddressTableModel());
|
||||
dlg.setTab(AddressBookDialog::SendingTab);
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void BitcoinGUI::receivingAddressesClicked()
|
||||
{
|
||||
AddressBookDialog dlg;
|
||||
dlg.setModel(model->getAddressTableModel());
|
||||
dlg.setTab(AddressBookDialog::ReceivingTab);
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void BitcoinGUI::optionsClicked()
|
||||
{
|
||||
OptionsDialog dlg;
|
||||
dlg.setModel(model->getOptionsModel());
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void BitcoinGUI::aboutClicked()
|
||||
{
|
||||
AboutDialog dlg;
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void BitcoinGUI::newAddressClicked()
|
||||
{
|
||||
EditAddressDialog dlg(EditAddressDialog::NewReceivingAddress);
|
||||
dlg.setModel(model->getAddressTableModel());
|
||||
if(dlg.exec())
|
||||
{
|
||||
QString newAddress = dlg.saveCurrentRow();
|
||||
// Set returned address as new default addres
|
||||
if(!newAddress.isEmpty())
|
||||
{
|
||||
model->setAddress(newAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BitcoinGUI::copyClipboardClicked()
|
||||
{
|
||||
// Copy text in address to clipboard
|
||||
QApplication::clipboard()->setText(address->text());
|
||||
}
|
||||
|
||||
void BitcoinGUI::setBalance(qint64 balance)
|
||||
{
|
||||
labelBalance->setText(QString::fromStdString(FormatMoney(balance)));
|
||||
}
|
||||
|
||||
void BitcoinGUI::setAddress(const QString &addr)
|
||||
{
|
||||
address->setText(addr);
|
||||
}
|
||||
|
||||
void BitcoinGUI::setNumConnections(int count)
|
||||
{
|
||||
labelConnections->setText(QLocale::system().toString(count)+" "+tr("connections(s)", "", count));
|
||||
}
|
||||
|
||||
void BitcoinGUI::setNumBlocks(int count)
|
||||
{
|
||||
labelBlocks->setText(QLocale::system().toString(count)+" "+tr("block(s)", "", count));
|
||||
}
|
||||
|
||||
void BitcoinGUI::setNumTransactions(int count)
|
||||
{
|
||||
labelTransactions->setText(QLocale::system().toString(count)+" "+tr("transaction(s)", "", count));
|
||||
}
|
||||
|
||||
void BitcoinGUI::error(const QString &title, const QString &message)
|
||||
{
|
||||
// Report errors from network/worker thread
|
||||
if(trayIcon->supportsMessages())
|
||||
{
|
||||
// Show as "balloon" message if possible
|
||||
trayIcon->showMessage(title, message, QSystemTrayIcon::Critical);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fall back to old fashioned popup dialog if not
|
||||
QMessageBox::critical(this, title,
|
||||
message,
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
|
||||
void BitcoinGUI::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::WindowStateChange)
|
||||
{
|
||||
if(model->getOptionsModel()->getMinimizeToTray())
|
||||
{
|
||||
if (isMinimized())
|
||||
{
|
||||
hide();
|
||||
e->ignore();
|
||||
}
|
||||
else
|
||||
{
|
||||
e->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
QMainWindow::changeEvent(e);
|
||||
}
|
||||
|
||||
void BitcoinGUI::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if(!model->getOptionsModel()->getMinimizeToTray() &&
|
||||
!model->getOptionsModel()->getMinimizeOnClose())
|
||||
{
|
||||
qApp->quit();
|
||||
}
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
|
||||
{
|
||||
QString strMessage =
|
||||
tr("This transaction is over the size limit. You can still send it for a fee of %1, "
|
||||
"which goes to the nodes that process your transaction and helps to support the network. "
|
||||
"Do you want to pay the fee?").arg(QString::fromStdString(FormatMoney(nFeeRequired)));
|
||||
QMessageBox::StandardButton retval = QMessageBox::question(
|
||||
this, tr("Sending..."), strMessage,
|
||||
QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
|
||||
*payFee = (retval == QMessageBox::Yes);
|
||||
}
|
||||
|
||||
void BitcoinGUI::transactionDetails(const QModelIndex& idx)
|
||||
{
|
||||
/* A transaction is doubleclicked */
|
||||
TransactionDescDialog dlg(idx);
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end)
|
||||
{
|
||||
TransactionTableModel *ttm = model->getTransactionTableModel();
|
||||
qint64 credit = ttm->index(start, TransactionTableModel::Credit, parent)
|
||||
.data(Qt::EditRole).toULongLong();
|
||||
qint64 debit = ttm->index(start, TransactionTableModel::Debit, parent)
|
||||
.data(Qt::EditRole).toULongLong();
|
||||
if((credit+debit)>0)
|
||||
{
|
||||
/* On incoming transaction, make an info balloon */
|
||||
QString date = ttm->index(start, TransactionTableModel::Date, parent)
|
||||
.data().toString();
|
||||
QString description = ttm->index(start, TransactionTableModel::Description, parent)
|
||||
.data().toString();
|
||||
|
||||
trayIcon->showMessage(tr("Incoming transaction"),
|
||||
"Date: " + date + "\n" +
|
||||
"Amount: " + QString::fromStdString(FormatMoney(credit+debit, true)) + "\n" +
|
||||
description,
|
||||
QSystemTrayIcon::Information);
|
||||
}
|
||||
}
|
||||
88
src/qt/bitcoingui.h
Normal file
88
src/qt/bitcoingui.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef BITCOINGUI_H
|
||||
#define BITCOINGUI_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
class TransactionTableModel;
|
||||
class ClientModel;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QTableView;
|
||||
class QAbstractItemModel;
|
||||
class QModelIndex;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class BitcoinGUI : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BitcoinGUI(QWidget *parent = 0);
|
||||
void setModel(ClientModel *model);
|
||||
|
||||
/* Transaction table tab indices */
|
||||
enum {
|
||||
AllTransactions = 0,
|
||||
SentReceived = 1,
|
||||
Sent = 2,
|
||||
Received = 3
|
||||
} TabIndex;
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e);
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
private:
|
||||
ClientModel *model;
|
||||
|
||||
QLineEdit *address;
|
||||
QLabel *labelBalance;
|
||||
QLabel *labelConnections;
|
||||
QLabel *labelBlocks;
|
||||
QLabel *labelTransactions;
|
||||
|
||||
QAction *quit;
|
||||
QAction *sendcoins;
|
||||
QAction *addressbook;
|
||||
QAction *about;
|
||||
QAction *receivingAddresses;
|
||||
QAction *options;
|
||||
QAction *openBitcoin;
|
||||
|
||||
QSystemTrayIcon *trayIcon;
|
||||
QList<QTableView *> transactionViews;
|
||||
|
||||
void createActions();
|
||||
QWidget *createTabs();
|
||||
void createTrayIcon();
|
||||
void setTabsModel(QAbstractItemModel *transaction_model);
|
||||
|
||||
public slots:
|
||||
void setBalance(qint64 balance);
|
||||
void setAddress(const QString &address);
|
||||
void setNumConnections(int count);
|
||||
void setNumBlocks(int count);
|
||||
void setNumTransactions(int count);
|
||||
void error(const QString &title, const QString &message);
|
||||
/* It is currently not possible to pass a return value to another thread through
|
||||
BlockingQueuedConnection, so use an indirected pointer.
|
||||
http://bugreports.qt.nokia.com/browse/QTBUG-10440
|
||||
*/
|
||||
void askFee(qint64 nFeeRequired, bool *payFee);
|
||||
|
||||
private slots:
|
||||
void sendcoinsClicked();
|
||||
void addressbookClicked();
|
||||
void optionsClicked();
|
||||
void receivingAddressesClicked();
|
||||
void aboutClicked();
|
||||
void newAddressClicked();
|
||||
void copyClipboardClicked();
|
||||
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||
void transactionDetails(const QModelIndex& idx);
|
||||
void incomingTransaction(const QModelIndex & parent, int start, int end);
|
||||
};
|
||||
|
||||
#endif
|
||||
156
src/qt/clientmodel.cpp
Normal file
156
src/qt/clientmodel.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "clientmodel.h"
|
||||
#include "main.h"
|
||||
#include "guiconstants.h"
|
||||
#include "optionsmodel.h"
|
||||
#include "addresstablemodel.h"
|
||||
#include "transactiontablemodel.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
ClientModel::ClientModel(QObject *parent) :
|
||||
QObject(parent), optionsModel(0), addressTableModel(0),
|
||||
transactionTableModel(0)
|
||||
{
|
||||
/* Until signal notifications is built into the bitcoin core,
|
||||
simply update everything after polling using a timer.
|
||||
*/
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
timer->start(MODEL_UPDATE_DELAY);
|
||||
|
||||
optionsModel = new OptionsModel(this);
|
||||
addressTableModel = new AddressTableModel(this);
|
||||
transactionTableModel = new TransactionTableModel(this);
|
||||
}
|
||||
|
||||
qint64 ClientModel::getBalance()
|
||||
{
|
||||
return GetBalance();
|
||||
}
|
||||
|
||||
QString ClientModel::getAddress()
|
||||
{
|
||||
std::vector<unsigned char> vchPubKey;
|
||||
if (CWalletDB("r").ReadDefaultKey(vchPubKey))
|
||||
{
|
||||
return QString::fromStdString(PubKeyToAddress(vchPubKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
int ClientModel::getNumConnections()
|
||||
{
|
||||
return vNodes.size();
|
||||
}
|
||||
|
||||
int ClientModel::getNumBlocks()
|
||||
{
|
||||
return nBestHeight;
|
||||
}
|
||||
|
||||
int ClientModel::getNumTransactions()
|
||||
{
|
||||
int numTransactions = 0;
|
||||
CRITICAL_BLOCK(cs_mapWallet)
|
||||
{
|
||||
numTransactions = mapWallet.size();
|
||||
}
|
||||
return numTransactions;
|
||||
}
|
||||
|
||||
void ClientModel::update()
|
||||
{
|
||||
/* Plainly emit all signals for now. To be precise this should check
|
||||
wether the values actually changed first.
|
||||
*/
|
||||
emit balanceChanged(getBalance());
|
||||
emit addressChanged(getAddress());
|
||||
emit numConnectionsChanged(getNumConnections());
|
||||
emit numBlocksChanged(getNumBlocks());
|
||||
emit numTransactionsChanged(getNumTransactions());
|
||||
}
|
||||
|
||||
void ClientModel::setAddress(const QString &defaultAddress)
|
||||
{
|
||||
uint160 hash160;
|
||||
std::string strAddress = defaultAddress.toStdString();
|
||||
if (!AddressToHash160(strAddress, hash160))
|
||||
return;
|
||||
if (!mapPubKeys.count(hash160))
|
||||
return;
|
||||
CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
|
||||
}
|
||||
|
||||
ClientModel::StatusCode ClientModel::sendCoins(const QString &payTo, qint64 payAmount)
|
||||
{
|
||||
uint160 hash160 = 0;
|
||||
bool valid = false;
|
||||
|
||||
if(!AddressToHash160(payTo.toUtf8().constData(), hash160))
|
||||
{
|
||||
return InvalidAddress;
|
||||
}
|
||||
|
||||
if(payAmount <= 0)
|
||||
{
|
||||
return InvalidAmount;
|
||||
}
|
||||
|
||||
if(payAmount > getBalance())
|
||||
{
|
||||
return AmountExceedsBalance;
|
||||
}
|
||||
|
||||
if((payAmount + nTransactionFee) > getBalance())
|
||||
{
|
||||
return AmountWithFeeExceedsBalance;
|
||||
}
|
||||
|
||||
CRITICAL_BLOCK(cs_main)
|
||||
{
|
||||
// Send to bitcoin address
|
||||
CWalletTx wtx;
|
||||
CScript scriptPubKey;
|
||||
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
|
||||
std::string strError = SendMoney(scriptPubKey, payAmount, wtx, true);
|
||||
if (strError == "")
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
else if (strError == "ABORTED")
|
||||
{
|
||||
return Aborted;
|
||||
}
|
||||
else
|
||||
{
|
||||
emit error(tr("Sending..."), QString::fromStdString(strError));
|
||||
return MiscError;
|
||||
}
|
||||
}
|
||||
// Add addresses that we've sent to to the address book
|
||||
std::string strAddress = payTo.toStdString();
|
||||
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||
if (!mapAddressBook.count(strAddress))
|
||||
SetAddressBookName(strAddress, "");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
OptionsModel *ClientModel::getOptionsModel()
|
||||
{
|
||||
return optionsModel;
|
||||
}
|
||||
|
||||
AddressTableModel *ClientModel::getAddressTableModel()
|
||||
{
|
||||
return addressTableModel;
|
||||
}
|
||||
|
||||
TransactionTableModel *ClientModel::getTransactionTableModel()
|
||||
{
|
||||
return transactionTableModel;
|
||||
}
|
||||
61
src/qt/clientmodel.h
Normal file
61
src/qt/clientmodel.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef CLIENTMODEL_H
|
||||
#define CLIENTMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class OptionsModel;
|
||||
class AddressTableModel;
|
||||
class TransactionTableModel;
|
||||
|
||||
class ClientModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClientModel(QObject *parent = 0);
|
||||
|
||||
enum StatusCode
|
||||
{
|
||||
OK,
|
||||
InvalidAmount,
|
||||
InvalidAddress,
|
||||
AmountExceedsBalance,
|
||||
AmountWithFeeExceedsBalance,
|
||||
Aborted,
|
||||
MiscError
|
||||
};
|
||||
|
||||
OptionsModel *getOptionsModel();
|
||||
AddressTableModel *getAddressTableModel();
|
||||
TransactionTableModel *getTransactionTableModel();
|
||||
|
||||
qint64 getBalance();
|
||||
QString getAddress();
|
||||
int getNumConnections();
|
||||
int getNumBlocks();
|
||||
int getNumTransactions();
|
||||
|
||||
/* Set default address */
|
||||
void setAddress(const QString &defaultAddress);
|
||||
/* Send coins */
|
||||
StatusCode sendCoins(const QString &payTo, qint64 payAmount);
|
||||
private:
|
||||
OptionsModel *optionsModel;
|
||||
AddressTableModel *addressTableModel;
|
||||
TransactionTableModel *transactionTableModel;
|
||||
|
||||
signals:
|
||||
void balanceChanged(qint64 balance);
|
||||
void addressChanged(const QString &address);
|
||||
void numConnectionsChanged(int count);
|
||||
void numBlocksChanged(int count);
|
||||
void numTransactionsChanged(int count);
|
||||
/* Asynchronous error notification */
|
||||
void error(const QString &title, const QString &message);
|
||||
|
||||
public slots:
|
||||
|
||||
private slots:
|
||||
void update();
|
||||
};
|
||||
|
||||
#endif // CLIENTMODEL_H
|
||||
84
src/qt/editaddressdialog.cpp
Normal file
84
src/qt/editaddressdialog.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "editaddressdialog.h"
|
||||
#include "ui_editaddressdialog.h"
|
||||
#include "addresstablemodel.h"
|
||||
#include "guiutil.h"
|
||||
|
||||
#include <QDataWidgetMapper>
|
||||
#include <QMessageBox>
|
||||
|
||||
EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::EditAddressDialog), mapper(0), mode(mode), model(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
GUIUtil::setupAddressWidget(ui->addressEdit, this);
|
||||
|
||||
switch(mode)
|
||||
{
|
||||
case NewReceivingAddress:
|
||||
setWindowTitle(tr("New receiving address"));
|
||||
ui->addressEdit->setEnabled(false);
|
||||
break;
|
||||
case NewSendingAddress:
|
||||
setWindowTitle(tr("New sending address"));
|
||||
break;
|
||||
case EditReceivingAddress:
|
||||
setWindowTitle(tr("Edit receiving address"));
|
||||
ui->addressEdit->setReadOnly(true);
|
||||
break;
|
||||
case EditSendingAddress:
|
||||
setWindowTitle(tr("Edit sending address"));
|
||||
break;
|
||||
}
|
||||
|
||||
mapper = new QDataWidgetMapper(this);
|
||||
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
|
||||
}
|
||||
|
||||
EditAddressDialog::~EditAddressDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void EditAddressDialog::setModel(AddressTableModel *model)
|
||||
{
|
||||
this->model = model;
|
||||
mapper->setModel(model);
|
||||
mapper->addMapping(ui->labelEdit, AddressTableModel::Label);
|
||||
mapper->addMapping(ui->addressEdit, AddressTableModel::Address);
|
||||
}
|
||||
|
||||
void EditAddressDialog::loadRow(int row)
|
||||
{
|
||||
mapper->setCurrentIndex(row);
|
||||
}
|
||||
|
||||
QString EditAddressDialog::saveCurrentRow()
|
||||
{
|
||||
QString address;
|
||||
switch(mode)
|
||||
{
|
||||
case NewReceivingAddress:
|
||||
case NewSendingAddress:
|
||||
address = model->addRow(
|
||||
mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive,
|
||||
ui->labelEdit->text(),
|
||||
ui->addressEdit->text());
|
||||
if(address.isEmpty())
|
||||
{
|
||||
QMessageBox::warning(this, windowTitle(),
|
||||
tr("The address %1 is already in the address book.").arg(ui->addressEdit->text()),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
}
|
||||
break;
|
||||
case EditReceivingAddress:
|
||||
case EditSendingAddress:
|
||||
if(mapper->submit())
|
||||
{
|
||||
address = ui->addressEdit->text();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
41
src/qt/editaddressdialog.h
Normal file
41
src/qt/editaddressdialog.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef EDITADDRESSDIALOG_H
|
||||
#define EDITADDRESSDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDataWidgetMapper;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Ui {
|
||||
class EditAddressDialog;
|
||||
}
|
||||
class AddressTableModel;
|
||||
|
||||
class EditAddressDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
NewReceivingAddress,
|
||||
NewSendingAddress,
|
||||
EditReceivingAddress,
|
||||
EditSendingAddress
|
||||
};
|
||||
|
||||
explicit EditAddressDialog(Mode mode, QWidget *parent = 0);
|
||||
~EditAddressDialog();
|
||||
|
||||
void setModel(AddressTableModel *model);
|
||||
void loadRow(int row);
|
||||
QString saveCurrentRow();
|
||||
|
||||
private:
|
||||
Ui::EditAddressDialog *ui;
|
||||
QDataWidgetMapper *mapper;
|
||||
Mode mode;
|
||||
AddressTableModel *model;
|
||||
};
|
||||
|
||||
#endif // EDITADDRESSDIALOG_H
|
||||
162
src/qt/forms/aboutdialog.ui
Normal file
162
src/qt/forms/aboutdialog.ui
Normal file
@@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AboutDialog</class>
|
||||
<widget class="QDialog" name="AboutDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>593</width>
|
||||
<height>319</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>About Bitcoin</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Ignored">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../bitcoin.qrc">:/images/about</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><b>Bitcoin</b> version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="versionLabel">
|
||||
<property name="text">
|
||||
<string>0.3.666-beta</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Copyright © 2009-2011 Bitcoin Developers
|
||||
|
||||
This is experimental software.
|
||||
|
||||
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) and UPnP software written by Thomas Bernard.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../bitcoin.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>AboutDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>360</x>
|
||||
<y>308</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>AboutDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>428</x>
|
||||
<y>308</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
196
src/qt/forms/addressbookdialog.ui
Normal file
196
src/qt/forms/addressbookdialog.ui
Normal file
@@ -0,0 +1,196 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AddressBookDialog</class>
|
||||
<widget class="QDialog" name="AddressBookDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>591</width>
|
||||
<height>347</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Address Book</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="sendTab">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Sending</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTableView" name="sendTableView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="receiveTab">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Receiving</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>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.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="receiveTableView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="newAddressButton">
|
||||
<property name="toolTip">
|
||||
<string>Create a new address</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&New Address...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="copyToClipboard">
|
||||
<property name="toolTip">
|
||||
<string>Copy the currently selected address to the system clipboard</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Copy to Clipboard</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="editButton">
|
||||
<property name="toolTip">
|
||||
<string>Edit the currently selected address</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Edit...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteButton">
|
||||
<property name="toolTip">
|
||||
<string>Delete the currently selected address from the list</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>receiveTableView</sender>
|
||||
<signal>doubleClicked(QModelIndex)</signal>
|
||||
<receiver>editButton</receiver>
|
||||
<slot>click()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>334</x>
|
||||
<y>249</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>333</x>
|
||||
<y>326</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>sendTableView</sender>
|
||||
<signal>doubleClicked(QModelIndex)</signal>
|
||||
<receiver>editButton</receiver>
|
||||
<slot>click()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>329</x>
|
||||
<y>261</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>332</x>
|
||||
<y>326</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
105
src/qt/forms/editaddressdialog.ui
Normal file
105
src/qt/forms/editaddressdialog.ui
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditAddressDialog</class>
|
||||
<widget class="QDialog" name="EditAddressDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>458</width>
|
||||
<height>113</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Address</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>&Label</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>labelEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>&Address</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>addressEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="labelEdit">
|
||||
<property name="toolTip">
|
||||
<string>The label associated with this address book entry</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="addressEdit">
|
||||
<property name="toolTip">
|
||||
<string>The address associated with this address book entry. This can only be modified for sending addresses.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>EditAddressDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>EditAddressDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
180
src/qt/forms/sendcoinsdialog.ui
Normal file
180
src/qt/forms/sendcoinsdialog.ui
Normal file
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SendCoinsDialog</class>
|
||||
<widget class="QDialog" name="SendCoinsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>736</width>
|
||||
<height>149</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Send Coins</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>&Amount:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>payAmount</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Pay &To:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>payTo</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="payTo">
|
||||
<property name="toolTip">
|
||||
<string>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>34</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="payAmount">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>145</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Amount of bitcoins to send (e.g. 0.05)</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="pasteButton">
|
||||
<property name="toolTip">
|
||||
<string>Paste address from system clipboard</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Paste</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QPushButton" name="addressBookButton">
|
||||
<property name="toolTip">
|
||||
<string>Look up adress in address book</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Address &Book...</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="sendButton">
|
||||
<property name="toolTip">
|
||||
<string>Confirm the send action</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Send</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../bitcoin.qrc">
|
||||
<normaloff>:/icons/send</normaloff>:/icons/send</iconset>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Abort the send action</string>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../bitcoin.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
71
src/qt/forms/transactiondescdialog.ui
Normal file
71
src/qt/forms/transactiondescdialog.ui
Normal file
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TransactionDescDialog</class>
|
||||
<widget class="QDialog" name="TransactionDescDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Transaction details</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="detailText">
|
||||
<property name="toolTip">
|
||||
<string>This pane shows a detailed description of the transaction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>TransactionDescDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>TransactionDescDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
11
src/qt/guiconstants.h
Normal file
11
src/qt/guiconstants.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef GUICONSTANTS_H
|
||||
#define GUICONSTANTS_H
|
||||
|
||||
/* milliseconds between model updates */
|
||||
static const int MODEL_UPDATE_DELAY = 250;
|
||||
|
||||
/* size of cache */
|
||||
static const unsigned int WALLET_CACHE_SIZE = 100;
|
||||
|
||||
|
||||
#endif // GUICONSTANTS_H
|
||||
38
src/qt/guiutil.cpp
Normal file
38
src/qt/guiutil.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "guiutil.h"
|
||||
#include "bitcoinaddressvalidator.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#include <QDoubleValidator>
|
||||
#include <QFont>
|
||||
#include <QLineEdit>
|
||||
|
||||
QString GUIUtil::DateTimeStr(qint64 nTime)
|
||||
{
|
||||
QDateTime date = QDateTime::fromMSecsSinceEpoch(nTime*1000);
|
||||
return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
|
||||
}
|
||||
|
||||
QFont GUIUtil::bitcoinAddressFont()
|
||||
{
|
||||
QFont font("Monospace");
|
||||
font.setStyleHint(QFont::TypeWriter);
|
||||
return font;
|
||||
}
|
||||
|
||||
void GUIUtil::setupAddressWidget(QLineEdit *widget, QWidget *parent)
|
||||
{
|
||||
widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
|
||||
widget->setValidator(new BitcoinAddressValidator(parent));
|
||||
widget->setFont(bitcoinAddressFont());
|
||||
}
|
||||
|
||||
void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent)
|
||||
{
|
||||
QDoubleValidator *amountValidator = new QDoubleValidator(parent);
|
||||
amountValidator->setDecimals(8);
|
||||
amountValidator->setBottom(0.0);
|
||||
widget->setValidator(amountValidator);
|
||||
widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
||||
}
|
||||
|
||||
25
src/qt/guiutil.h
Normal file
25
src/qt/guiutil.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef GUIUTIL_H
|
||||
#define GUIUTIL_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QFont;
|
||||
class QLineEdit;
|
||||
class QWidget;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class GUIUtil
|
||||
{
|
||||
public:
|
||||
static QString DateTimeStr(qint64 nTime);
|
||||
|
||||
/* Render bitcoin addresses in monospace font */
|
||||
static QFont bitcoinAddressFont();
|
||||
|
||||
static void setupAddressWidget(QLineEdit *widget, QWidget *parent);
|
||||
|
||||
static void setupAmountWidget(QLineEdit *widget, QWidget *parent);
|
||||
};
|
||||
|
||||
#endif // GUIUTIL_H
|
||||
39
src/qt/monitoreddatamapper.cpp
Normal file
39
src/qt/monitoreddatamapper.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "monitoreddatamapper.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaProperty>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
MonitoredDataMapper::MonitoredDataMapper(QObject *parent) :
|
||||
QDataWidgetMapper(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void MonitoredDataMapper::addMapping(QWidget *widget, int section)
|
||||
{
|
||||
QDataWidgetMapper::addMapping(widget, section);
|
||||
addChangeMonitor(widget);
|
||||
}
|
||||
|
||||
void MonitoredDataMapper::addMapping(QWidget *widget, int section, const QByteArray &propertyName)
|
||||
{
|
||||
QDataWidgetMapper::addMapping(widget, section, propertyName);
|
||||
addChangeMonitor(widget);
|
||||
}
|
||||
|
||||
void MonitoredDataMapper::addChangeMonitor(QWidget *widget)
|
||||
{
|
||||
/* Watch user property of widget for changes, and connect
|
||||
the signal to our viewModified signal.
|
||||
*/
|
||||
QMetaProperty prop = widget->metaObject()->userProperty();
|
||||
int signal = prop.notifySignalIndex();
|
||||
int method = this->metaObject()->indexOfMethod("viewModified()");
|
||||
if(signal != -1 && method != -1)
|
||||
{
|
||||
QMetaObject::connect(widget, signal, this, method);
|
||||
}
|
||||
}
|
||||
32
src/qt/monitoreddatamapper.h
Normal file
32
src/qt/monitoreddatamapper.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef MONITOREDDATAMAPPER_H
|
||||
#define MONITOREDDATAMAPPER_H
|
||||
|
||||
#include <QDataWidgetMapper>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWidget;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
/* Data <-> Widget mapper that watches for changes,
|
||||
to be able to notify when 'dirty' (for example, to
|
||||
enable a commit/apply button).
|
||||
*/
|
||||
class MonitoredDataMapper : public QDataWidgetMapper
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MonitoredDataMapper(QObject *parent=0);
|
||||
|
||||
void addMapping(QWidget *widget, int section);
|
||||
void addMapping(QWidget *widget, int section, const QByteArray &propertyName);
|
||||
private:
|
||||
void addChangeMonitor(QWidget *widget);
|
||||
|
||||
signals:
|
||||
void viewModified();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // MONITOREDDATAMAPPER_H
|
||||
234
src/qt/optionsdialog.cpp
Normal file
234
src/qt/optionsdialog.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
#include "optionsdialog.h"
|
||||
#include "optionsmodel.h"
|
||||
#include "monitoreddatamapper.h"
|
||||
#include "guiutil.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QListWidget>
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QIntValidator>
|
||||
#include <QDoubleValidator>
|
||||
#include <QRegExpValidator>
|
||||
|
||||
/* First (currently only) page of options */
|
||||
class MainOptionsPage : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit MainOptionsPage(QWidget *parent=0);
|
||||
|
||||
void setMapper(MonitoredDataMapper *mapper);
|
||||
private:
|
||||
QCheckBox *bitcoin_at_startup;
|
||||
QCheckBox *minimize_to_tray;
|
||||
QCheckBox *map_port_upnp;
|
||||
QCheckBox *minimize_on_close;
|
||||
QCheckBox *connect_socks4;
|
||||
QLineEdit *proxy_ip;
|
||||
QLineEdit *proxy_port;
|
||||
QLineEdit *fee_edit;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
OptionsDialog::OptionsDialog(QWidget *parent):
|
||||
QDialog(parent), contents_widget(0), pages_widget(0),
|
||||
main_options_page(0), model(0)
|
||||
{
|
||||
contents_widget = new QListWidget();
|
||||
contents_widget->setMaximumWidth(128);
|
||||
|
||||
pages_widget = new QStackedWidget();
|
||||
pages_widget->setMinimumWidth(300);
|
||||
|
||||
QListWidgetItem *item_main = new QListWidgetItem(tr("Main"));
|
||||
contents_widget->addItem(item_main);
|
||||
main_options_page = new MainOptionsPage(this);
|
||||
pages_widget->addWidget(main_options_page);
|
||||
|
||||
contents_widget->setCurrentRow(0);
|
||||
|
||||
QHBoxLayout *main_layout = new QHBoxLayout();
|
||||
main_layout->addWidget(contents_widget);
|
||||
main_layout->addWidget(pages_widget, 1);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout();
|
||||
layout->addLayout(main_layout);
|
||||
|
||||
QHBoxLayout *buttons = new QHBoxLayout();
|
||||
buttons->addStretch(1);
|
||||
QPushButton *ok_button = new QPushButton(tr("OK"));
|
||||
buttons->addWidget(ok_button);
|
||||
QPushButton *cancel_button = new QPushButton(tr("Cancel"));
|
||||
buttons->addWidget(cancel_button);
|
||||
apply_button = new QPushButton(tr("Apply"));
|
||||
apply_button->setEnabled(false);
|
||||
buttons->addWidget(apply_button);
|
||||
|
||||
layout->addLayout(buttons);
|
||||
|
||||
setLayout(layout);
|
||||
setWindowTitle(tr("Options"));
|
||||
|
||||
/* Widget-to-option mapper */
|
||||
mapper = new MonitoredDataMapper(this);
|
||||
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
|
||||
mapper->setOrientation(Qt::Vertical);
|
||||
/* enable apply button when data modified */
|
||||
connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApply()));
|
||||
/* disable apply button when new data loaded */
|
||||
connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApply()));
|
||||
|
||||
/* Event bindings */
|
||||
connect(ok_button, SIGNAL(clicked()), this, SLOT(okClicked()));
|
||||
connect(cancel_button, SIGNAL(clicked()), this, SLOT(cancelClicked()));
|
||||
connect(apply_button, SIGNAL(clicked()), this, SLOT(applyClicked()));
|
||||
}
|
||||
|
||||
void OptionsDialog::setModel(OptionsModel *model)
|
||||
{
|
||||
this->model = model;
|
||||
|
||||
mapper->setModel(model);
|
||||
main_options_page->setMapper(mapper);
|
||||
|
||||
mapper->toFirst();
|
||||
}
|
||||
|
||||
void OptionsDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
|
||||
{
|
||||
Q_UNUSED(previous);
|
||||
if(current)
|
||||
{
|
||||
pages_widget->setCurrentIndex(contents_widget->row(current));
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDialog::okClicked()
|
||||
{
|
||||
mapper->submit();
|
||||
accept();
|
||||
}
|
||||
|
||||
void OptionsDialog::cancelClicked()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
|
||||
void OptionsDialog::applyClicked()
|
||||
{
|
||||
mapper->submit();
|
||||
apply_button->setEnabled(false);
|
||||
}
|
||||
|
||||
void OptionsDialog::enableApply()
|
||||
{
|
||||
apply_button->setEnabled(true);
|
||||
}
|
||||
|
||||
void OptionsDialog::disableApply()
|
||||
{
|
||||
apply_button->setEnabled(false);
|
||||
}
|
||||
|
||||
MainOptionsPage::MainOptionsPage(QWidget *parent):
|
||||
QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout();
|
||||
|
||||
bitcoin_at_startup = new QCheckBox(tr("&Start Bitcoin on window system startup"));
|
||||
bitcoin_at_startup->setToolTip(tr("Automatically start Bitcoin after the computer is turned on"));
|
||||
layout->addWidget(bitcoin_at_startup);
|
||||
|
||||
minimize_to_tray = new QCheckBox(tr("&Minimize to the tray instead of the taskbar"));
|
||||
minimize_to_tray->setToolTip(tr("Show only a tray icon after minimizing the window"));
|
||||
layout->addWidget(minimize_to_tray);
|
||||
|
||||
map_port_upnp = new QCheckBox(tr("Map port using &UPnP"));
|
||||
map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled."));
|
||||
layout->addWidget(map_port_upnp);
|
||||
|
||||
minimize_on_close = new QCheckBox(tr("M&inimize on close"));
|
||||
minimize_on_close->setToolTip(tr("Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu."));
|
||||
layout->addWidget(minimize_on_close);
|
||||
|
||||
connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:"));
|
||||
connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)"));
|
||||
layout->addWidget(connect_socks4);
|
||||
|
||||
QHBoxLayout *proxy_hbox = new QHBoxLayout();
|
||||
proxy_hbox->addSpacing(18);
|
||||
QLabel *proxy_ip_label = new QLabel(tr("Proxy &IP: "));
|
||||
proxy_hbox->addWidget(proxy_ip_label);
|
||||
proxy_ip = new QLineEdit();
|
||||
proxy_ip->setMaximumWidth(140);
|
||||
proxy_ip->setEnabled(false);
|
||||
proxy_ip->setValidator(new QRegExpValidator(QRegExp("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"), this));
|
||||
proxy_ip->setToolTip(tr("IP address of the proxy (e.g. 127.0.0.1)"));
|
||||
proxy_ip_label->setBuddy(proxy_ip);
|
||||
proxy_hbox->addWidget(proxy_ip);
|
||||
QLabel *proxy_port_label = new QLabel(tr("&Port: "));
|
||||
proxy_hbox->addWidget(proxy_port_label);
|
||||
proxy_port = new QLineEdit();
|
||||
proxy_port->setMaximumWidth(55);
|
||||
proxy_port->setValidator(new QIntValidator(0, 65535, this));
|
||||
proxy_port->setEnabled(false);
|
||||
proxy_port->setToolTip(tr("Port of the proxy (e.g. 1234)"));
|
||||
proxy_port_label->setBuddy(proxy_port);
|
||||
proxy_hbox->addWidget(proxy_port);
|
||||
proxy_hbox->addStretch(1);
|
||||
|
||||
layout->addLayout(proxy_hbox);
|
||||
QLabel *fee_help = new QLabel(tr("Optional transaction fee per KB that helps make sure your transactions are processed quickly. Most transactions are 1KB. Fee 0.01 recommended."));
|
||||
fee_help->setWordWrap(true);
|
||||
layout->addWidget(fee_help);
|
||||
|
||||
QHBoxLayout *fee_hbox = new QHBoxLayout();
|
||||
fee_hbox->addSpacing(18);
|
||||
QLabel *fee_label = new QLabel(tr("Pay transaction &fee"));
|
||||
fee_hbox->addWidget(fee_label);
|
||||
fee_edit = new QLineEdit();
|
||||
fee_edit->setMaximumWidth(100);
|
||||
fee_edit->setToolTip(tr("Optional transaction fee per KB that helps make sure your transactions are processed quickly. Most transactions are 1KB. Fee 0.01 recommended."));
|
||||
|
||||
GUIUtil::setupAmountWidget(fee_edit, this);
|
||||
|
||||
fee_label->setBuddy(fee_edit);
|
||||
fee_hbox->addWidget(fee_edit);
|
||||
fee_hbox->addStretch(1);
|
||||
|
||||
layout->addLayout(fee_hbox);
|
||||
|
||||
layout->addStretch(1); /* Extra space at bottom */
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
connect(connect_socks4, SIGNAL(toggled(bool)), proxy_ip, SLOT(setEnabled(bool)));
|
||||
connect(connect_socks4, SIGNAL(toggled(bool)), proxy_port, SLOT(setEnabled(bool)));
|
||||
|
||||
#ifndef USE_UPNP
|
||||
map_port_upnp->setDisabled(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainOptionsPage::setMapper(MonitoredDataMapper *mapper)
|
||||
{
|
||||
/* Map model to widgets */
|
||||
mapper->addMapping(bitcoin_at_startup, OptionsModel::StartAtStartup);
|
||||
mapper->addMapping(minimize_to_tray, OptionsModel::MinimizeToTray);
|
||||
mapper->addMapping(map_port_upnp, OptionsModel::MapPortUPnP);
|
||||
mapper->addMapping(minimize_on_close, OptionsModel::MinimizeOnClose);
|
||||
mapper->addMapping(connect_socks4, OptionsModel::ConnectSOCKS4);
|
||||
mapper->addMapping(proxy_ip, OptionsModel::ProxyIP);
|
||||
mapper->addMapping(proxy_port, OptionsModel::ProxyPort);
|
||||
mapper->addMapping(fee_edit, OptionsModel::Fee);
|
||||
}
|
||||
|
||||
45
src/qt/optionsdialog.h
Normal file
45
src/qt/optionsdialog.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef OPTIONSDIALOG_H
|
||||
#define OPTIONSDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QStackedWidget;
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
class QPushButton;
|
||||
QT_END_NAMESPACE
|
||||
class OptionsModel;
|
||||
class MainOptionsPage;
|
||||
class MonitoredDataMapper;
|
||||
|
||||
class OptionsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OptionsDialog(QWidget *parent=0);
|
||||
|
||||
void setModel(OptionsModel *model);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void changePage(QListWidgetItem *current, QListWidgetItem *previous);
|
||||
private slots:
|
||||
void okClicked();
|
||||
void cancelClicked();
|
||||
void applyClicked();
|
||||
void enableApply();
|
||||
void disableApply();
|
||||
private:
|
||||
QListWidget *contents_widget;
|
||||
QStackedWidget *pages_widget;
|
||||
MainOptionsPage *main_options_page;
|
||||
OptionsModel *model;
|
||||
MonitoredDataMapper *mapper;
|
||||
QPushButton *apply_button;
|
||||
|
||||
void setupMainPage();
|
||||
};
|
||||
|
||||
#endif // OPTIONSDIALOG_H
|
||||
140
src/qt/optionsmodel.cpp
Normal file
140
src/qt/optionsmodel.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "optionsmodel.h"
|
||||
#include "main.h"
|
||||
#include "net.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
OptionsModel::OptionsModel(QObject *parent) :
|
||||
QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int OptionsModel::rowCount(const QModelIndex & parent) const
|
||||
{
|
||||
return OptionIDRowCount;
|
||||
}
|
||||
|
||||
QVariant OptionsModel::data(const QModelIndex & index, int role) const
|
||||
{
|
||||
if(role == Qt::EditRole)
|
||||
{
|
||||
switch(index.row())
|
||||
{
|
||||
case StartAtStartup:
|
||||
return QVariant();
|
||||
case MinimizeToTray:
|
||||
return QVariant(fMinimizeToTray);
|
||||
case MapPortUPnP:
|
||||
return QVariant(fUseUPnP);
|
||||
case MinimizeOnClose:
|
||||
return QVariant(fMinimizeOnClose);
|
||||
case ConnectSOCKS4:
|
||||
return QVariant(fUseProxy);
|
||||
case ProxyIP:
|
||||
return QVariant(QString::fromStdString(addrProxy.ToStringIP()));
|
||||
case ProxyPort:
|
||||
return QVariant(QString::fromStdString(addrProxy.ToStringPort()));
|
||||
case Fee:
|
||||
return QVariant(QString::fromStdString(FormatMoney(nTransactionFee)));
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
|
||||
{
|
||||
bool successful = true; /* set to false on parse error */
|
||||
if(role == Qt::EditRole)
|
||||
{
|
||||
CWalletDB walletdb;
|
||||
switch(index.row())
|
||||
{
|
||||
case StartAtStartup:
|
||||
successful = false; /*TODO*/
|
||||
break;
|
||||
case MinimizeToTray:
|
||||
fMinimizeToTray = value.toBool();
|
||||
walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
|
||||
break;
|
||||
case MapPortUPnP:
|
||||
fUseUPnP = value.toBool();
|
||||
walletdb.WriteSetting("fUseUPnP", fUseUPnP);
|
||||
#ifdef USE_UPNP
|
||||
MapPort(fUseUPnP);
|
||||
#endif
|
||||
break;
|
||||
case MinimizeOnClose:
|
||||
fMinimizeOnClose = value.toBool();
|
||||
walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
|
||||
break;
|
||||
case ConnectSOCKS4:
|
||||
fUseProxy = value.toBool();
|
||||
walletdb.WriteSetting("fUseProxy", fUseProxy);
|
||||
break;
|
||||
case ProxyIP:
|
||||
{
|
||||
/* Use CAddress to parse IP */
|
||||
CAddress addr(value.toString().toStdString() + ":1");
|
||||
if (addr.ip != INADDR_NONE)
|
||||
{
|
||||
addrProxy.ip = addr.ip;
|
||||
walletdb.WriteSetting("addrProxy", addrProxy);
|
||||
}
|
||||
else
|
||||
{
|
||||
successful = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ProxyPort:
|
||||
{
|
||||
int nPort = atoi(value.toString().toAscii().data());
|
||||
if (nPort > 0 && nPort < USHRT_MAX)
|
||||
{
|
||||
addrProxy.port = htons(nPort);
|
||||
walletdb.WriteSetting("addrProxy", addrProxy);
|
||||
}
|
||||
else
|
||||
{
|
||||
successful = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Fee: {
|
||||
int64 retval;
|
||||
if(ParseMoney(value.toString().toStdString(), retval))
|
||||
{
|
||||
nTransactionFee = retval;
|
||||
walletdb.WriteSetting("nTransactionFee", nTransactionFee);
|
||||
}
|
||||
else
|
||||
{
|
||||
successful = false; /* parse error */
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit dataChanged(index, index);
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
qint64 OptionsModel::getTransactionFee()
|
||||
{
|
||||
return nTransactionFee;
|
||||
}
|
||||
|
||||
bool OptionsModel::getMinimizeToTray()
|
||||
{
|
||||
return fMinimizeToTray;
|
||||
}
|
||||
|
||||
bool OptionsModel::getMinimizeOnClose()
|
||||
{
|
||||
return fMinimizeOnClose;
|
||||
}
|
||||
44
src/qt/optionsmodel.h
Normal file
44
src/qt/optionsmodel.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef OPTIONSMODEL_H
|
||||
#define OPTIONSMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
/* Interface from QT to configuration data structure for bitcoin client.
|
||||
To QT, the options are presented as a list with the different options
|
||||
laid out vertically.
|
||||
This can be changed to a tree once the settings become sufficiently
|
||||
complex.
|
||||
*/
|
||||
class OptionsModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OptionsModel(QObject *parent = 0);
|
||||
|
||||
enum OptionID {
|
||||
StartAtStartup,
|
||||
MinimizeToTray,
|
||||
MapPortUPnP,
|
||||
MinimizeOnClose,
|
||||
ConnectSOCKS4,
|
||||
ProxyIP,
|
||||
ProxyPort,
|
||||
Fee,
|
||||
OptionIDRowCount
|
||||
};
|
||||
|
||||
int rowCount(const QModelIndex & parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
|
||||
|
||||
/* Explicit getters */
|
||||
qint64 getTransactionFee();
|
||||
bool getMinimizeToTray();
|
||||
bool getMinimizeOnClose();
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
#endif // OPTIONSMODEL_H
|
||||
BIN
src/qt/res/icons/address-book.png
Normal file
BIN
src/qt/res/icons/address-book.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/qt/res/icons/bitcoin.png
Normal file
BIN
src/qt/res/icons/bitcoin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/qt/res/icons/quit.png
Normal file
BIN
src/qt/res/icons/quit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 876 B |
BIN
src/qt/res/icons/send.png
Normal file
BIN
src/qt/res/icons/send.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/qt/res/icons/toolbar.png
Normal file
BIN
src/qt/res/icons/toolbar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 968 B |
BIN
src/qt/res/images/about.png
Normal file
BIN
src/qt/res/images/about.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
113
src/qt/sendcoinsdialog.cpp
Normal file
113
src/qt/sendcoinsdialog.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "sendcoinsdialog.h"
|
||||
#include "ui_sendcoinsdialog.h"
|
||||
#include "clientmodel.h"
|
||||
#include "guiutil.h"
|
||||
|
||||
#include "addressbookdialog.h"
|
||||
#include "optionsmodel.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QMessageBox>
|
||||
#include <QLocale>
|
||||
#include <QDebug>
|
||||
|
||||
#include "util.h"
|
||||
#include "base58.h"
|
||||
|
||||
SendCoinsDialog::SendCoinsDialog(QWidget *parent, const QString &address) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::SendCoinsDialog),
|
||||
model(0)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
GUIUtil::setupAddressWidget(ui->payTo, this);
|
||||
GUIUtil::setupAmountWidget(ui->payAmount, this);
|
||||
|
||||
/* Set initial address if provided */
|
||||
if(!address.isEmpty())
|
||||
{
|
||||
ui->payTo->setText(address);
|
||||
ui->payAmount->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void SendCoinsDialog::setModel(ClientModel *model)
|
||||
{
|
||||
this->model = model;
|
||||
}
|
||||
|
||||
SendCoinsDialog::~SendCoinsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SendCoinsDialog::on_sendButton_clicked()
|
||||
{
|
||||
bool valid;
|
||||
QString payAmount = ui->payAmount->text();
|
||||
qint64 payAmountParsed;
|
||||
|
||||
valid = ParseMoney(payAmount.toStdString(), payAmountParsed);
|
||||
|
||||
if(!valid)
|
||||
{
|
||||
QMessageBox::warning(this, tr("Send Coins"),
|
||||
tr("The amount to pay must be a valid number."),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(model->sendCoins(ui->payTo->text(), payAmountParsed))
|
||||
{
|
||||
case ClientModel::InvalidAddress:
|
||||
QMessageBox::warning(this, tr("Send Coins"),
|
||||
tr("The recepient address is not valid, please recheck."),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
ui->payTo->setFocus();
|
||||
break;
|
||||
case ClientModel::InvalidAmount:
|
||||
QMessageBox::warning(this, tr("Send Coins"),
|
||||
tr("The amount to pay must be larger than 0."),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
ui->payAmount->setFocus();
|
||||
break;
|
||||
case ClientModel::AmountExceedsBalance:
|
||||
QMessageBox::warning(this, tr("Send Coins"),
|
||||
tr("Amount exceeds your balance"),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
ui->payAmount->setFocus();
|
||||
break;
|
||||
case ClientModel::AmountWithFeeExceedsBalance:
|
||||
QMessageBox::warning(this, tr("Send Coins"),
|
||||
tr("Total exceeds your balance when the %1 transaction fee is included").
|
||||
arg(QString::fromStdString(FormatMoney(model->getOptionsModel()->getTransactionFee()))),
|
||||
QMessageBox::Ok, QMessageBox::Ok);
|
||||
ui->payAmount->setFocus();
|
||||
break;
|
||||
case ClientModel::OK:
|
||||
accept();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SendCoinsDialog::on_pasteButton_clicked()
|
||||
{
|
||||
/* Paste text from clipboard into recipient field */
|
||||
ui->payTo->setText(QApplication::clipboard()->text());
|
||||
}
|
||||
|
||||
void SendCoinsDialog::on_addressBookButton_clicked()
|
||||
{
|
||||
AddressBookDialog dlg;
|
||||
dlg.setModel(model->getAddressTableModel());
|
||||
dlg.setTab(AddressBookDialog::SendingTab);
|
||||
dlg.exec();
|
||||
ui->payTo->setText(dlg.getReturnValue());
|
||||
}
|
||||
|
||||
void SendCoinsDialog::on_buttonBox_rejected()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
32
src/qt/sendcoinsdialog.h
Normal file
32
src/qt/sendcoinsdialog.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef SENDCOINSDIALOG_H
|
||||
#define SENDCOINSDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class SendCoinsDialog;
|
||||
}
|
||||
class ClientModel;
|
||||
|
||||
class SendCoinsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SendCoinsDialog(QWidget *parent = 0, const QString &address = "");
|
||||
~SendCoinsDialog();
|
||||
|
||||
void setModel(ClientModel *model);
|
||||
|
||||
private:
|
||||
Ui::SendCoinsDialog *ui;
|
||||
ClientModel *model;
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_rejected();
|
||||
void on_addressBookButton_clicked();
|
||||
void on_pasteButton_clicked();
|
||||
void on_sendButton_clicked();
|
||||
};
|
||||
|
||||
#endif // SENDCOINSDIALOG_H
|
||||
310
src/qt/transactiondesc.cpp
Normal file
310
src/qt/transactiondesc.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
#include <transactiondesc.h>
|
||||
|
||||
#include "guiutil.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
/* Taken straight from ui.cpp
|
||||
TODO: Convert to use QStrings, Qt::Escape and tr()
|
||||
*/
|
||||
|
||||
using namespace std;
|
||||
|
||||
static 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 += "<";
|
||||
else if (*p == '>') str += ">";
|
||||
else if (*p == '&') str += "&";
|
||||
else if (*p == '"') str += """;
|
||||
else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += " ";
|
||||
else if (*p == '\n' && fMultiLine) str += "<br>\n";
|
||||
else
|
||||
str += *p;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static string HtmlEscape(const string& str, bool fMultiLine=false)
|
||||
{
|
||||
return HtmlEscape(str.c_str(), fMultiLine);
|
||||
}
|
||||
|
||||
static 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"), GUIUtil::DateTimeStr(wtx.nLockTime).toStdString().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 TransactionDesc::toHTML(CWalletTx &wtx)
|
||||
{
|
||||
string strHTML;
|
||||
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||
{
|
||||
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 ? GUIUtil::DateTimeStr(nTime).toStdString() : "") + "<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
|
||||
BOOST_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;
|
||||
BOOST_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;
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
fAllFromMe = fAllFromMe && txin.IsMine();
|
||||
|
||||
bool fAllToMe = true;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
fAllToMe = fAllToMe && txout.IsMine();
|
||||
|
||||
if (fAllFromMe)
|
||||
{
|
||||
//
|
||||
// Debit
|
||||
//
|
||||
BOOST_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
|
||||
int64 nChange = wtx.GetChange();
|
||||
int64 nValue = nCredit - nChange;
|
||||
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
|
||||
//
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
if (txin.IsMine())
|
||||
strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
|
||||
BOOST_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.mapValue["comment"].empty())
|
||||
strHTML += string() + "<br><b>" + _("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], 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>";
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
if (txin.IsMine())
|
||||
strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
if (txout.IsMine())
|
||||
strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
|
||||
|
||||
strHTML += "<br><b>Transaction:</b><br>";
|
||||
strHTML += HtmlEscape(wtx.ToString(), true);
|
||||
|
||||
strHTML += "<br><b>Inputs:</b><br>";
|
||||
CRITICAL_BLOCK(cs_mapWallet)
|
||||
{
|
||||
BOOST_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 += " " + FormatTxStatus(prev) + ", ";
|
||||
strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
strHTML += "</font></html>";
|
||||
}
|
||||
return strHTML;
|
||||
}
|
||||
15
src/qt/transactiondesc.h
Normal file
15
src/qt/transactiondesc.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef TRANSACTIONDESC_H
|
||||
#define TRANSACTIONDESC_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class CWalletTx;
|
||||
|
||||
class TransactionDesc
|
||||
{
|
||||
public:
|
||||
/* Provide human-readable extended HTML description of a transaction */
|
||||
static std::string toHTML(CWalletTx &wtx);
|
||||
};
|
||||
|
||||
#endif // TRANSACTIONDESC_H
|
||||
20
src/qt/transactiondescdialog.cpp
Normal file
20
src/qt/transactiondescdialog.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "transactiondescdialog.h"
|
||||
#include "ui_transactiondescdialog.h"
|
||||
|
||||
#include "transactiontablemodel.h"
|
||||
|
||||
#include <QModelIndex>
|
||||
|
||||
TransactionDescDialog::TransactionDescDialog(const QModelIndex &idx, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::TransactionDescDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QString desc = idx.data(TransactionTableModel::LongDescriptionRole).toString();
|
||||
ui->detailText->setHtml(desc);
|
||||
}
|
||||
|
||||
TransactionDescDialog::~TransactionDescDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
25
src/qt/transactiondescdialog.h
Normal file
25
src/qt/transactiondescdialog.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef TRANSACTIONDESCDIALOG_H
|
||||
#define TRANSACTIONDESCDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class TransactionDescDialog;
|
||||
}
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QModelIndex;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class TransactionDescDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TransactionDescDialog(const QModelIndex &idx, QWidget *parent = 0);
|
||||
~TransactionDescDialog();
|
||||
|
||||
private:
|
||||
Ui::TransactionDescDialog *ui;
|
||||
};
|
||||
|
||||
#endif // TRANSACTIONDESCDIALOG_H
|
||||
254
src/qt/transactionrecord.cpp
Normal file
254
src/qt/transactionrecord.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "transactionrecord.h"
|
||||
|
||||
|
||||
/* Return positive answer if transaction should be shown in list.
|
||||
*/
|
||||
bool TransactionRecord::showTransaction(const CWalletTx &wtx)
|
||||
{
|
||||
if (wtx.IsCoinBase())
|
||||
{
|
||||
// Don't show generated coin until confirmed by at least one block after it
|
||||
// so we don't get the user's hopes up until it looks like it's probably accepted.
|
||||
//
|
||||
// It is not an error when generated blocks are not accepted. By design,
|
||||
// some percentage of blocks, like 10% or more, will end up not accepted.
|
||||
// This is the normal mechanism by which the network copes with latency.
|
||||
//
|
||||
// We display regular transactions right away before any confirmation
|
||||
// because they can always get into some block eventually. Generated coins
|
||||
// are special because if their block is not accepted, they are not valid.
|
||||
//
|
||||
if (wtx.GetDepthInMainChain() < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Decompose CWallet transaction to model transaction records.
|
||||
*/
|
||||
QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWalletTx &wtx)
|
||||
{
|
||||
QList<TransactionRecord> parts;
|
||||
int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
|
||||
int64 nCredit = wtx.GetCredit(true);
|
||||
int64 nDebit = wtx.GetDebit();
|
||||
int64 nNet = nCredit - nDebit;
|
||||
uint256 hash = wtx.GetHash();
|
||||
std::map<std::string, std::string> mapValue = wtx.mapValue;
|
||||
|
||||
if (showTransaction(wtx))
|
||||
{
|
||||
if (nNet > 0 || wtx.IsCoinBase())
|
||||
{
|
||||
//
|
||||
// Credit
|
||||
//
|
||||
TransactionRecord sub(hash, nTime);
|
||||
|
||||
sub.credit = nNet;
|
||||
|
||||
if (wtx.IsCoinBase())
|
||||
{
|
||||
// Generated
|
||||
sub.type = TransactionRecord::Generated;
|
||||
|
||||
if (nCredit == 0)
|
||||
{
|
||||
int64 nUnmatured = 0;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
nUnmatured += txout.GetCredit();
|
||||
sub.credit = nUnmatured;
|
||||
}
|
||||
}
|
||||
else if (!mapValue["from"].empty() || !mapValue["message"].empty())
|
||||
{
|
||||
// Received by IP connection
|
||||
sub.type = TransactionRecord::RecvFromIP;
|
||||
if (!mapValue["from"].empty())
|
||||
sub.address = mapValue["from"];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Received by Bitcoin Address
|
||||
sub.type = TransactionRecord::RecvWithAddress;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
{
|
||||
if (txout.IsMine())
|
||||
{
|
||||
std::vector<unsigned char> vchPubKey;
|
||||
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
|
||||
{
|
||||
sub.address = PubKeyToAddress(vchPubKey);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
parts.append(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool fAllFromMe = true;
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
fAllFromMe = fAllFromMe && txin.IsMine();
|
||||
|
||||
bool fAllToMe = true;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
fAllToMe = fAllToMe && txout.IsMine();
|
||||
|
||||
if (fAllFromMe && fAllToMe)
|
||||
{
|
||||
// Payment to self
|
||||
int64 nChange = wtx.GetChange();
|
||||
|
||||
parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
|
||||
-(nDebit - nChange), nCredit - nChange));
|
||||
}
|
||||
else if (fAllFromMe)
|
||||
{
|
||||
//
|
||||
// Debit
|
||||
//
|
||||
int64 nTxFee = nDebit - wtx.GetValueOut();
|
||||
|
||||
for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
|
||||
{
|
||||
const CTxOut& txout = wtx.vout[nOut];
|
||||
TransactionRecord sub(hash, nTime);
|
||||
sub.idx = parts.size();
|
||||
|
||||
if (txout.IsMine())
|
||||
{
|
||||
// Ignore parts sent to self, as this is usually the change
|
||||
// from a transaction sent back to our own address.
|
||||
continue;
|
||||
}
|
||||
else if (!mapValue["to"].empty())
|
||||
{
|
||||
// Sent to IP
|
||||
sub.type = TransactionRecord::SendToIP;
|
||||
sub.address = mapValue["to"];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sent to Bitcoin Address
|
||||
sub.type = TransactionRecord::SendToAddress;
|
||||
uint160 hash160;
|
||||
if (ExtractHash160(txout.scriptPubKey, hash160))
|
||||
sub.address = Hash160ToAddress(hash160);
|
||||
}
|
||||
|
||||
int64 nValue = txout.nValue;
|
||||
/* Add fee to first output */
|
||||
if (nTxFee > 0)
|
||||
{
|
||||
nValue += nTxFee;
|
||||
nTxFee = 0;
|
||||
}
|
||||
sub.debit = -nValue;
|
||||
|
||||
parts.append(sub);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Mixed debit transaction, can't break down payees
|
||||
//
|
||||
bool fAllMine = true;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
fAllMine = fAllMine && txout.IsMine();
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
fAllMine = fAllMine && txin.IsMine();
|
||||
|
||||
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
void TransactionRecord::updateStatus(const CWalletTx &wtx)
|
||||
{
|
||||
// Determine transaction status
|
||||
|
||||
// Find the block the tx is in
|
||||
CBlockIndex* pindex = NULL;
|
||||
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(wtx.hashBlock);
|
||||
if (mi != mapBlockIndex.end())
|
||||
pindex = (*mi).second;
|
||||
|
||||
// Sort order, unrecorded transactions sort to the top
|
||||
status.sortKey = strprintf("%010d-%01d-%010u-%03d",
|
||||
(pindex ? pindex->nHeight : INT_MAX),
|
||||
(wtx.IsCoinBase() ? 1 : 0),
|
||||
wtx.nTimeReceived,
|
||||
idx);
|
||||
status.confirmed = wtx.IsConfirmed();
|
||||
status.depth = wtx.GetDepthInMainChain();
|
||||
status.cur_num_blocks = nBestHeight;
|
||||
|
||||
if (!wtx.IsFinal())
|
||||
{
|
||||
if (wtx.nLockTime < 500000000)
|
||||
{
|
||||
status.status = TransactionStatus::OpenUntilBlock;
|
||||
status.open_for = nBestHeight - wtx.nLockTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
status.status = TransactionStatus::OpenUntilDate;
|
||||
status.open_for = wtx.nLockTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
||||
{
|
||||
status.status = TransactionStatus::Offline;
|
||||
}
|
||||
else if (status.depth < 6)
|
||||
{
|
||||
status.status = TransactionStatus::Unconfirmed;
|
||||
}
|
||||
else
|
||||
{
|
||||
status.status = TransactionStatus::HaveConfirmations;
|
||||
}
|
||||
}
|
||||
|
||||
// For generated transactions, determine maturity
|
||||
if(type == TransactionRecord::Generated)
|
||||
{
|
||||
int64 nCredit = wtx.GetCredit(true);
|
||||
if (nCredit == 0)
|
||||
{
|
||||
status.maturity = TransactionStatus::Immature;
|
||||
|
||||
if (wtx.IsInMainChain())
|
||||
{
|
||||
status.matures_in = wtx.GetBlocksToMaturity();
|
||||
|
||||
// Check if the block was requested by anyone
|
||||
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
||||
status.maturity = TransactionStatus::MaturesWarning;
|
||||
}
|
||||
else
|
||||
{
|
||||
status.maturity = TransactionStatus::NotAccepted;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status.maturity = TransactionStatus::Mature;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TransactionRecord::statusUpdateNeeded()
|
||||
{
|
||||
return status.cur_num_blocks != nBestHeight;
|
||||
}
|
||||
109
src/qt/transactionrecord.h
Normal file
109
src/qt/transactionrecord.h
Normal file
@@ -0,0 +1,109 @@
|
||||
#ifndef TRANSACTIONRECORD_H
|
||||
#define TRANSACTIONRECORD_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
class TransactionStatus
|
||||
{
|
||||
public:
|
||||
TransactionStatus():
|
||||
confirmed(false), sortKey(""), maturity(Mature),
|
||||
matures_in(0), status(Offline), depth(0), open_for(0), cur_num_blocks(-1)
|
||||
{ }
|
||||
|
||||
enum Maturity
|
||||
{
|
||||
Immature,
|
||||
Mature,
|
||||
MaturesWarning, /* Will likely not mature because no nodes have confirmed */
|
||||
NotAccepted
|
||||
};
|
||||
|
||||
enum Status {
|
||||
OpenUntilDate,
|
||||
OpenUntilBlock,
|
||||
Offline,
|
||||
Unconfirmed,
|
||||
HaveConfirmations
|
||||
};
|
||||
|
||||
bool confirmed;
|
||||
std::string sortKey;
|
||||
|
||||
/* For "Generated" transactions */
|
||||
Maturity maturity;
|
||||
int matures_in;
|
||||
|
||||
/* Reported status */
|
||||
Status status;
|
||||
int64 depth;
|
||||
int64 open_for; /* Timestamp if status==OpenUntilDate, otherwise number of blocks */
|
||||
|
||||
/* Current number of blocks (to know whether cached status is still valid. */
|
||||
int cur_num_blocks;
|
||||
};
|
||||
|
||||
class TransactionRecord
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
Other,
|
||||
Generated,
|
||||
SendToAddress,
|
||||
SendToIP,
|
||||
RecvWithAddress,
|
||||
RecvFromIP,
|
||||
SendToSelf
|
||||
};
|
||||
|
||||
TransactionRecord():
|
||||
hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0)
|
||||
{
|
||||
}
|
||||
|
||||
TransactionRecord(uint256 hash, int64 time):
|
||||
hash(hash), time(time), type(Other), address(""), debit(0),
|
||||
credit(0), idx(0)
|
||||
{
|
||||
}
|
||||
|
||||
TransactionRecord(uint256 hash, int64 time,
|
||||
Type type, const std::string &address,
|
||||
int64 debit, int64 credit):
|
||||
hash(hash), time(time), type(type), address(address), debit(debit), credit(credit),
|
||||
idx(0)
|
||||
{
|
||||
}
|
||||
|
||||
/* Decompose CWallet transaction to model transaction records.
|
||||
*/
|
||||
static bool showTransaction(const CWalletTx &wtx);
|
||||
static QList<TransactionRecord> decomposeTransaction(const CWalletTx &wtx);
|
||||
|
||||
/* Fixed */
|
||||
uint256 hash;
|
||||
int64 time;
|
||||
Type type;
|
||||
std::string address;
|
||||
int64 debit;
|
||||
int64 credit;
|
||||
|
||||
/* Subtransaction index, for sort key */
|
||||
int idx;
|
||||
|
||||
/* Status: can change with block chain update */
|
||||
TransactionStatus status;
|
||||
|
||||
/* Update status from wallet tx.
|
||||
*/
|
||||
void updateStatus(const CWalletTx &wtx);
|
||||
|
||||
/* Is a status update needed?
|
||||
*/
|
||||
bool statusUpdateNeeded();
|
||||
};
|
||||
|
||||
#endif // TRANSACTIONRECORD_H
|
||||
512
src/qt/transactiontablemodel.cpp
Normal file
512
src/qt/transactiontablemodel.cpp
Normal file
@@ -0,0 +1,512 @@
|
||||
#include "transactiontablemodel.h"
|
||||
#include "guiutil.h"
|
||||
#include "transactionrecord.h"
|
||||
#include "guiconstants.h"
|
||||
#include "main.h"
|
||||
#include "transactiondesc.h"
|
||||
|
||||
#include <QLocale>
|
||||
#include <QDebug>
|
||||
#include <QList>
|
||||
#include <QColor>
|
||||
#include <QTimer>
|
||||
#include <QtAlgorithms>
|
||||
|
||||
const QString TransactionTableModel::Sent = "s";
|
||||
const QString TransactionTableModel::Received = "r";
|
||||
const QString TransactionTableModel::Other = "o";
|
||||
|
||||
/* Comparison operator for sort/binary search of model tx list */
|
||||
struct TxLessThan
|
||||
{
|
||||
bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
|
||||
{
|
||||
return a.hash < b.hash;
|
||||
}
|
||||
bool operator()(const TransactionRecord &a, const uint256 &b) const
|
||||
{
|
||||
return a.hash < b;
|
||||
}
|
||||
bool operator()(const uint256 &a, const TransactionRecord &b) const
|
||||
{
|
||||
return a < b.hash;
|
||||
}
|
||||
};
|
||||
|
||||
/* Private implementation */
|
||||
struct TransactionTablePriv
|
||||
{
|
||||
TransactionTablePriv(TransactionTableModel *parent):
|
||||
parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
TransactionTableModel *parent;
|
||||
|
||||
/* Local cache of wallet.
|
||||
* As it is in the same order as the CWallet, by definition
|
||||
* this is sorted by sha256.
|
||||
*/
|
||||
QList<TransactionRecord> cachedWallet;
|
||||
|
||||
void refreshWallet()
|
||||
{
|
||||
qDebug() << "refreshWallet";
|
||||
|
||||
/* Query entire wallet from core.
|
||||
*/
|
||||
cachedWallet.clear();
|
||||
CRITICAL_BLOCK(cs_mapWallet)
|
||||
{
|
||||
for(std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
cachedWallet.append(TransactionRecord::decomposeTransaction(it->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update our model of the wallet incrementally.
|
||||
Call with list of hashes of transactions that were added, removed or changed.
|
||||
*/
|
||||
void updateWallet(const QList<uint256> &updated)
|
||||
{
|
||||
/* Walk through updated transactions, update model as needed.
|
||||
*/
|
||||
qDebug() << "updateWallet";
|
||||
|
||||
/* Sort update list, and iterate through it in reverse, so that model updates
|
||||
can be emitted from end to beginning (so that earlier updates will not influence
|
||||
the indices of latter ones).
|
||||
*/
|
||||
QList<uint256> updated_sorted = updated;
|
||||
qSort(updated_sorted);
|
||||
|
||||
CRITICAL_BLOCK(cs_mapWallet)
|
||||
{
|
||||
for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx)
|
||||
{
|
||||
const uint256 &hash = updated_sorted.at(update_idx);
|
||||
/* Find transaction in wallet */
|
||||
std::map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
|
||||
bool inWallet = mi != mapWallet.end();
|
||||
/* Find bounds of this transaction in model */
|
||||
QList<TransactionRecord>::iterator lower = qLowerBound(
|
||||
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
|
||||
QList<TransactionRecord>::iterator upper = qUpperBound(
|
||||
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
|
||||
int lowerIndex = (lower - cachedWallet.begin());
|
||||
int upperIndex = (upper - cachedWallet.begin());
|
||||
|
||||
bool inModel = false;
|
||||
if(lower != upper)
|
||||
{
|
||||
inModel = true;
|
||||
}
|
||||
|
||||
qDebug() << " " << QString::fromStdString(hash.ToString()) << inWallet << " " << inModel
|
||||
<< lowerIndex << "-" << upperIndex;
|
||||
|
||||
if(inWallet && !inModel)
|
||||
{
|
||||
/* Added */
|
||||
QList<TransactionRecord> toInsert =
|
||||
TransactionRecord::decomposeTransaction(mi->second);
|
||||
if(!toInsert.isEmpty()) /* only if something to insert */
|
||||
{
|
||||
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
|
||||
int insert_idx = lowerIndex;
|
||||
foreach(const TransactionRecord &rec, toInsert)
|
||||
{
|
||||
cachedWallet.insert(insert_idx, rec);
|
||||
insert_idx += 1;
|
||||
}
|
||||
parent->endInsertRows();
|
||||
}
|
||||
}
|
||||
else if(!inWallet && inModel)
|
||||
{
|
||||
/* Removed */
|
||||
parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
|
||||
cachedWallet.erase(lower, upper);
|
||||
parent->endRemoveRows();
|
||||
}
|
||||
else if(inWallet && inModel)
|
||||
{
|
||||
/* Updated -- nothing to do, status update will take care of this */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int size()
|
||||
{
|
||||
return cachedWallet.size();
|
||||
}
|
||||
|
||||
TransactionRecord *index(int idx)
|
||||
{
|
||||
if(idx >= 0 && idx < cachedWallet.size())
|
||||
{
|
||||
TransactionRecord *rec = &cachedWallet[idx];
|
||||
|
||||
/* If a status update is needed (blocks came in since last check),
|
||||
update the status of this transaction from the wallet. Otherwise,
|
||||
simply re-use the cached status.
|
||||
*/
|
||||
if(rec->statusUpdateNeeded())
|
||||
{
|
||||
CRITICAL_BLOCK(cs_mapWallet)
|
||||
{
|
||||
std::map<uint256, CWalletTx>::iterator mi = mapWallet.find(rec->hash);
|
||||
|
||||
if(mi != mapWallet.end())
|
||||
{
|
||||
rec->updateStatus(mi->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QString describe(TransactionRecord *rec)
|
||||
{
|
||||
CRITICAL_BLOCK(cs_mapWallet)
|
||||
{
|
||||
std::map<uint256, CWalletTx>::iterator mi = mapWallet.find(rec->hash);
|
||||
if(mi != mapWallet.end())
|
||||
{
|
||||
return QString::fromStdString(TransactionDesc::toHTML(mi->second));
|
||||
}
|
||||
}
|
||||
return QString("");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* Credit and Debit columns are right-aligned as they contain numbers */
|
||||
static int column_alignments[] = {
|
||||
Qt::AlignLeft|Qt::AlignVCenter,
|
||||
Qt::AlignLeft|Qt::AlignVCenter,
|
||||
Qt::AlignLeft|Qt::AlignVCenter,
|
||||
Qt::AlignRight|Qt::AlignVCenter,
|
||||
Qt::AlignRight|Qt::AlignVCenter,
|
||||
Qt::AlignLeft|Qt::AlignVCenter
|
||||
};
|
||||
|
||||
TransactionTableModel::TransactionTableModel(QObject *parent):
|
||||
QAbstractTableModel(parent),
|
||||
priv(new TransactionTablePriv(this))
|
||||
{
|
||||
columns << tr("Status") << tr("Date") << tr("Description") << tr("Debit") << tr("Credit");
|
||||
|
||||
priv->refreshWallet();
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
timer->start(MODEL_UPDATE_DELAY);
|
||||
}
|
||||
|
||||
TransactionTableModel::~TransactionTableModel()
|
||||
{
|
||||
delete priv;
|
||||
}
|
||||
|
||||
void TransactionTableModel::update()
|
||||
{
|
||||
QList<uint256> updated;
|
||||
|
||||
/* Check if there are changes to wallet map */
|
||||
TRY_CRITICAL_BLOCK(cs_mapWallet)
|
||||
{
|
||||
if(!vWalletUpdated.empty())
|
||||
{
|
||||
BOOST_FOREACH(uint256 hash, vWalletUpdated)
|
||||
{
|
||||
updated.append(hash);
|
||||
}
|
||||
vWalletUpdated.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if(!updated.empty())
|
||||
{
|
||||
priv->updateWallet(updated);
|
||||
|
||||
/* Status (number of confirmations) and (possibly) description
|
||||
columns changed for all rows.
|
||||
*/
|
||||
emit dataChanged(index(0, Status), index(priv->size()-1, Status));
|
||||
emit dataChanged(index(0, Description), index(priv->size()-1, Description));
|
||||
}
|
||||
}
|
||||
|
||||
int TransactionTableModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return priv->size();
|
||||
}
|
||||
|
||||
int TransactionTableModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return columns.length();
|
||||
}
|
||||
|
||||
QVariant TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) const
|
||||
{
|
||||
QString status;
|
||||
|
||||
switch(wtx->status.status)
|
||||
{
|
||||
case TransactionStatus::OpenUntilBlock:
|
||||
status = tr("Open for %n block(s)","",wtx->status.open_for);
|
||||
break;
|
||||
case TransactionStatus::OpenUntilDate:
|
||||
status = tr("Open until ") + GUIUtil::DateTimeStr(wtx->status.open_for);
|
||||
break;
|
||||
case TransactionStatus::Offline:
|
||||
status = tr("%1/offline").arg(wtx->status.depth);
|
||||
break;
|
||||
case TransactionStatus::Unconfirmed:
|
||||
status = tr("%1/unconfirmed").arg(wtx->status.depth);
|
||||
break;
|
||||
case TransactionStatus::HaveConfirmations:
|
||||
status = tr("%1 confirmations").arg(wtx->status.depth);
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant(status);
|
||||
}
|
||||
|
||||
QVariant TransactionTableModel::formatTxDate(const TransactionRecord *wtx) const
|
||||
{
|
||||
if(wtx->time)
|
||||
{
|
||||
return QVariant(GUIUtil::DateTimeStr(wtx->time));
|
||||
}
|
||||
else
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
/* Look up address in address book, if found return
|
||||
address[0:12]... (label)
|
||||
otherwise just return address
|
||||
*/
|
||||
std::string lookupAddress(const std::string &address)
|
||||
{
|
||||
std::string description;
|
||||
CRITICAL_BLOCK(cs_mapAddressBook)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator mi = mapAddressBook.find(address);
|
||||
if (mi != mapAddressBook.end() && !(*mi).second.empty())
|
||||
{
|
||||
std::string label = (*mi).second;
|
||||
description += address.substr(0,12) + "... ";
|
||||
description += "(" + label + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
description += address;
|
||||
}
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
QVariant TransactionTableModel::formatTxDescription(const TransactionRecord *wtx) const
|
||||
{
|
||||
QString description;
|
||||
|
||||
switch(wtx->type)
|
||||
{
|
||||
case TransactionRecord::RecvWithAddress:
|
||||
description = tr("Received with: ") + QString::fromStdString(lookupAddress(wtx->address));
|
||||
break;
|
||||
case TransactionRecord::RecvFromIP:
|
||||
description = tr("Received from IP: ") + QString::fromStdString(wtx->address);
|
||||
break;
|
||||
case TransactionRecord::SendToAddress:
|
||||
description = tr("Sent to: ") + QString::fromStdString(lookupAddress(wtx->address));
|
||||
break;
|
||||
case TransactionRecord::SendToIP:
|
||||
description = tr("Sent to IP: ") + QString::fromStdString(wtx->address);
|
||||
break;
|
||||
case TransactionRecord::SendToSelf:
|
||||
description = tr("Payment to yourself");
|
||||
break;
|
||||
case TransactionRecord::Generated:
|
||||
switch(wtx->status.maturity)
|
||||
{
|
||||
case TransactionStatus::Immature:
|
||||
description = tr("Generated (matures in %n more blocks)", "",
|
||||
wtx->status.matures_in);
|
||||
break;
|
||||
case TransactionStatus::Mature:
|
||||
description = tr("Generated");
|
||||
break;
|
||||
case TransactionStatus::MaturesWarning:
|
||||
description = tr("Generated - Warning: This block was not received by any other nodes and will probably not be accepted!");
|
||||
break;
|
||||
case TransactionStatus::NotAccepted:
|
||||
description = tr("Generated (not accepted)");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return QVariant(description);
|
||||
}
|
||||
|
||||
QVariant TransactionTableModel::formatTxDebit(const TransactionRecord *wtx) const
|
||||
{
|
||||
if(wtx->debit)
|
||||
{
|
||||
QString str = QString::fromStdString(FormatMoney(wtx->debit));
|
||||
if(!wtx->status.confirmed || wtx->status.maturity != TransactionStatus::Mature)
|
||||
{
|
||||
str = QString("[") + str + QString("]");
|
||||
}
|
||||
return QVariant(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant TransactionTableModel::formatTxCredit(const TransactionRecord *wtx) const
|
||||
{
|
||||
if(wtx->credit)
|
||||
{
|
||||
QString str = QString::fromStdString(FormatMoney(wtx->credit));
|
||||
if(!wtx->status.confirmed || wtx->status.maturity != TransactionStatus::Mature)
|
||||
{
|
||||
str = QString("[") + str + QString("]");
|
||||
}
|
||||
return QVariant(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if(!index.isValid())
|
||||
return QVariant();
|
||||
TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
|
||||
|
||||
if(role == Qt::DisplayRole)
|
||||
{
|
||||
/* Delegate to specific column handlers */
|
||||
switch(index.column())
|
||||
{
|
||||
case Status:
|
||||
return formatTxStatus(rec);
|
||||
case Date:
|
||||
return formatTxDate(rec);
|
||||
case Description:
|
||||
return formatTxDescription(rec);
|
||||
case Debit:
|
||||
return formatTxDebit(rec);
|
||||
case Credit:
|
||||
return formatTxCredit(rec);
|
||||
}
|
||||
}
|
||||
else if(role == Qt::EditRole)
|
||||
{
|
||||
/* Edit role is used for sorting so return the real values */
|
||||
switch(index.column())
|
||||
{
|
||||
case Status:
|
||||
return QString::fromStdString(rec->status.sortKey);
|
||||
case Date:
|
||||
return rec->time;
|
||||
case Description:
|
||||
return formatTxDescription(rec);
|
||||
case Debit:
|
||||
return rec->debit;
|
||||
case Credit:
|
||||
return rec->credit;
|
||||
}
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole)
|
||||
{
|
||||
return column_alignments[index.column()];
|
||||
}
|
||||
else if (role == Qt::ForegroundRole)
|
||||
{
|
||||
/* Non-confirmed transactions are grey */
|
||||
if(rec->status.confirmed)
|
||||
{
|
||||
return QColor(0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QColor(128, 128, 128);
|
||||
}
|
||||
}
|
||||
else if (role == TypeRole)
|
||||
{
|
||||
/* Role for filtering tabs by type */
|
||||
switch(rec->type)
|
||||
{
|
||||
case TransactionRecord::RecvWithAddress:
|
||||
case TransactionRecord::RecvFromIP:
|
||||
return TransactionTableModel::Received;
|
||||
case TransactionRecord::SendToAddress:
|
||||
case TransactionRecord::SendToIP:
|
||||
case TransactionRecord::SendToSelf:
|
||||
return TransactionTableModel::Sent;
|
||||
default:
|
||||
return TransactionTableModel::Other;
|
||||
}
|
||||
}
|
||||
else if (role == LongDescriptionRole)
|
||||
{
|
||||
return priv->describe(rec);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if(orientation == Qt::Horizontal)
|
||||
{
|
||||
if(role == Qt::DisplayRole)
|
||||
{
|
||||
return columns[section];
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole)
|
||||
{
|
||||
return column_alignments[section];
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::ItemFlags TransactionTableModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
return QAbstractTableModel::flags(index);
|
||||
}
|
||||
|
||||
QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
TransactionRecord *data = priv->index(row);
|
||||
if(data)
|
||||
{
|
||||
return createIndex(row, column, priv->index(row));
|
||||
}
|
||||
else
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
58
src/qt/transactiontablemodel.h
Normal file
58
src/qt/transactiontablemodel.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef TRANSACTIONTABLEMODEL_H
|
||||
#define TRANSACTIONTABLEMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStringList>
|
||||
|
||||
class TransactionTablePriv;
|
||||
class TransactionRecord;
|
||||
|
||||
class TransactionTableModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TransactionTableModel(QObject *parent = 0);
|
||||
~TransactionTableModel();
|
||||
|
||||
enum {
|
||||
Status = 0,
|
||||
Date = 1,
|
||||
Description = 2,
|
||||
Debit = 3,
|
||||
Credit = 4
|
||||
} ColumnIndex;
|
||||
|
||||
enum {
|
||||
TypeRole = Qt::UserRole,
|
||||
LongDescriptionRole = Qt::UserRole+1
|
||||
} RoleIndex;
|
||||
|
||||
/* TypeRole values */
|
||||
static const QString Sent;
|
||||
static const QString Received;
|
||||
static const QString Other;
|
||||
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
int columnCount(const QModelIndex &parent) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
|
||||
private:
|
||||
QStringList columns;
|
||||
TransactionTablePriv *priv;
|
||||
|
||||
QVariant formatTxStatus(const TransactionRecord *wtx) const;
|
||||
QVariant formatTxDate(const TransactionRecord *wtx) const;
|
||||
QVariant formatTxDescription(const TransactionRecord *wtx) const;
|
||||
QVariant formatTxDebit(const TransactionRecord *wtx) const;
|
||||
QVariant formatTxCredit(const TransactionRecord *wtx) const;
|
||||
|
||||
private slots:
|
||||
void update();
|
||||
|
||||
friend class TransactionTablePriv;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
2209
src/rpc.cpp
Normal file
2209
src/rpc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
6
src/rpc.h
Normal file
6
src/rpc.h
Normal file
@@ -0,0 +1,6 @@
|
||||
// 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[]);
|
||||
1208
src/script.cpp
Normal file
1208
src/script.cpp
Normal file
File diff suppressed because it is too large
Load Diff
718
src/script.h
Normal file
718
src/script.h
Normal file
@@ -0,0 +1,718 @@
|
||||
// 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.
|
||||
#ifndef H_BITCOIN_SCRIPT
|
||||
#define H_BITCOIN_SCRIPT
|
||||
|
||||
#include "base58.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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,
|
||||
|
||||
// expansion
|
||||
OP_NOP1,
|
||||
OP_NOP2,
|
||||
OP_NOP3,
|
||||
OP_NOP4,
|
||||
OP_NOP5,
|
||||
OP_NOP6,
|
||||
OP_NOP7,
|
||||
OP_NOP8,
|
||||
OP_NOP9,
|
||||
OP_NOP10,
|
||||
|
||||
|
||||
|
||||
// template matching params
|
||||
OP_PUBKEYHASH = 0xfd,
|
||||
OP_PUBKEY = 0xfe,
|
||||
|
||||
OP_INVALIDOPCODE = 0xff,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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";
|
||||
|
||||
// expanson
|
||||
case OP_NOP1 : return "OP_NOP1";
|
||||
case OP_NOP2 : return "OP_NOP2";
|
||||
case OP_NOP3 : return "OP_NOP3";
|
||||
case OP_NOP4 : return "OP_NOP4";
|
||||
case OP_NOP5 : return "OP_NOP5";
|
||||
case OP_NOP6 : return "OP_NOP6";
|
||||
case OP_NOP7 : return "OP_NOP7";
|
||||
case OP_NOP8 : return "OP_NOP8";
|
||||
case OP_NOP9 : return "OP_NOP9";
|
||||
case OP_NOP10 : return "OP_NOP10";
|
||||
|
||||
|
||||
|
||||
// template matching params
|
||||
case OP_PUBKEYHASH : return "OP_PUBKEYHASH";
|
||||
case OP_PUBKEY : return "OP_PUBKEY";
|
||||
|
||||
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
||||
default:
|
||||
return "OP_UNKNOWN";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
inline std::string ValueString(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.size() <= 4)
|
||||
return strprintf("%d", CBigNum(vch).getint());
|
||||
else
|
||||
return HexStr(vch);
|
||||
}
|
||||
|
||||
inline std::string StackString(const std::vector<std::vector<unsigned char> >& vStack)
|
||||
{
|
||||
std::string str;
|
||||
BOOST_FOREACH(const std::vector<unsigned char>& vch, vStack)
|
||||
{
|
||||
if (!str.empty())
|
||||
str += " ";
|
||||
str += ValueString(vch);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CScript : public std::vector<unsigned char>
|
||||
{
|
||||
protected:
|
||||
CScript& push_int64(int64 n)
|
||||
{
|
||||
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 <= 16)
|
||||
{
|
||||
push_back(n + (OP_1 - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
CBigNum bn(n);
|
||||
*this << bn.getvch();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
CScript() { }
|
||||
CScript(const CScript& b) : std::vector<unsigned char>(b.begin(), b.end()) { }
|
||||
CScript(const_iterator pbegin, const_iterator pend) : std::vector<unsigned char>(pbegin, pend) { }
|
||||
#ifndef _MSC_VER
|
||||
CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector<unsigned char>(pbegin, pend) { }
|
||||
#endif
|
||||
|
||||
CScript& operator+=(const CScript& b)
|
||||
{
|
||||
insert(end(), b.begin(), b.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend CScript operator+(const CScript& a, const CScript& b)
|
||||
{
|
||||
CScript ret = a;
|
||||
ret += b;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
explicit CScript(char b) { operator<<(b); }
|
||||
explicit CScript(short b) { operator<<(b); }
|
||||
explicit CScript(int b) { operator<<(b); }
|
||||
explicit CScript(long b) { operator<<(b); }
|
||||
explicit CScript(int64 b) { operator<<(b); }
|
||||
explicit CScript(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 std::vector<unsigned char>& b) { operator<<(b); }
|
||||
|
||||
|
||||
CScript& operator<<(char b) { return push_int64(b); }
|
||||
CScript& operator<<(short b) { return push_int64(b); }
|
||||
CScript& operator<<(int b) { return push_int64(b); }
|
||||
CScript& operator<<(long b) { return push_int64(b); }
|
||||
CScript& operator<<(int64 b) { return push_int64(b); }
|
||||
CScript& operator<<(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 < 0 || opcode > 0xff)
|
||||
throw std::runtime_error("CScript::operator<<() : invalid opcode");
|
||||
insert(end(), (unsigned char)opcode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const uint160& b)
|
||||
{
|
||||
insert(end(), sizeof(b));
|
||||
insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b));
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const uint256& b)
|
||||
{
|
||||
insert(end(), sizeof(b));
|
||||
insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b));
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const CBigNum& b)
|
||||
{
|
||||
*this << b.getvch();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const std::vector<unsigned char>& b)
|
||||
{
|
||||
if (b.size() < OP_PUSHDATA1)
|
||||
{
|
||||
insert(end(), (unsigned char)b.size());
|
||||
}
|
||||
else if (b.size() <= 0xff)
|
||||
{
|
||||
insert(end(), OP_PUSHDATA1);
|
||||
insert(end(), (unsigned char)b.size());
|
||||
}
|
||||
else if (b.size() <= 0xffff)
|
||||
{
|
||||
insert(end(), OP_PUSHDATA2);
|
||||
unsigned short nSize = b.size();
|
||||
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
insert(end(), OP_PUSHDATA4);
|
||||
unsigned int nSize = b.size();
|
||||
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
|
||||
}
|
||||
insert(end(), b.begin(), b.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const CScript& b)
|
||||
{
|
||||
// I'm not sure if this should push the script or concatenate scripts.
|
||||
// If there's ever a use for pushing a script onto a script, delete this member fn
|
||||
assert(("warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate", false));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool GetOp(iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
// Wrapper so it can be called with either iterator or const_iterator
|
||||
const_iterator pc2 = pc;
|
||||
bool fRet = GetOp2(pc2, opcodeRet, &vchRet);
|
||||
pc = begin() + (pc2 - begin());
|
||||
return fRet;
|
||||
}
|
||||
|
||||
bool GetOp(iterator& pc, opcodetype& opcodeRet)
|
||||
{
|
||||
const_iterator pc2 = pc;
|
||||
bool fRet = GetOp2(pc2, opcodeRet, NULL);
|
||||
pc = begin() + (pc2 - begin());
|
||||
return fRet;
|
||||
}
|
||||
|
||||
bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const
|
||||
{
|
||||
return GetOp2(pc, opcodeRet, &vchRet);
|
||||
}
|
||||
|
||||
bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const
|
||||
{
|
||||
return GetOp2(pc, opcodeRet, NULL);
|
||||
}
|
||||
|
||||
bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet) const
|
||||
{
|
||||
opcodeRet = OP_INVALIDOPCODE;
|
||||
if (pvchRet)
|
||||
pvchRet->clear();
|
||||
if (pc >= end())
|
||||
return false;
|
||||
|
||||
// Read instruction
|
||||
if (end() - pc < 1)
|
||||
return false;
|
||||
unsigned int opcode = *pc++;
|
||||
|
||||
// Immediate operand
|
||||
if (opcode <= OP_PUSHDATA4)
|
||||
{
|
||||
unsigned int nSize;
|
||||
if (opcode < OP_PUSHDATA1)
|
||||
{
|
||||
nSize = opcode;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA1)
|
||||
{
|
||||
if (end() - pc < 1)
|
||||
return false;
|
||||
nSize = *pc++;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA2)
|
||||
{
|
||||
if (end() - pc < 2)
|
||||
return false;
|
||||
nSize = 0;
|
||||
memcpy(&nSize, &pc[0], 2);
|
||||
pc += 2;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA4)
|
||||
{
|
||||
if (end() - pc < 4)
|
||||
return false;
|
||||
memcpy(&nSize, &pc[0], 4);
|
||||
pc += 4;
|
||||
}
|
||||
if (end() - pc < nSize)
|
||||
return false;
|
||||
if (pvchRet)
|
||||
pvchRet->assign(pc, pc + nSize);
|
||||
pc += nSize;
|
||||
}
|
||||
|
||||
opcodeRet = (opcodetype)opcode;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void FindAndDelete(const CScript& b)
|
||||
{
|
||||
if (b.empty())
|
||||
return;
|
||||
iterator pc = begin();
|
||||
opcodetype opcode;
|
||||
do
|
||||
{
|
||||
while (end() - pc >= b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
|
||||
erase(pc, pc + b.size());
|
||||
}
|
||||
while (GetOp(pc, opcode));
|
||||
}
|
||||
|
||||
|
||||
int GetSigOpCount() const
|
||||
{
|
||||
int n = 0;
|
||||
const_iterator pc = begin();
|
||||
while (pc < end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!GetOp(pc, opcode))
|
||||
break;
|
||||
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
|
||||
n++;
|
||||
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
|
||||
n += 20;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
bool IsPushOnly() const
|
||||
{
|
||||
if (size() > 200)
|
||||
return false;
|
||||
const_iterator pc = begin();
|
||||
while (pc < end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!GetOp(pc, opcode))
|
||||
return false;
|
||||
if (opcode > OP_16)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint160 GetBitcoinAddressHash160() const
|
||||
{
|
||||
opcodetype opcode;
|
||||
std::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;
|
||||
}
|
||||
|
||||
std::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 std::vector<unsigned char>& vchPubKey)
|
||||
{
|
||||
SetBitcoinAddress(Hash160(vchPubKey));
|
||||
}
|
||||
|
||||
bool SetBitcoinAddress(const std::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(), true).c_str());
|
||||
}
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
std::string str;
|
||||
opcodetype opcode;
|
||||
std::vector<unsigned char> vch;
|
||||
const_iterator pc = begin();
|
||||
while (pc < end())
|
||||
{
|
||||
if (!str.empty())
|
||||
str += " ";
|
||||
if (!GetOp(pc, opcode, vch))
|
||||
{
|
||||
str += "[error]";
|
||||
return str;
|
||||
}
|
||||
if (0 <= opcode && opcode <= OP_PUSHDATA4)
|
||||
str += ValueString(vch);
|
||||
else
|
||||
str += GetOpName(opcode);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void print() const
|
||||
{
|
||||
printf("%s\n", ToString().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
bool IsStandard(const CScript& scriptPubKey);
|
||||
bool IsMine(const CScript& scriptPubKey);
|
||||
bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, std::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);
|
||||
|
||||
#endif
|
||||
1271
src/serialize.h
Normal file
1271
src/serialize.h
Normal file
File diff suppressed because it is too large
Load Diff
86
src/strlcpy.h
Normal file
86
src/strlcpy.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef BITCOIN_STRLCPY_H
|
||||
#define BITCOIN_STRLCPY_H
|
||||
/*
|
||||
* 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 */
|
||||
}
|
||||
#endif
|
||||
765
src/uint256.h
Normal file
765
src/uint256.h
Normal file
@@ -0,0 +1,765 @@
|
||||
// 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.
|
||||
#ifndef BITCOIN_UINT256_H
|
||||
#define BITCOIN_UINT256_H
|
||||
|
||||
#include "serialize.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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(std::vector<std::string> vArg);
|
||||
|
||||
|
||||
|
||||
// We have to keep a separate base class without constructors
|
||||
// so the compiler will let us use it in a union
|
||||
template<unsigned int BITS>
|
||||
class base_uint
|
||||
{
|
||||
protected:
|
||||
enum { WIDTH=BITS/32 };
|
||||
unsigned int pn[WIDTH];
|
||||
public:
|
||||
|
||||
bool operator!() const
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
if (pn[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const base_uint operator~() const
|
||||
{
|
||||
base_uint ret;
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
ret.pn[i] = ~pn[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
const base_uint operator-() const
|
||||
{
|
||||
base_uint ret;
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
ret.pn[i] = ~pn[i];
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
base_uint& operator=(uint64 b)
|
||||
{
|
||||
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 std::string(psz, psz + sizeof(pn)*2);
|
||||
}
|
||||
|
||||
void SetHex(const char* psz)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = 0;
|
||||
|
||||
// skip leading spaces
|
||||
while (isspace(*psz))
|
||||
psz++;
|
||||
|
||||
// skip 0x
|
||||
if (psz[0] == '0' && tolower(psz[1]) == 'x')
|
||||
psz += 2;
|
||||
|
||||
// hex string to uint
|
||||
static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
|
||||
const char* pbegin = psz;
|
||||
while (phexdigit[*psz] || *psz == '0')
|
||||
psz++;
|
||||
psz--;
|
||||
unsigned char* p1 = (unsigned char*)pn;
|
||||
unsigned char* pend = p1 + WIDTH * 4;
|
||||
while (psz >= pbegin && p1 < pend)
|
||||
{
|
||||
*p1 = phexdigit[(unsigned char)*psz--];
|
||||
if (psz >= pbegin)
|
||||
{
|
||||
*p1 |= (phexdigit[(unsigned char)*psz--] << 4);
|
||||
p1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetHex(const std::string& str)
|
||||
{
|
||||
SetHex(str.c_str());
|
||||
}
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return (GetHex());
|
||||
}
|
||||
|
||||
unsigned char* begin()
|
||||
{
|
||||
return (unsigned char*)&pn[0];
|
||||
}
|
||||
|
||||
unsigned char* end()
|
||||
{
|
||||
return (unsigned char*)&pn[WIDTH];
|
||||
}
|
||||
|
||||
unsigned int size()
|
||||
{
|
||||
return sizeof(pn);
|
||||
}
|
||||
|
||||
|
||||
unsigned int GetSerializeSize(int nType=0, int nVersion=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(std::vector<std::string> vArg);
|
||||
};
|
||||
|
||||
typedef base_uint<160> base_uint160;
|
||||
typedef base_uint<256> base_uint256;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// uint160 and uint256 could be implemented as templates, but to keep
|
||||
// compile errors and debugging cleaner, they're copy and pasted.
|
||||
//
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// uint160
|
||||
//
|
||||
|
||||
class uint160 : public base_uint160
|
||||
{
|
||||
public:
|
||||
typedef base_uint160 basetype;
|
||||
|
||||
uint160()
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = 0;
|
||||
}
|
||||
|
||||
uint160(const basetype& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = b.pn[i];
|
||||
}
|
||||
|
||||
uint160& operator=(const basetype& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
pn[i] = b.pn[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint160(uint64 b)
|
||||
{
|
||||
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(std::vector<std::string> vArg)
|
||||
{
|
||||
uint256 g(0);
|
||||
|
||||
|
||||
printf("%s\n", g.ToString().c_str());
|
||||
g--; printf("g--\n");
|
||||
printf("%s\n", g.ToString().c_str());
|
||||
g--; printf("g--\n");
|
||||
printf("%s\n", g.ToString().c_str());
|
||||
g++; printf("g++\n");
|
||||
printf("%s\n", g.ToString().c_str());
|
||||
g++; printf("g++\n");
|
||||
printf("%s\n", g.ToString().c_str());
|
||||
g++; printf("g++\n");
|
||||
printf("%s\n", g.ToString().c_str());
|
||||
g++; printf("g++\n");
|
||||
printf("%s\n", g.ToString().c_str());
|
||||
|
||||
|
||||
|
||||
uint256 a(7);
|
||||
printf("a=7\n");
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
|
||||
uint256 b;
|
||||
printf("b undefined\n");
|
||||
printf("%s\n", b.ToString().c_str());
|
||||
int c = 3;
|
||||
|
||||
a = c;
|
||||
a.pn[3] = 15;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
uint256 k(c);
|
||||
|
||||
a = 5;
|
||||
a.pn[3] = 15;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
b = 1;
|
||||
b <<= 52;
|
||||
|
||||
a |= b;
|
||||
|
||||
a ^= 0x500;
|
||||
|
||||
printf("a %s\n", a.ToString().c_str());
|
||||
|
||||
a = a | b | (uint256)0x1000;
|
||||
|
||||
|
||||
printf("a %s\n", a.ToString().c_str());
|
||||
printf("b %s\n", b.ToString().c_str());
|
||||
|
||||
a = 0xfffffffe;
|
||||
a.pn[4] = 9;
|
||||
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
a++;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
a++;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
a++;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
a++;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
|
||||
a--;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
a--;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
a--;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
uint256 d = a--;
|
||||
printf("%s\n", d.ToString().c_str());
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
a--;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
a--;
|
||||
printf("%s\n", a.ToString().c_str());
|
||||
|
||||
d = a;
|
||||
|
||||
printf("%s\n", d.ToString().c_str());
|
||||
for (int i = uint256::WIDTH-1; i >= 0; i--) printf("%08x", d.pn[i]); printf("\n");
|
||||
|
||||
uint256 neg = d;
|
||||
neg = ~neg;
|
||||
printf("%s\n", neg.ToString().c_str());
|
||||
|
||||
|
||||
uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111");
|
||||
printf("\n");
|
||||
printf("%s\n", e.ToString().c_str());
|
||||
|
||||
|
||||
printf("\n");
|
||||
uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111");
|
||||
uint256 x2;
|
||||
printf("%s\n", x1.ToString().c_str());
|
||||
for (int i = 0; i < 270; i += 4)
|
||||
{
|
||||
x2 = x1 << i;
|
||||
printf("%s\n", x2.ToString().c_str());
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("%s\n", x1.ToString().c_str());
|
||||
for (int i = 0; i < 270; i += 4)
|
||||
{
|
||||
x2 = x1;
|
||||
x2 >>= i;
|
||||
printf("%s\n", x2.ToString().c_str());
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
uint256 k = (~uint256(0) >> i);
|
||||
printf("%s\n", k.ToString().c_str());
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
uint256 k = (~uint256(0) << i);
|
||||
printf("%s\n", k.ToString().c_str());
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
||||
906
src/util.cpp
Normal file
906
src/util.cpp
Normal file
@@ -0,0 +1,906 @@
|
||||
// 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"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
map<string, string> mapArgs;
|
||||
map<string, vector<string> > mapMultiArgs;
|
||||
bool fDebug = false;
|
||||
bool fPrintToConsole = false;
|
||||
bool fPrintToDebugger = false;
|
||||
char pszSetDataDir[MAX_PATH] = "";
|
||||
bool fRequestShutdown = false;
|
||||
bool fShutdown = false;
|
||||
bool fDaemon = false;
|
||||
bool fServer = false;
|
||||
bool fCommandLine = false;
|
||||
string strMiscWarning;
|
||||
bool fTestNet = false;
|
||||
bool fNoListen = false;
|
||||
bool fLogTimestamps = false;
|
||||
|
||||
|
||||
|
||||
|
||||
// Workaround for "multiple definition of `_tls_used'"
|
||||
// http://svn.boost.org/trac/boost/ticket/4258
|
||||
extern "C" void tss_cleanup_implemented() { }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Init openssl library multithreading support
|
||||
static boost::interprocess::interprocess_mutex** ppmutexOpenSSL;
|
||||
void locking_callback(int mode, int i, const char* file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
ppmutexOpenSSL[i]->lock();
|
||||
else
|
||||
ppmutexOpenSSL[i]->unlock();
|
||||
}
|
||||
|
||||
// Init
|
||||
class CInit
|
||||
{
|
||||
public:
|
||||
CInit()
|
||||
{
|
||||
// Init openssl library multithreading support
|
||||
ppmutexOpenSSL = (boost::interprocess::interprocess_mutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(boost::interprocess::interprocess_mutex*));
|
||||
for (int i = 0; i < CRYPTO_num_locks(); i++)
|
||||
ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex();
|
||||
CRYPTO_set_locking_callback(locking_callback);
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// Seed random number generator with screen scrape and other hardware sources
|
||||
RAND_screen();
|
||||
#endif
|
||||
|
||||
// Seed random number generator with performance counter
|
||||
RandAddSeed();
|
||||
}
|
||||
~CInit()
|
||||
{
|
||||
// Shutdown openssl library multithreading support
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for (int i = 0; i < CRYPTO_num_locks(); i++)
|
||||
delete ppmutexOpenSSL[i];
|
||||
OPENSSL_free(ppmutexOpenSSL);
|
||||
}
|
||||
}
|
||||
instance_of_cinit;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void RandAddSeed()
|
||||
{
|
||||
// Seed with CPU performance counter
|
||||
int64 nCounter = GetPerformanceCounter();
|
||||
RAND_add(&nCounter, sizeof(nCounter), 1.5);
|
||||
memset(&nCounter, 0, sizeof(nCounter));
|
||||
}
|
||||
|
||||
void RandAddSeedPerfmon()
|
||||
{
|
||||
RandAddSeed();
|
||||
|
||||
// This can take up to 2 seconds, so only do it every 10 minutes
|
||||
static int64 nLastPerfmon;
|
||||
if (GetTime() < nLastPerfmon + 10 * 60)
|
||||
return;
|
||||
nLastPerfmon = GetTime();
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
|
||||
// Seed with the entire set of perfmon data
|
||||
unsigned char pdata[250000];
|
||||
memset(pdata, 0, sizeof(pdata));
|
||||
unsigned long nSize = sizeof(pdata);
|
||||
long ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
|
||||
RegCloseKey(HKEY_PERFORMANCE_DATA);
|
||||
if (ret == ERROR_SUCCESS)
|
||||
{
|
||||
RAND_add(pdata, nSize, nSize/100.0);
|
||||
memset(pdata, 0, nSize);
|
||||
printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64 GetRand(uint64 nMax)
|
||||
{
|
||||
if (nMax == 0)
|
||||
return 0;
|
||||
|
||||
// The range of the random source must be a multiple of the modulus
|
||||
// to give every possible output value an equal possibility
|
||||
uint64 nRange = (UINT64_MAX / nMax) * nMax;
|
||||
uint64 nRand = 0;
|
||||
do
|
||||
RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
|
||||
while (nRand >= nRange);
|
||||
return (nRand % nMax);
|
||||
}
|
||||
|
||||
int GetRandInt(int nMax)
|
||||
{
|
||||
return GetRand(nMax);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline int OutputDebugStringF(const char* pszFormat, ...)
|
||||
{
|
||||
int ret = 0;
|
||||
if (fPrintToConsole)
|
||||
{
|
||||
// print to console
|
||||
va_list arg_ptr;
|
||||
va_start(arg_ptr, pszFormat);
|
||||
ret = vprintf(pszFormat, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// print to debug.log
|
||||
static FILE* fileout = NULL;
|
||||
|
||||
if (!fileout)
|
||||
{
|
||||
char pszFile[MAX_PATH+100];
|
||||
GetDataDir(pszFile);
|
||||
strlcat(pszFile, "/debug.log", sizeof(pszFile));
|
||||
fileout = fopen(pszFile, "a");
|
||||
if (fileout) setbuf(fileout, NULL); // unbuffered
|
||||
}
|
||||
if (fileout)
|
||||
{
|
||||
static bool fStartedNewLine = true;
|
||||
|
||||
// Debug print useful for profiling
|
||||
if (fLogTimestamps && fStartedNewLine)
|
||||
fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
|
||||
if (pszFormat[strlen(pszFormat) - 1] == '\n')
|
||||
fStartedNewLine = true;
|
||||
else
|
||||
fStartedNewLine = false;
|
||||
|
||||
va_list arg_ptr;
|
||||
va_start(arg_ptr, pszFormat);
|
||||
ret = vfprintf(fileout, pszFormat, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __WXMSW__
|
||||
if (fPrintToDebugger)
|
||||
{
|
||||
static CCriticalSection cs_OutputDebugStringF;
|
||||
|
||||
// accumulate a line at a time
|
||||
CRITICAL_BLOCK(cs_OutputDebugStringF)
|
||||
{
|
||||
static char pszBuffer[50000];
|
||||
static char* pend;
|
||||
if (pend == NULL)
|
||||
pend = pszBuffer;
|
||||
va_list arg_ptr;
|
||||
va_start(arg_ptr, pszFormat);
|
||||
int limit = END(pszBuffer) - pend - 2;
|
||||
int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
if (ret < 0 || ret >= limit)
|
||||
{
|
||||
pend = END(pszBuffer) - 2;
|
||||
*pend++ = '\n';
|
||||
}
|
||||
else
|
||||
pend += ret;
|
||||
*pend = '\0';
|
||||
char* p1 = pszBuffer;
|
||||
char* p2;
|
||||
while (p2 = strchr(p1, '\n'))
|
||||
{
|
||||
p2++;
|
||||
char c = *p2;
|
||||
*p2 = '\0';
|
||||
OutputDebugStringA(p1);
|
||||
*p2 = c;
|
||||
p1 = p2;
|
||||
}
|
||||
if (p1 != pszBuffer)
|
||||
memmove(pszBuffer, p1, pend - p1 + 1);
|
||||
pend -= (p1 - pszBuffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Safer snprintf
|
||||
// - prints up to limit-1 characters
|
||||
// - output string is always null terminated even if limit reached
|
||||
// - return value is the number of characters actually printed
|
||||
int my_snprintf(char* buffer, size_t limit, const char* format, ...)
|
||||
{
|
||||
if (limit == 0)
|
||||
return 0;
|
||||
va_list arg_ptr;
|
||||
va_start(arg_ptr, format);
|
||||
int ret = _vsnprintf(buffer, limit, format, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
if (ret < 0 || ret >= limit)
|
||||
{
|
||||
ret = limit - 1;
|
||||
buffer[limit-1] = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
string strprintf(const char* format, ...)
|
||||
{
|
||||
char buffer[50000];
|
||||
char* p = buffer;
|
||||
int limit = sizeof(buffer);
|
||||
int ret;
|
||||
loop
|
||||
{
|
||||
va_list arg_ptr;
|
||||
va_start(arg_ptr, format);
|
||||
ret = _vsnprintf(p, limit, format, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
if (ret >= 0 && ret < limit)
|
||||
break;
|
||||
if (p != buffer)
|
||||
delete[] p;
|
||||
limit *= 2;
|
||||
p = new char[limit];
|
||||
if (p == NULL)
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
string str(p, p+ret);
|
||||
if (p != buffer)
|
||||
delete[] p;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
bool error(const char* format, ...)
|
||||
{
|
||||
char buffer[50000];
|
||||
int limit = sizeof(buffer);
|
||||
va_list arg_ptr;
|
||||
va_start(arg_ptr, format);
|
||||
int ret = _vsnprintf(buffer, limit, format, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
if (ret < 0 || ret >= limit)
|
||||
{
|
||||
ret = limit - 1;
|
||||
buffer[limit-1] = 0;
|
||||
}
|
||||
printf("ERROR: %s\n", buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ParseString(const string& str, char c, vector<string>& v)
|
||||
{
|
||||
if (str.empty())
|
||||
return;
|
||||
string::size_type i1 = 0;
|
||||
string::size_type i2;
|
||||
loop
|
||||
{
|
||||
i2 = str.find(c, i1);
|
||||
if (i2 == str.npos)
|
||||
{
|
||||
v.push_back(str.substr(i1));
|
||||
return;
|
||||
}
|
||||
v.push_back(str.substr(i1, i2-i1));
|
||||
i1 = i2+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string FormatMoney(int64 n, bool fPlus)
|
||||
{
|
||||
// Note: not using straight sprintf here because we do NOT want
|
||||
// localized number formatting.
|
||||
int64 n_abs = (n > 0 ? n : -n);
|
||||
int64 quotient = n_abs/COIN;
|
||||
int64 remainder = n_abs%COIN;
|
||||
string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder);
|
||||
|
||||
// Right-trim excess 0's before the decimal point:
|
||||
int nTrim = 0;
|
||||
for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)
|
||||
++nTrim;
|
||||
if (nTrim)
|
||||
str.erase(str.size()-nTrim, nTrim);
|
||||
|
||||
// Insert thousands-separators:
|
||||
size_t point = str.find(".");
|
||||
for (int i = (str.size()-point)+3; i < str.size(); i += 4)
|
||||
if (isdigit(str[str.size() - i - 1]))
|
||||
str.insert(str.size() - i, 1, ',');
|
||||
if (n < 0)
|
||||
str.insert((unsigned int)0, 1, '-');
|
||||
else if (fPlus && n > 0)
|
||||
str.insert((unsigned int)0, 1, '+');
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
bool ParseMoney(const string& str, int64& nRet)
|
||||
{
|
||||
return ParseMoney(str.c_str(), nRet);
|
||||
}
|
||||
|
||||
bool ParseMoney(const char* pszIn, int64& nRet)
|
||||
{
|
||||
string strWhole;
|
||||
int64 nUnits = 0;
|
||||
const char* p = pszIn;
|
||||
while (isspace(*p))
|
||||
p++;
|
||||
for (; *p; p++)
|
||||
{
|
||||
if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))
|
||||
continue;
|
||||
if (*p == '.')
|
||||
{
|
||||
p++;
|
||||
int64 nMult = CENT*10;
|
||||
while (isdigit(*p) && (nMult > 0))
|
||||
{
|
||||
nUnits += nMult * (*p++ - '0');
|
||||
nMult /= 10;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isspace(*p))
|
||||
break;
|
||||
if (!isdigit(*p))
|
||||
return false;
|
||||
strWhole.insert(strWhole.end(), *p);
|
||||
}
|
||||
for (; *p; p++)
|
||||
if (!isspace(*p))
|
||||
return false;
|
||||
if (strWhole.size() > 14)
|
||||
return false;
|
||||
if (nUnits < 0 || nUnits > COIN)
|
||||
return false;
|
||||
int64 nWhole = atoi64(strWhole);
|
||||
int64 nValue = nWhole*COIN + nUnits;
|
||||
|
||||
nRet = nValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
vector<unsigned char> ParseHex(const char* psz)
|
||||
{
|
||||
static char phexdigit[256] =
|
||||
{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
|
||||
-1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
|
||||
|
||||
// convert hex dump to vector
|
||||
vector<unsigned char> vch;
|
||||
loop
|
||||
{
|
||||
while (isspace(*psz))
|
||||
psz++;
|
||||
char c = phexdigit[(unsigned char)*psz++];
|
||||
if (c == (char)-1)
|
||||
break;
|
||||
unsigned char n = (c << 4);
|
||||
c = phexdigit[(unsigned char)*psz++];
|
||||
if (c == (char)-1)
|
||||
break;
|
||||
n |= c;
|
||||
vch.push_back(n);
|
||||
}
|
||||
return vch;
|
||||
}
|
||||
|
||||
vector<unsigned char> ParseHex(const string& str)
|
||||
{
|
||||
return ParseHex(str.c_str());
|
||||
}
|
||||
|
||||
|
||||
void ParseParameters(int argc, char* argv[])
|
||||
{
|
||||
mapArgs.clear();
|
||||
mapMultiArgs.clear();
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
char psz[10000];
|
||||
strlcpy(psz, argv[i], sizeof(psz));
|
||||
char* pszValue = (char*)"";
|
||||
if (strchr(psz, '='))
|
||||
{
|
||||
pszValue = strchr(psz, '=');
|
||||
*pszValue++ = '\0';
|
||||
}
|
||||
#ifdef __WXMSW__
|
||||
_strlwr(psz);
|
||||
if (psz[0] == '/')
|
||||
psz[0] = '-';
|
||||
#endif
|
||||
if (psz[0] != '-')
|
||||
break;
|
||||
mapArgs[psz] = pszValue;
|
||||
mapMultiArgs[psz].push_back(pszValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char* wxGetTranslation(const char* pszEnglish)
|
||||
{
|
||||
#ifdef GUI
|
||||
// Wrapper of wxGetTranslation returning the same const char* type as was passed in
|
||||
static CCriticalSection cs;
|
||||
CRITICAL_BLOCK(cs)
|
||||
{
|
||||
// Look in cache
|
||||
static map<string, char*> mapCache;
|
||||
map<string, char*>::iterator mi = mapCache.find(pszEnglish);
|
||||
if (mi != mapCache.end())
|
||||
return (*mi).second;
|
||||
|
||||
// wxWidgets translation
|
||||
wxString strTranslated = wxGetTranslation(wxString(pszEnglish, wxConvUTF8));
|
||||
|
||||
// We don't cache unknown strings because caller might be passing in a
|
||||
// dynamic string and we would keep allocating memory for each variation.
|
||||
if (strcmp(pszEnglish, strTranslated.utf8_str()) == 0)
|
||||
return pszEnglish;
|
||||
|
||||
// Add to cache, memory doesn't need to be freed. We only cache because
|
||||
// we must pass back a pointer to permanently allocated memory.
|
||||
char* pszCached = new char[strlen(strTranslated.utf8_str())+1];
|
||||
strcpy(pszCached, strTranslated.utf8_str());
|
||||
mapCache[pszEnglish] = pszCached;
|
||||
return pszCached;
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
return pszEnglish;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool WildcardMatch(const char* psz, const char* mask)
|
||||
{
|
||||
loop
|
||||
{
|
||||
switch (*mask)
|
||||
{
|
||||
case '\0':
|
||||
return (*psz == '\0');
|
||||
case '*':
|
||||
return WildcardMatch(psz, mask+1) || (*psz && WildcardMatch(psz+1, mask));
|
||||
case '?':
|
||||
if (*psz == '\0')
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
if (*psz != *mask)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
psz++;
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
|
||||
bool WildcardMatch(const string& str, const string& mask)
|
||||
{
|
||||
return WildcardMatch(str.c_str(), mask.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
char pszModule[MAX_PATH];
|
||||
pszModule[0] = '\0';
|
||||
GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
|
||||
#else
|
||||
const char* pszModule = "bitcoin";
|
||||
#endif
|
||||
if (pex)
|
||||
snprintf(pszMessage, 1000,
|
||||
"EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
|
||||
else
|
||||
snprintf(pszMessage, 1000,
|
||||
"UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
|
||||
}
|
||||
|
||||
void LogException(std::exception* pex, const char* pszThread)
|
||||
{
|
||||
char pszMessage[10000];
|
||||
FormatException(pszMessage, pex, pszThread);
|
||||
printf("\n%s", pszMessage);
|
||||
}
|
||||
|
||||
void PrintException(std::exception* pex, const char* pszThread)
|
||||
{
|
||||
char pszMessage[10000];
|
||||
FormatException(pszMessage, pex, pszThread);
|
||||
printf("\n\n************************\n%s\n", pszMessage);
|
||||
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
|
||||
strMiscWarning = pszMessage;
|
||||
#ifdef GUI
|
||||
if (wxTheApp && !fDaemon)
|
||||
MyMessageBox(pszMessage, "Bitcoin", wxOK | wxICON_ERROR);
|
||||
#endif
|
||||
throw;
|
||||
}
|
||||
|
||||
void ThreadOneMessageBox(string strMessage)
|
||||
{
|
||||
// Skip message boxes if one is already open
|
||||
static bool fMessageBoxOpen;
|
||||
if (fMessageBoxOpen)
|
||||
return;
|
||||
fMessageBoxOpen = true;
|
||||
ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
|
||||
fMessageBoxOpen = false;
|
||||
}
|
||||
|
||||
void PrintExceptionContinue(std::exception* pex, const char* pszThread)
|
||||
{
|
||||
char pszMessage[10000];
|
||||
FormatException(pszMessage, pex, pszThread);
|
||||
printf("\n\n************************\n%s\n", pszMessage);
|
||||
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
|
||||
strMiscWarning = pszMessage;
|
||||
#ifdef GUI
|
||||
if (wxTheApp && !fDaemon)
|
||||
boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#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 isn't always available on old Windows versions
|
||||
HMODULE hShell32 = LoadLibraryA("shell32.dll");
|
||||
if (hShell32)
|
||||
{
|
||||
PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
|
||||
(PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
|
||||
if (pSHGetSpecialFolderPath)
|
||||
(*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
|
||||
FreeModule(hShell32);
|
||||
}
|
||||
|
||||
// Backup option
|
||||
if (pszPath[0] == '\0')
|
||||
{
|
||||
if (nFolder == CSIDL_STARTUP)
|
||||
{
|
||||
strcpy(pszPath, getenv("USERPROFILE"));
|
||||
strcat(pszPath, "\\Start Menu\\Programs\\Startup");
|
||||
}
|
||||
else if (nFolder == CSIDL_APPDATA)
|
||||
{
|
||||
strcpy(pszPath, getenv("APPDATA"));
|
||||
}
|
||||
}
|
||||
|
||||
return pszPath;
|
||||
}
|
||||
#endif
|
||||
|
||||
string GetDefaultDataDir()
|
||||
{
|
||||
// Windows: C:\Documents and Settings\username\Application Data\Bitcoin
|
||||
// Mac: ~/Library/Application Support/Bitcoin
|
||||
// Unix: ~/.bitcoin
|
||||
#ifdef __WXMSW__
|
||||
// Windows
|
||||
return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
|
||||
#else
|
||||
char* pszHome = getenv("HOME");
|
||||
if (pszHome == NULL || strlen(pszHome) == 0)
|
||||
pszHome = (char*)"/";
|
||||
string strHome = pszHome;
|
||||
if (strHome[strHome.size()-1] != '/')
|
||||
strHome += '/';
|
||||
#ifdef __WXMAC_OSX__
|
||||
// Mac
|
||||
strHome += "Library/Application Support/";
|
||||
filesystem::create_directory(strHome.c_str());
|
||||
return strHome + "Bitcoin";
|
||||
#else
|
||||
// Unix
|
||||
return strHome + ".bitcoin";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetDataDir(char* pszDir)
|
||||
{
|
||||
// pszDir must be at least MAX_PATH length.
|
||||
int nVariation;
|
||||
if (pszSetDataDir[0] != 0)
|
||||
{
|
||||
strlcpy(pszDir, pszSetDataDir, MAX_PATH);
|
||||
nVariation = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This can be called during exceptions by printf, so we cache the
|
||||
// value so we don't have to do memory allocations after that.
|
||||
static char pszCachedDir[MAX_PATH];
|
||||
if (pszCachedDir[0] == 0)
|
||||
strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
|
||||
strlcpy(pszDir, pszCachedDir, MAX_PATH);
|
||||
nVariation = 1;
|
||||
}
|
||||
if (fTestNet)
|
||||
{
|
||||
char* p = pszDir + strlen(pszDir);
|
||||
if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
|
||||
*p++ = '/';
|
||||
strcpy(p, "testnet");
|
||||
nVariation += 2;
|
||||
}
|
||||
static bool pfMkdir[4];
|
||||
if (!pfMkdir[nVariation])
|
||||
{
|
||||
pfMkdir[nVariation] = true;
|
||||
boost::filesystem::create_directory(pszDir);
|
||||
}
|
||||
}
|
||||
|
||||
string GetDataDir()
|
||||
{
|
||||
char pszDir[MAX_PATH];
|
||||
GetDataDir(pszDir);
|
||||
return pszDir;
|
||||
}
|
||||
|
||||
string GetConfigFile()
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
|
||||
if (!pathConfig.is_complete())
|
||||
pathConfig = fs::path(GetDataDir()) / pathConfig;
|
||||
return pathConfig.string();
|
||||
}
|
||||
|
||||
void ReadConfigFile(map<string, string>& mapSettingsRet,
|
||||
map<string, vector<string> >& mapMultiSettingsRet)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
namespace pod = boost::program_options::detail;
|
||||
|
||||
fs::ifstream streamConfig(GetConfigFile());
|
||||
if (!streamConfig.good())
|
||||
return;
|
||||
|
||||
set<string> setOptions;
|
||||
setOptions.insert("*");
|
||||
|
||||
for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
|
||||
{
|
||||
// Don't overwrite existing settings so command line settings override bitcoin.conf
|
||||
string strKey = string("-") + it->string_key;
|
||||
if (mapSettingsRet.count(strKey) == 0)
|
||||
mapSettingsRet[strKey] = it->value[0];
|
||||
mapMultiSettingsRet[strKey].push_back(it->value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
string GetPidFile()
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
|
||||
if (!pathConfig.is_complete())
|
||||
pathConfig = fs::path(GetDataDir()) / pathConfig;
|
||||
return pathConfig.string();
|
||||
}
|
||||
|
||||
void CreatePidFile(string pidFile, pid_t pid)
|
||||
{
|
||||
FILE* file;
|
||||
if (file = fopen(pidFile.c_str(), "w"))
|
||||
{
|
||||
fprintf(file, "%d\n", pid);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
int GetFilesize(FILE* file)
|
||||
{
|
||||
int nSavePos = ftell(file);
|
||||
int nFilesize = -1;
|
||||
if (fseek(file, 0, SEEK_END) == 0)
|
||||
nFilesize = ftell(file);
|
||||
fseek(file, nSavePos, SEEK_SET);
|
||||
return nFilesize;
|
||||
}
|
||||
|
||||
void ShrinkDebugFile()
|
||||
{
|
||||
// Scroll debug.log if it's getting too big
|
||||
string strFile = GetDataDir() + "/debug.log";
|
||||
FILE* file = fopen(strFile.c_str(), "r");
|
||||
if (file && GetFilesize(file) > 10 * 1000000)
|
||||
{
|
||||
// Restart the file with some of the end
|
||||
char pch[200000];
|
||||
fseek(file, -sizeof(pch), SEEK_END);
|
||||
int nBytes = fread(pch, 1, sizeof(pch), file);
|
||||
fclose(file);
|
||||
if (file = fopen(strFile.c_str(), "w"))
|
||||
{
|
||||
fwrite(pch, 1, nBytes, file);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// "Never go to sea with two chronometers; take one or three."
|
||||
// Our three time sources are:
|
||||
// - System clock
|
||||
// - Median of other nodes's clocks
|
||||
// - The user (asking the user to fix the system clock if the first two disagree)
|
||||
//
|
||||
int64 GetTime()
|
||||
{
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
static int64 nTimeOffset = 0;
|
||||
|
||||
int64 GetAdjustedTime()
|
||||
{
|
||||
return GetTime() + nTimeOffset;
|
||||
}
|
||||
|
||||
void AddTimeData(unsigned int ip, int64 nTime)
|
||||
{
|
||||
int64 nOffsetSample = nTime - GetTime();
|
||||
|
||||
// Ignore duplicates
|
||||
static set<unsigned int> setKnown;
|
||||
if (!setKnown.insert(ip).second)
|
||||
return;
|
||||
|
||||
// Add data
|
||||
static vector<int64> vTimeOffsets;
|
||||
if (vTimeOffsets.empty())
|
||||
vTimeOffsets.push_back(0);
|
||||
vTimeOffsets.push_back(nOffsetSample);
|
||||
printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
|
||||
if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
|
||||
{
|
||||
sort(vTimeOffsets.begin(), vTimeOffsets.end());
|
||||
int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
|
||||
// Only let other nodes change our time by so much
|
||||
if (abs64(nMedian) < 70 * 60)
|
||||
{
|
||||
nTimeOffset = nMedian;
|
||||
}
|
||||
else
|
||||
{
|
||||
nTimeOffset = 0;
|
||||
|
||||
static bool fDone;
|
||||
if (!fDone)
|
||||
{
|
||||
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
|
||||
bool fMatch = false;
|
||||
BOOST_FOREACH(int64 nOffset, vTimeOffsets)
|
||||
if (nOffset != 0 && abs64(nOffset) < 5 * 60)
|
||||
fMatch = true;
|
||||
|
||||
if (!fMatch)
|
||||
{
|
||||
fDone = true;
|
||||
string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.");
|
||||
strMiscWarning = strMessage;
|
||||
printf("*** %s\n", strMessage.c_str());
|
||||
boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(int64 n, vTimeOffsets)
|
||||
printf("%+"PRI64d" ", n);
|
||||
printf("| nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
string FormatVersion(int nVersion)
|
||||
{
|
||||
if (nVersion%100 == 0)
|
||||
return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100);
|
||||
else
|
||||
return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100);
|
||||
}
|
||||
|
||||
string FormatFullVersion()
|
||||
{
|
||||
string s = FormatVersion(VERSION) + pszSubVer;
|
||||
if (VERSION_IS_BETA)
|
||||
s += _("-beta");
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
680
src/util.h
Normal file
680
src/util.h
Normal file
@@ -0,0 +1,680 @@
|
||||
// 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.
|
||||
#ifndef BITCOIN_UTIL_H
|
||||
#define BITCOIN_UTIL_H
|
||||
|
||||
#include "uint256.h"
|
||||
|
||||
#ifndef __WXMSW__
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian_types.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/ripemd.h>
|
||||
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
#else
|
||||
typedef long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1300
|
||||
#define for if (false) ; else for
|
||||
#endif
|
||||
#ifndef _MSC_VER
|
||||
#define __forceinline inline
|
||||
#endif
|
||||
|
||||
#define loop for (;;)
|
||||
#define BEGIN(a) ((char*)&(a))
|
||||
#define END(a) ((char*)&((&(a))[1]))
|
||||
#define UBEGIN(a) ((unsigned char*)&(a))
|
||||
#define UEND(a) ((unsigned char*)&((&(a))[1]))
|
||||
#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
|
||||
#define printf OutputDebugStringF
|
||||
|
||||
#ifdef snprintf
|
||||
#undef snprintf
|
||||
#endif
|
||||
#define snprintf my_snprintf
|
||||
|
||||
#ifndef PRI64d
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MSVCRT__)
|
||||
#define PRI64d "I64d"
|
||||
#define PRI64u "I64u"
|
||||
#define PRI64x "I64x"
|
||||
#else
|
||||
#define PRI64d "lld"
|
||||
#define PRI64u "llu"
|
||||
#define PRI64x "llx"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This is needed because the foreach macro can't get over the comma in pair<t1, t2>
|
||||
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
|
||||
|
||||
// Used to bypass the rule against non-const reference to temporary
|
||||
// where it makes sense with wrappers such as CFlatData or CTxDB
|
||||
template<typename T>
|
||||
inline T& REF(const T& val)
|
||||
{
|
||||
return (T&)val;
|
||||
}
|
||||
|
||||
// Align by increasing pointer, must have extra space at end of buffer
|
||||
template <size_t nBytes, typename T>
|
||||
T* alignup(T* p)
|
||||
{
|
||||
union
|
||||
{
|
||||
T* ptr;
|
||||
size_t n;
|
||||
} u;
|
||||
u.ptr = p;
|
||||
u.n = (u.n + (nBytes-1)) & ~(nBytes-1);
|
||||
return u.ptr;
|
||||
}
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#define MSG_NOSIGNAL 0
|
||||
#define MSG_DONTWAIT 0
|
||||
#ifndef UINT64_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define INT64_MIN _I64_MIN
|
||||
#endif
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR 0400
|
||||
#define S_IWUSR 0200
|
||||
#endif
|
||||
#define unlink _unlink
|
||||
typedef int socklen_t;
|
||||
#else
|
||||
#define WSAGetLastError() errno
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define WSAEMSGSIZE EMSGSIZE
|
||||
#define WSAEINTR EINTR
|
||||
#define WSAEINPROGRESS EINPROGRESS
|
||||
#define WSAEADDRINUSE EADDRINUSE
|
||||
#define WSAENOTSOCK EBADF
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#define SOCKET_ERROR -1
|
||||
typedef u_int SOCKET;
|
||||
#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
|
||||
#define strlwr(psz) to_lower(psz)
|
||||
#define _strlwr(psz) to_lower(psz)
|
||||
#define MAX_PATH 1024
|
||||
#define Beep(n1,n2) (0)
|
||||
inline void Sleep(int64 n)
|
||||
{
|
||||
boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(n));
|
||||
}
|
||||
#endif
|
||||
|
||||
inline int myclosesocket(SOCKET& hSocket)
|
||||
{
|
||||
if (hSocket == INVALID_SOCKET)
|
||||
return WSAENOTSOCK;
|
||||
#ifdef __WXMSW__
|
||||
int ret = closesocket(hSocket);
|
||||
#else
|
||||
int ret = close(hSocket);
|
||||
#endif
|
||||
hSocket = INVALID_SOCKET;
|
||||
return ret;
|
||||
}
|
||||
#define closesocket(s) myclosesocket(s)
|
||||
|
||||
#ifndef GUI
|
||||
inline const char* _(const char* psz)
|
||||
{
|
||||
return psz;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern std::map<std::string, std::string> mapArgs;
|
||||
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
|
||||
extern bool fDebug;
|
||||
extern bool fPrintToConsole;
|
||||
extern bool fPrintToDebugger;
|
||||
extern char pszSetDataDir[MAX_PATH];
|
||||
extern bool fRequestShutdown;
|
||||
extern bool fShutdown;
|
||||
extern bool fDaemon;
|
||||
extern bool fServer;
|
||||
extern bool fCommandLine;
|
||||
extern std::string strMiscWarning;
|
||||
extern bool fTestNet;
|
||||
extern bool fNoListen;
|
||||
extern bool fLogTimestamps;
|
||||
|
||||
void RandAddSeed();
|
||||
void RandAddSeedPerfmon();
|
||||
int OutputDebugStringF(const char* pszFormat, ...);
|
||||
int my_snprintf(char* buffer, size_t limit, const char* format, ...);
|
||||
std::string strprintf(const char* format, ...);
|
||||
bool error(const char* format, ...);
|
||||
void LogException(std::exception* pex, const char* pszThread);
|
||||
void PrintException(std::exception* pex, const char* pszThread);
|
||||
void PrintExceptionContinue(std::exception* pex, const char* pszThread);
|
||||
void ParseString(const std::string& str, char c, std::vector<std::string>& v);
|
||||
std::string FormatMoney(int64 n, bool fPlus=false);
|
||||
bool ParseMoney(const std::string& str, int64& nRet);
|
||||
bool ParseMoney(const char* pszIn, int64& nRet);
|
||||
std::vector<unsigned char> ParseHex(const char* psz);
|
||||
std::vector<unsigned char> ParseHex(const std::string& str);
|
||||
void ParseParameters(int argc, char* argv[]);
|
||||
const char* wxGetTranslation(const char* psz);
|
||||
bool WildcardMatch(const char* psz, const char* mask);
|
||||
bool WildcardMatch(const std::string& str, const std::string& mask);
|
||||
int GetFilesize(FILE* file);
|
||||
void GetDataDir(char* pszDirRet);
|
||||
std::string GetConfigFile();
|
||||
std::string GetPidFile();
|
||||
void CreatePidFile(std::string pidFile, pid_t pid);
|
||||
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
|
||||
#ifdef __WXMSW__
|
||||
std::string MyGetSpecialFolderPath(int nFolder, bool fCreate);
|
||||
#endif
|
||||
std::string GetDefaultDataDir();
|
||||
std::string GetDataDir();
|
||||
void ShrinkDebugFile();
|
||||
int GetRandInt(int nMax);
|
||||
uint64 GetRand(uint64 nMax);
|
||||
int64 GetTime();
|
||||
int64 GetAdjustedTime();
|
||||
void AddTimeData(unsigned int ip, int64 nTime);
|
||||
std::string FormatFullVersion();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Wrapper to automatically initialize critical sections
|
||||
class CCriticalSection
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
protected:
|
||||
CRITICAL_SECTION cs;
|
||||
public:
|
||||
explicit CCriticalSection() { InitializeCriticalSection(&cs); }
|
||||
~CCriticalSection() { DeleteCriticalSection(&cs); }
|
||||
void Enter() { EnterCriticalSection(&cs); }
|
||||
void Leave() { LeaveCriticalSection(&cs); }
|
||||
bool TryEnter() { return TryEnterCriticalSection(&cs); }
|
||||
#else
|
||||
protected:
|
||||
boost::interprocess::interprocess_recursive_mutex mutex;
|
||||
public:
|
||||
explicit CCriticalSection() { }
|
||||
~CCriticalSection() { }
|
||||
void Enter() { mutex.lock(); }
|
||||
void Leave() { mutex.unlock(); }
|
||||
bool TryEnter() { return mutex.try_lock(); }
|
||||
#endif
|
||||
public:
|
||||
const char* pszFile;
|
||||
int nLine;
|
||||
};
|
||||
|
||||
// Automatically leave critical section when leaving block, needed for exception safety
|
||||
class CCriticalBlock
|
||||
{
|
||||
protected:
|
||||
CCriticalSection* pcs;
|
||||
public:
|
||||
CCriticalBlock(CCriticalSection& csIn) { pcs = &csIn; pcs->Enter(); }
|
||||
~CCriticalBlock() { pcs->Leave(); }
|
||||
};
|
||||
|
||||
// WARNING: This will catch continue and break!
|
||||
// break is caught with an assertion, but there's no way to detect continue.
|
||||
// I'd rather be careful than suffer the other more error prone syntax.
|
||||
// The compiler will optimise away all this loop junk.
|
||||
#define CRITICAL_BLOCK(cs) \
|
||||
for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \
|
||||
for (CCriticalBlock criticalblock(cs); fcriticalblockonce && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
|
||||
|
||||
class CTryCriticalBlock
|
||||
{
|
||||
protected:
|
||||
CCriticalSection* pcs;
|
||||
public:
|
||||
CTryCriticalBlock(CCriticalSection& csIn) { pcs = (csIn.TryEnter() ? &csIn : NULL); }
|
||||
~CTryCriticalBlock() { if (pcs) pcs->Leave(); }
|
||||
bool Entered() { return pcs != NULL; }
|
||||
};
|
||||
|
||||
#define TRY_CRITICAL_BLOCK(cs) \
|
||||
for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by TRY_CRITICAL_BLOCK!", !fcriticalblockonce)), fcriticalblockonce=false) \
|
||||
for (CTryCriticalBlock criticalblock(cs); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()) && (cs.pszFile=__FILE__, cs.nLine=__LINE__, true); fcriticalblockonce=false, cs.pszFile=NULL, cs.nLine=0)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline std::string i64tostr(int64 n)
|
||||
{
|
||||
return strprintf("%"PRI64d, n);
|
||||
}
|
||||
|
||||
inline std::string itostr(int n)
|
||||
{
|
||||
return strprintf("%d", n);
|
||||
}
|
||||
|
||||
inline int64 atoi64(const char* psz)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _atoi64(psz);
|
||||
#else
|
||||
return strtoll(psz, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int64 atoi64(const std::string& str)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _atoi64(str.c_str());
|
||||
#else
|
||||
return strtoll(str.c_str(), NULL, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int atoi(const std::string& str)
|
||||
{
|
||||
return atoi(str.c_str());
|
||||
}
|
||||
|
||||
inline int roundint(double d)
|
||||
{
|
||||
return (int)(d > 0 ? d + 0.5 : d - 0.5);
|
||||
}
|
||||
|
||||
inline int64 roundint64(double d)
|
||||
{
|
||||
return (int64)(d > 0 ? d + 0.5 : d - 0.5);
|
||||
}
|
||||
|
||||
inline int64 abs64(int64 n)
|
||||
{
|
||||
return (n >= 0 ? n : -n);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
|
||||
{
|
||||
if (itbegin == itend)
|
||||
return "";
|
||||
const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
|
||||
const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
|
||||
std::string str;
|
||||
str.reserve((pend-pbegin) * (fSpaces ? 3 : 2));
|
||||
for (const unsigned char* p = pbegin; p != pend; p++)
|
||||
str += strprintf((fSpaces && p != pend-1 ? "%02x " : "%02x"), *p);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline std::string HexStr(const std::vector<unsigned char>& vch, bool fSpaces=false)
|
||||
{
|
||||
return HexStr(vch.begin(), vch.end(), fSpaces);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string HexNumStr(const T itbegin, const T itend, bool f0x=true)
|
||||
{
|
||||
if (itbegin == itend)
|
||||
return "";
|
||||
const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
|
||||
const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
|
||||
std::string str = (f0x ? "0x" : "");
|
||||
str.reserve(str.size() + (pend-pbegin) * 2);
|
||||
for (const unsigned char* p = pend-1; p >= pbegin; p--)
|
||||
str += strprintf("%02x", *p);
|
||||
return str;
|
||||
}
|
||||
|
||||
inline std::string HexNumStr(const std::vector<unsigned char>& vch, bool f0x=true)
|
||||
{
|
||||
return HexNumStr(vch.begin(), vch.end(), f0x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true)
|
||||
{
|
||||
printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str());
|
||||
}
|
||||
|
||||
inline void PrintHex(const std::vector<unsigned char>& vch, const char* pszFormat="%s", bool fSpaces=true)
|
||||
{
|
||||
printf(pszFormat, HexStr(vch, fSpaces).c_str());
|
||||
}
|
||||
|
||||
inline int64 GetPerformanceCounter()
|
||||
{
|
||||
int64 nCounter = 0;
|
||||
#ifdef __WXMSW__
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
|
||||
#else
|
||||
timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
nCounter = t.tv_sec * 1000000 + t.tv_usec;
|
||||
#endif
|
||||
return nCounter;
|
||||
}
|
||||
|
||||
inline int64 GetTimeMillis()
|
||||
{
|
||||
return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) -
|
||||
boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
|
||||
}
|
||||
|
||||
inline std::string DateTimeStrFormat(const char* pszFormat, int64 nTime)
|
||||
{
|
||||
time_t n = nTime;
|
||||
struct tm* ptmTime = gmtime(&n);
|
||||
char pszTime[200];
|
||||
strftime(pszTime, sizeof(pszTime), pszFormat, ptmTime);
|
||||
return pszTime;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void skipspaces(T& it)
|
||||
{
|
||||
while (isspace(*it))
|
||||
++it;
|
||||
}
|
||||
|
||||
inline bool IsSwitchChar(char c)
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
return c == '-' || c == '/';
|
||||
#else
|
||||
return c == '-';
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::string GetArg(const std::string& strArg, const std::string& strDefault)
|
||||
{
|
||||
if (mapArgs.count(strArg))
|
||||
return mapArgs[strArg];
|
||||
return strDefault;
|
||||
}
|
||||
|
||||
inline int64 GetArg(const std::string& strArg, int64 nDefault)
|
||||
{
|
||||
if (mapArgs.count(strArg))
|
||||
return atoi64(mapArgs[strArg]);
|
||||
return nDefault;
|
||||
}
|
||||
|
||||
inline bool GetBoolArg(const std::string& strArg)
|
||||
{
|
||||
if (mapArgs.count(strArg))
|
||||
{
|
||||
if (mapArgs[strArg].empty())
|
||||
return true;
|
||||
return (atoi(mapArgs[strArg]) != 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline void heapchk()
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
/// for debugging
|
||||
//if (_heapchk() != _HEAPOK)
|
||||
// DebugBreak();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Randomize the stack to help protect against buffer overrun exploits
|
||||
#define IMPLEMENT_RANDOMIZE_STACK(ThreadFn) \
|
||||
{ \
|
||||
static char nLoops; \
|
||||
if (nLoops <= 0) \
|
||||
nLoops = GetRand(20) + 1; \
|
||||
if (nLoops-- > 1) \
|
||||
{ \
|
||||
ThreadFn; \
|
||||
return; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CATCH_PRINT_EXCEPTION(pszFn) \
|
||||
catch (std::exception& e) { \
|
||||
PrintException(&e, (pszFn)); \
|
||||
} catch (...) { \
|
||||
PrintException(NULL, (pszFn)); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T1>
|
||||
inline uint256 Hash(const T1 pbegin, const T1 pend)
|
||||
{
|
||||
static unsigned char pblank[1];
|
||||
uint256 hash1;
|
||||
SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
|
||||
uint256 hash2;
|
||||
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
|
||||
return hash2;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
inline uint256 Hash(const T1 p1begin, const T1 p1end,
|
||||
const T2 p2begin, const T2 p2end)
|
||||
{
|
||||
static unsigned char pblank[1];
|
||||
uint256 hash1;
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
|
||||
SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
|
||||
SHA256_Final((unsigned char*)&hash1, &ctx);
|
||||
uint256 hash2;
|
||||
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
|
||||
return hash2;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
inline uint256 Hash(const T1 p1begin, const T1 p1end,
|
||||
const T2 p2begin, const T2 p2end,
|
||||
const T3 p3begin, const T3 p3end)
|
||||
{
|
||||
static unsigned char pblank[1];
|
||||
uint256 hash1;
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
|
||||
SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
|
||||
SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0]));
|
||||
SHA256_Final((unsigned char*)&hash1, &ctx);
|
||||
uint256 hash2;
|
||||
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
|
||||
return hash2;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=VERSION)
|
||||
{
|
||||
// Most of the time is spent allocating and deallocating CDataStream's
|
||||
// buffer. If this ever needs to be optimized further, make a CStaticStream
|
||||
// class with its buffer on the stack.
|
||||
CDataStream ss(nType, nVersion);
|
||||
ss.reserve(10000);
|
||||
ss << obj;
|
||||
return Hash(ss.begin(), ss.end());
|
||||
}
|
||||
|
||||
inline uint160 Hash160(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
uint256 hash1;
|
||||
SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
|
||||
uint160 hash2;
|
||||
RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
|
||||
return hash2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Note: It turns out we might have been able to use boost::thread
|
||||
// by using TerminateThread(boost::thread.native_handle(), 0);
|
||||
#ifdef __WXMSW__
|
||||
typedef HANDLE pthread_t;
|
||||
|
||||
inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
|
||||
{
|
||||
DWORD nUnused = 0;
|
||||
HANDLE hthread =
|
||||
CreateThread(
|
||||
NULL, // default security
|
||||
0, // inherit stack size from parent
|
||||
(LPTHREAD_START_ROUTINE)pfn, // function pointer
|
||||
parg, // argument
|
||||
0, // creation option, start immediately
|
||||
&nUnused); // thread identifier
|
||||
if (hthread == NULL)
|
||||
{
|
||||
printf("Error: CreateThread() returned %d\n", GetLastError());
|
||||
return (pthread_t)0;
|
||||
}
|
||||
if (!fWantHandle)
|
||||
{
|
||||
CloseHandle(hthread);
|
||||
return (pthread_t)-1;
|
||||
}
|
||||
return hthread;
|
||||
}
|
||||
|
||||
inline void SetThreadPriority(int nPriority)
|
||||
{
|
||||
SetThreadPriority(GetCurrentThread(), nPriority);
|
||||
}
|
||||
#else
|
||||
inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
|
||||
{
|
||||
pthread_t hthread = 0;
|
||||
int ret = pthread_create(&hthread, NULL, (void*(*)(void*))pfn, parg);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("Error: pthread_create() returned %d\n", ret);
|
||||
return (pthread_t)0;
|
||||
}
|
||||
if (!fWantHandle)
|
||||
return (pthread_t)-1;
|
||||
return hthread;
|
||||
}
|
||||
|
||||
#define THREAD_PRIORITY_LOWEST PRIO_MAX
|
||||
#define THREAD_PRIORITY_BELOW_NORMAL 2
|
||||
#define THREAD_PRIORITY_NORMAL 0
|
||||
#define THREAD_PRIORITY_ABOVE_NORMAL 0
|
||||
|
||||
inline void SetThreadPriority(int nPriority)
|
||||
{
|
||||
// It's unclear if it's even possible to change thread priorities on Linux,
|
||||
// but we really and truly need it for the generation threads.
|
||||
#ifdef PRIO_THREAD
|
||||
setpriority(PRIO_THREAD, 0, nPriority);
|
||||
#else
|
||||
setpriority(PRIO_PROCESS, 0, nPriority);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)
|
||||
{
|
||||
return (pthread_cancel(hthread) == 0);
|
||||
}
|
||||
|
||||
inline void ExitThread(unsigned int nExitCode)
|
||||
{
|
||||
pthread_exit((void*)nExitCode);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool AffinityBugWorkaround(void(*pfn)(void*))
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
// Sometimes after a few hours affinity gets stuck on one processor
|
||||
DWORD dwProcessAffinityMask = -1;
|
||||
DWORD dwSystemAffinityMask = -1;
|
||||
GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
|
||||
DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
|
||||
DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
|
||||
if (dwPrev2 != dwProcessAffinityMask)
|
||||
{
|
||||
printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask);
|
||||
if (!CreateThread(pfn, NULL))
|
||||
printf("Error: CreateThread() failed\n");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user