Initial commit.

This commit is contained in:
transcoder
2013-07-18 19:01:17 -06:00
commit f3307413ec
377 changed files with 150655 additions and 0 deletions

527
src/addrman.cpp Normal file
View File

@@ -0,0 +1,527 @@
// Copyright (c) 2012 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "addrman.h"
using namespace std;
int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const
{
CDataStream ss1(SER_GETHASH, 0);
std::vector<unsigned char> vchKey = GetKey();
ss1 << nKey << vchKey;
uint64 hash1 = Hash(ss1.begin(), ss1.end()).Get64();
CDataStream ss2(SER_GETHASH, 0);
std::vector<unsigned char> vchGroupKey = GetGroup();
ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP);
uint64 hash2 = Hash(ss2.begin(), ss2.end()).Get64();
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
}
int CAddrInfo::GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const
{
CDataStream ss1(SER_GETHASH, 0);
std::vector<unsigned char> vchGroupKey = GetGroup();
std::vector<unsigned char> vchSourceGroupKey = src.GetGroup();
ss1 << nKey << vchGroupKey << vchSourceGroupKey;
uint64 hash1 = Hash(ss1.begin(), ss1.end()).Get64();
CDataStream ss2(SER_GETHASH, 0);
ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP);
uint64 hash2 = Hash(ss2.begin(), ss2.end()).Get64();
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
}
bool CAddrInfo::IsTerrible(int64 nNow) const
{
if (nLastTry && nLastTry >= nNow-60) // never remove things tried the last minute
return false;
if (nTime > nNow + 10*60) // came in a flying DeLorean
return true;
if (nTime==0 || nNow-nTime > ADDRMAN_HORIZON_DAYS*86400) // not seen in over a month
return true;
if (nLastSuccess==0 && nAttempts>=ADDRMAN_RETRIES) // tried three times and never a success
return true;
if (nNow-nLastSuccess > ADDRMAN_MIN_FAIL_DAYS*86400 && nAttempts>=ADDRMAN_MAX_FAILURES) // 10 successive failures in the last week
return true;
return false;
}
double CAddrInfo::GetChance(int64 nNow) const
{
double fChance = 1.0;
int64 nSinceLastSeen = nNow - nTime;
int64 nSinceLastTry = nNow - nLastTry;
if (nSinceLastSeen < 0) nSinceLastSeen = 0;
if (nSinceLastTry < 0) nSinceLastTry = 0;
fChance *= 600.0 / (600.0 + nSinceLastSeen);
// deprioritize very recent attempts away
if (nSinceLastTry < 60*10)
fChance *= 0.01;
// deprioritize 50% after each failed attempt
for (int n=0; n<nAttempts; n++)
fChance /= 1.5;
return fChance;
}
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int *pnId)
{
std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
if (it == mapAddr.end())
return NULL;
if (pnId)
*pnId = (*it).second;
std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
if (it2 != mapInfo.end())
return &(*it2).second;
return NULL;
}
CAddrInfo* CAddrMan::Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId)
{
int nId = nIdCount++;
mapInfo[nId] = CAddrInfo(addr, addrSource);
mapAddr[addr] = nId;
mapInfo[nId].nRandomPos = vRandom.size();
vRandom.push_back(nId);
if (pnId)
*pnId = nId;
return &mapInfo[nId];
}
void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
{
if (nRndPos1 == nRndPos2)
return;
assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
int nId1 = vRandom[nRndPos1];
int nId2 = vRandom[nRndPos2];
assert(mapInfo.count(nId1) == 1);
assert(mapInfo.count(nId2) == 1);
mapInfo[nId1].nRandomPos = nRndPos2;
mapInfo[nId2].nRandomPos = nRndPos1;
vRandom[nRndPos1] = nId2;
vRandom[nRndPos2] = nId1;
}
int CAddrMan::SelectTried(int nKBucket)
{
std::vector<int> &vTried = vvTried[nKBucket];
// random shuffle the first few elements (using the entire list)
// find the least recently tried among them
int64 nOldest = -1;
int nOldestPos = -1;
for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++)
{
int nPos = GetRandInt(vTried.size() - i) + i;
int nTemp = vTried[nPos];
vTried[nPos] = vTried[i];
vTried[i] = nTemp;
assert(nOldest == -1 || mapInfo.count(nTemp) == 1);
if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) {
nOldest = nTemp;
nOldestPos = nPos;
}
}
return nOldestPos;
}
int CAddrMan::ShrinkNew(int nUBucket)
{
assert(nUBucket >= 0 && (unsigned int)nUBucket < vvNew.size());
std::set<int> &vNew = vvNew[nUBucket];
// first look for deletable items
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
{
assert(mapInfo.count(*it));
CAddrInfo &info = mapInfo[*it];
if (info.IsTerrible())
{
if (--info.nRefCount == 0)
{
SwapRandom(info.nRandomPos, vRandom.size()-1);
vRandom.pop_back();
mapAddr.erase(info);
mapInfo.erase(*it);
nNew--;
}
vNew.erase(it);
return 0;
}
}
// otherwise, select four randomly, and pick the oldest of those to replace
int n[4] = {GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size())};
int nI = 0;
int nOldest = -1;
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
{
if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3])
{
assert(nOldest == -1 || mapInfo.count(*it) == 1);
if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime)
nOldest = *it;
}
nI++;
}
assert(mapInfo.count(nOldest) == 1);
CAddrInfo &info = mapInfo[nOldest];
if (--info.nRefCount == 0)
{
SwapRandom(info.nRandomPos, vRandom.size()-1);
vRandom.pop_back();
mapAddr.erase(info);
mapInfo.erase(nOldest);
nNew--;
}
vNew.erase(nOldest);
return 1;
}
void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
{
assert(vvNew[nOrigin].count(nId) == 1);
// remove the entry from all new buckets
for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++)
{
if ((*it).erase(nId))
info.nRefCount--;
}
nNew--;
assert(info.nRefCount == 0);
// what tried bucket to move the entry to
int nKBucket = info.GetTriedBucket(nKey);
std::vector<int> &vTried = vvTried[nKBucket];
// first check whether there is place to just add it
if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
{
vTried.push_back(nId);
nTried++;
info.fInTried = true;
return;
}
// otherwise, find an item to evict
int nPos = SelectTried(nKBucket);
// find which new bucket it belongs to
assert(mapInfo.count(vTried[nPos]) == 1);
int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey);
std::set<int> &vNew = vvNew[nUBucket];
// remove the to-be-replaced tried entry from the tried set
CAddrInfo& infoOld = mapInfo[vTried[nPos]];
infoOld.fInTried = false;
infoOld.nRefCount = 1;
// do not update nTried, as we are going to move something else there immediately
// check whether there is place in that one,
if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE)
{
// if so, move it back there
vNew.insert(vTried[nPos]);
} else {
// otherwise, move it to the new bucket nId came from (there is certainly place there)
vvNew[nOrigin].insert(vTried[nPos]);
}
nNew++;
vTried[nPos] = nId;
// we just overwrote an entry in vTried; no need to update nTried
info.fInTried = true;
return;
}
void CAddrMan::Good_(const CService &addr, int64 nTime)
{
// printf("Good: addr=%s\n", addr.ToString().c_str());
int nId;
CAddrInfo *pinfo = Find(addr, &nId);
// if not found, bail out
if (!pinfo)
return;
CAddrInfo &info = *pinfo;
// check whether we are talking about the exact same CService (including same port)
if (info != addr)
return;
// update info
info.nLastSuccess = nTime;
info.nLastTry = nTime;
info.nTime = nTime;
info.nAttempts = 0;
// if it is already in the tried set, don't do anything else
if (info.fInTried)
return;
// find a bucket it is in now
int nRnd = GetRandInt(vvNew.size());
int nUBucket = -1;
for (unsigned int n = 0; n < vvNew.size(); n++)
{
int nB = (n+nRnd) % vvNew.size();
std::set<int> &vNew = vvNew[nB];
if (vNew.count(nId))
{
nUBucket = nB;
break;
}
}
// if no bucket is found, something bad happened;
// TODO: maybe re-add the node, but for now, just bail out
if (nUBucket == -1) return;
printf("Moving %s to tried\n", addr.ToString().c_str());
// move nId to the tried tables
MakeTried(info, nId, nUBucket);
}
bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty)
{
if (!addr.IsRoutable())
return false;
bool fNew = false;
int nId;
CAddrInfo *pinfo = Find(addr, &nId);
if (pinfo)
{
// periodically update nTime
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
pinfo->nTime = max((int64)0, addr.nTime - nTimePenalty);
// add services
pinfo->nServices |= addr.nServices;
// do not update if no new information is present
if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
return false;
// do not update if the entry was already in the "tried" table
if (pinfo->fInTried)
return false;
// do not update if the max reference count is reached
if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
return false;
// stochastic test: previous nRefCount == N: 2^N times harder to increase it
int nFactor = 1;
for (int n=0; n<pinfo->nRefCount; n++)
nFactor *= 2;
if (nFactor > 1 && (GetRandInt(nFactor) != 0))
return false;
} else {
pinfo = Create(addr, source, &nId);
pinfo->nTime = max((int64)0, (int64)pinfo->nTime - nTimePenalty);
// printf("Added %s [nTime=%fhr]\n", pinfo->ToString().c_str(), (GetAdjustedTime() - pinfo->nTime) / 3600.0);
nNew++;
fNew = true;
}
int nUBucket = pinfo->GetNewBucket(nKey, source);
std::set<int> &vNew = vvNew[nUBucket];
if (!vNew.count(nId))
{
pinfo->nRefCount++;
if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE)
ShrinkNew(nUBucket);
vvNew[nUBucket].insert(nId);
}
return fNew;
}
void CAddrMan::Attempt_(const CService &addr, int64 nTime)
{
CAddrInfo *pinfo = Find(addr);
// if not found, bail out
if (!pinfo)
return;
CAddrInfo &info = *pinfo;
// check whether we are talking about the exact same CService (including same port)
if (info != addr)
return;
// update info
info.nLastTry = nTime;
info.nAttempts++;
}
CAddress CAddrMan::Select_(int nUnkBias)
{
if (size() == 0)
return CAddress();
double nCorTried = sqrt(nTried) * (100.0 - nUnkBias);
double nCorNew = sqrt(nNew) * nUnkBias;
if ((nCorTried + nCorNew)*GetRandInt(1<<30)/(1<<30) < nCorTried)
{
// use a tried node
double fChanceFactor = 1.0;
while(1)
{
int nKBucket = GetRandInt(vvTried.size());
std::vector<int> &vTried = vvTried[nKBucket];
if (vTried.size() == 0) continue;
int nPos = GetRandInt(vTried.size());
assert(mapInfo.count(vTried[nPos]) == 1);
CAddrInfo &info = mapInfo[vTried[nPos]];
if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
return info;
fChanceFactor *= 1.2;
}
} else {
// use an new node
double fChanceFactor = 1.0;
while(1)
{
int nUBucket = GetRandInt(vvNew.size());
std::set<int> &vNew = vvNew[nUBucket];
if (vNew.size() == 0) continue;
int nPos = GetRandInt(vNew.size());
std::set<int>::iterator it = vNew.begin();
while (nPos--)
it++;
assert(mapInfo.count(*it) == 1);
CAddrInfo &info = mapInfo[*it];
if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
return info;
fChanceFactor *= 1.2;
}
}
}
#ifdef DEBUG_ADDRMAN
int CAddrMan::Check_()
{
std::set<int> setTried;
std::map<int, int> mapNew;
if (vRandom.size() != nTried + nNew) return -7;
for (std::map<int, CAddrInfo>::iterator it = mapInfo.begin(); it != mapInfo.end(); it++)
{
int n = (*it).first;
CAddrInfo &info = (*it).second;
if (info.fInTried)
{
if (!info.nLastSuccess) return -1;
if (info.nRefCount) return -2;
setTried.insert(n);
} else {
if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return -3;
if (!info.nRefCount) return -4;
mapNew[n] = info.nRefCount;
}
if (mapAddr[info] != n) return -5;
if (info.nRandomPos<0 || info.nRandomPos>=vRandom.size() || vRandom[info.nRandomPos] != n) return -14;
if (info.nLastTry < 0) return -6;
if (info.nLastSuccess < 0) return -8;
}
if (setTried.size() != nTried) return -9;
if (mapNew.size() != nNew) return -10;
for (int n=0; n<vvTried.size(); n++)
{
std::vector<int> &vTried = vvTried[n];
for (std::vector<int>::iterator it = vTried.begin(); it != vTried.end(); it++)
{
if (!setTried.count(*it)) return -11;
setTried.erase(*it);
}
}
for (int n=0; n<vvNew.size(); n++)
{
std::set<int> &vNew = vvNew[n];
for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
{
if (!mapNew.count(*it)) return -12;
if (--mapNew[*it] == 0)
mapNew.erase(*it);
}
}
if (setTried.size()) return -13;
if (mapNew.size()) return -15;
return 0;
}
#endif
void CAddrMan::GetAddr_(std::vector<CAddress> &vAddr)
{
int nNodes = ADDRMAN_GETADDR_MAX_PCT*vRandom.size()/100;
if (nNodes > ADDRMAN_GETADDR_MAX)
nNodes = ADDRMAN_GETADDR_MAX;
// perform a random shuffle over the first nNodes elements of vRandom (selecting from all)
for (int n = 0; n<nNodes; n++)
{
int nRndPos = GetRandInt(vRandom.size() - n) + n;
SwapRandom(n, nRndPos);
assert(mapInfo.count(vRandom[n]) == 1);
vAddr.push_back(mapInfo[vRandom[n]]);
}
}
void CAddrMan::Connected_(const CService &addr, int64 nTime)
{
CAddrInfo *pinfo = Find(addr);
// if not found, bail out
if (!pinfo)
return;
CAddrInfo &info = *pinfo;
// check whether we are talking about the exact same CService (including same port)
if (info != addr)
return;
// update info
int64 nUpdateInterval = 20 * 60;
if (nTime - info.nTime > nUpdateInterval)
info.nTime = nTime;
}

503
src/addrman.h Normal file
View File

@@ -0,0 +1,503 @@
// Copyright (c) 2012 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _BITCOIN_ADDRMAN
#define _BITCOIN_ADDRMAN 1
#include "netbase.h"
#include "protocol.h"
#include "util.h"
#include "sync.h"
#include <map>
#include <vector>
#include <openssl/rand.h>
/** Extended statistics about a CAddress */
class CAddrInfo : public CAddress
{
private:
// where knowledge about this address first came from
CNetAddr source;
// last successful connection by us
int64 nLastSuccess;
// last try whatsoever by us:
// int64 CAddress::nLastTry
// connection attempts since last successful attempt
int nAttempts;
// reference count in new sets (memory only)
int nRefCount;
// in tried set? (memory only)
bool fInTried;
// position in vRandom
int nRandomPos;
friend class CAddrMan;
public:
IMPLEMENT_SERIALIZE(
CAddress* pthis = (CAddress*)(this);
READWRITE(*pthis);
READWRITE(source);
READWRITE(nLastSuccess);
READWRITE(nAttempts);
)
void Init()
{
nLastSuccess = 0;
nLastTry = 0;
nAttempts = 0;
nRefCount = 0;
fInTried = false;
nRandomPos = -1;
}
CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
{
Init();
}
CAddrInfo() : CAddress(), source()
{
Init();
}
// Calculate in which "tried" bucket this entry belongs
int GetTriedBucket(const std::vector<unsigned char> &nKey) const;
// Calculate in which "new" bucket this entry belongs, given a certain source
int GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const;
// Calculate in which "new" bucket this entry belongs, using its default source
int GetNewBucket(const std::vector<unsigned char> &nKey) const
{
return GetNewBucket(nKey, source);
}
// Determine whether the statistics about this entry are bad enough so that it can just be deleted
bool IsTerrible(int64 nNow = GetAdjustedTime()) const;
// Calculate the relative chance this entry should be given when selecting nodes to connect to
double GetChance(int64 nNow = GetAdjustedTime()) const;
};
// Stochastic address manager
//
// Design goals:
// * Only keep a limited number of addresses around, so that addr.dat and memory requirements do not grow without bound.
// * Keep the address tables in-memory, and asynchronously dump the entire to able in addr.dat.
// * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
//
// To that end:
// * Addresses are organized into buckets.
// * Address that have not yet been tried go into 256 "new" buckets.
// * Based on the address range (/16 for IPv4) of source of the information, 32 buckets are selected at random
// * The actual bucket is chosen from one of these, based on the range the address itself is located.
// * One single address can occur in up to 4 different buckets, to increase selection chances for addresses that
// are seen frequently. The chance for increasing this multiplicity decreases exponentially.
// * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
// ones) is removed from it first.
// * Addresses of nodes that are known to be accessible go into 64 "tried" buckets.
// * Each address range selects at random 4 of these buckets.
// * The actual bucket is chosen from one of these, based on the full address.
// * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
// tried ones) is evicted from it, back to the "new" buckets.
// * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
// be observable by adversaries.
// * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
// consistency checks for the entire datastructure.
// total number of buckets for tried addresses
#define ADDRMAN_TRIED_BUCKET_COUNT 64
// maximum allowed number of entries in buckets for tried addresses
#define ADDRMAN_TRIED_BUCKET_SIZE 64
// total number of buckets for new addresses
#define ADDRMAN_NEW_BUCKET_COUNT 256
// maximum allowed number of entries in buckets for new addresses
#define ADDRMAN_NEW_BUCKET_SIZE 64
// over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 4
// over how many buckets entries with new addresses originating from a single group are spread
#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 32
// in how many buckets for entries with new addresses a single address may occur
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 4
// how many entries in a bucket with tried addresses are inspected, when selecting one to replace
#define ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT 4
// how old addresses can maximally be
#define ADDRMAN_HORIZON_DAYS 30
// after how many failed attempts we give up on a new node
#define ADDRMAN_RETRIES 3
// how many successive failures are allowed ...
#define ADDRMAN_MAX_FAILURES 10
// ... in at least this many days
#define ADDRMAN_MIN_FAIL_DAYS 7
// the maximum percentage of nodes to return in a getaddr call
#define ADDRMAN_GETADDR_MAX_PCT 23
// the maximum number of nodes to return in a getaddr call
#define ADDRMAN_GETADDR_MAX 2500
/** Stochastical (IP) address manager */
class CAddrMan
{
private:
// critical section to protect the inner data structures
mutable CCriticalSection cs;
// secret key to randomize bucket select with
std::vector<unsigned char> nKey;
// last used nId
int nIdCount;
// table with information about all nId's
std::map<int, CAddrInfo> mapInfo;
// find an nId based on its network address
std::map<CNetAddr, int> mapAddr;
// randomly-ordered vector of all nId's
std::vector<int> vRandom;
// number of "tried" entries
int nTried;
// list of "tried" buckets
std::vector<std::vector<int> > vvTried;
// number of (unique) "new" entries
int nNew;
// list of "new" buckets
std::vector<std::set<int> > vvNew;
protected:
// Find an entry.
CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);
// find an entry, creating it if necessary.
// nTime and nServices of found node is updated, if necessary.
CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL);
// Swap two elements in vRandom.
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
// Return position in given bucket to replace.
int SelectTried(int nKBucket);
// Remove an element from a "new" bucket.
// This is the only place where actual deletes occur.
// They are never deleted while in the "tried" table, only possibly evicted back to the "new" table.
int ShrinkNew(int nUBucket);
// Move an entry from the "new" table(s) to the "tried" table
// @pre vvUnkown[nOrigin].count(nId) != 0
void MakeTried(CAddrInfo& info, int nId, int nOrigin);
// Mark an entry "good", possibly moving it from "new" to "tried".
void Good_(const CService &addr, int64 nTime);
// Add an entry to the "new" table.
bool Add_(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty);
// Mark an entry as attempted to connect.
void Attempt_(const CService &addr, int64 nTime);
// Select an address to connect to.
// nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100)
CAddress Select_(int nUnkBias);
#ifdef DEBUG_ADDRMAN
// Perform consistency check. Returns an error code or zero.
int Check_();
#endif
// Select several addresses at once.
void GetAddr_(std::vector<CAddress> &vAddr);
// Mark an entry as currently-connected-to.
void Connected_(const CService &addr, int64 nTime);
public:
IMPLEMENT_SERIALIZE
(({
// serialized format:
// * version byte (currently 0)
// * nKey
// * nNew
// * nTried
// * number of "new" buckets
// * all nNew addrinfo's in vvNew
// * all nTried addrinfo's in vvTried
// * for each bucket:
// * number of elements
// * for each element: index
//
// Notice that vvTried, mapAddr and vVector are never encoded explicitly;
// they are instead reconstructed from the other information.
//
// vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
// otherwise it is reconstructed as well.
//
// This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
// changes to the ADDRMAN_ parameters without breaking the on-disk structure.
{
LOCK(cs);
unsigned char nVersion = 0;
READWRITE(nVersion);
READWRITE(nKey);
READWRITE(nNew);
READWRITE(nTried);
CAddrMan *am = const_cast<CAddrMan*>(this);
if (fWrite)
{
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT;
READWRITE(nUBuckets);
std::map<int, int> mapUnkIds;
int nIds = 0;
for (std::map<int, CAddrInfo>::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++)
{
if (nIds == nNew) break; // this means nNew was wrong, oh ow
mapUnkIds[(*it).first] = nIds;
CAddrInfo &info = (*it).second;
if (info.nRefCount)
{
READWRITE(info);
nIds++;
}
}
nIds = 0;
for (std::map<int, CAddrInfo>::iterator it = am->mapInfo.begin(); it != am->mapInfo.end(); it++)
{
if (nIds == nTried) break; // this means nTried was wrong, oh ow
CAddrInfo &info = (*it).second;
if (info.fInTried)
{
READWRITE(info);
nIds++;
}
}
for (std::vector<std::set<int> >::iterator it = am->vvNew.begin(); it != am->vvNew.end(); it++)
{
const std::set<int> &vNew = (*it);
int nSize = vNew.size();
READWRITE(nSize);
for (std::set<int>::iterator it2 = vNew.begin(); it2 != vNew.end(); it2++)
{
int nIndex = mapUnkIds[*it2];
READWRITE(nIndex);
}
}
} else {
int nUBuckets = 0;
READWRITE(nUBuckets);
am->nIdCount = 0;
am->mapInfo.clear();
am->mapAddr.clear();
am->vRandom.clear();
am->vvTried = std::vector<std::vector<int> >(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0));
am->vvNew = std::vector<std::set<int> >(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>());
for (int n = 0; n < am->nNew; n++)
{
CAddrInfo &info = am->mapInfo[n];
READWRITE(info);
am->mapAddr[info] = n;
info.nRandomPos = vRandom.size();
am->vRandom.push_back(n);
if (nUBuckets != ADDRMAN_NEW_BUCKET_COUNT)
{
am->vvNew[info.GetNewBucket(am->nKey)].insert(n);
info.nRefCount++;
}
}
am->nIdCount = am->nNew;
int nLost = 0;
for (int n = 0; n < am->nTried; n++)
{
CAddrInfo info;
READWRITE(info);
std::vector<int> &vTried = am->vvTried[info.GetTriedBucket(am->nKey)];
if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
{
info.nRandomPos = vRandom.size();
info.fInTried = true;
am->vRandom.push_back(am->nIdCount);
am->mapInfo[am->nIdCount] = info;
am->mapAddr[info] = am->nIdCount;
vTried.push_back(am->nIdCount);
am->nIdCount++;
} else {
nLost++;
}
}
am->nTried -= nLost;
for (int b = 0; b < nUBuckets; b++)
{
std::set<int> &vNew = am->vvNew[b];
int nSize = 0;
READWRITE(nSize);
for (int n = 0; n < nSize; n++)
{
int nIndex = 0;
READWRITE(nIndex);
CAddrInfo &info = am->mapInfo[nIndex];
if (nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
{
info.nRefCount++;
vNew.insert(nIndex);
}
}
}
}
}
});)
CAddrMan() : vRandom(0), vvTried(ADDRMAN_TRIED_BUCKET_COUNT, std::vector<int>(0)), vvNew(ADDRMAN_NEW_BUCKET_COUNT, std::set<int>())
{
nKey.resize(32);
RAND_bytes(&nKey[0], 32);
nIdCount = 0;
nTried = 0;
nNew = 0;
}
// Return the number of (unique) addresses in all tables.
int size()
{
return vRandom.size();
}
// Consistency check
void Check()
{
#ifdef DEBUG_ADDRMAN
{
LOCK(cs);
int err;
if ((err=Check_()))
printf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
}
#endif
}
// Add a single address.
bool Add(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty = 0)
{
bool fRet = false;
{
LOCK(cs);
Check();
fRet |= Add_(addr, source, nTimePenalty);
Check();
}
if (fRet)
printf("Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort().c_str(), source.ToString().c_str(), nTried, nNew);
return fRet;
}
// Add multiple addresses.
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64 nTimePenalty = 0)
{
int nAdd = 0;
{
LOCK(cs);
Check();
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++)
nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0;
Check();
}
if (nAdd)
printf("Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString().c_str(), nTried, nNew);
return nAdd > 0;
}
// Mark an entry as accessible.
void Good(const CService &addr, int64 nTime = GetAdjustedTime())
{
{
LOCK(cs);
Check();
Good_(addr, nTime);
Check();
}
}
// Mark an entry as connection attempted to.
void Attempt(const CService &addr, int64 nTime = GetAdjustedTime())
{
{
LOCK(cs);
Check();
Attempt_(addr, nTime);
Check();
}
}
// Choose an address to connect to.
// nUnkBias determines how much "new" entries are favored over "tried" ones (0-100).
CAddress Select(int nUnkBias = 50)
{
CAddress addrRet;
{
LOCK(cs);
Check();
addrRet = Select_(nUnkBias);
Check();
}
return addrRet;
}
// Return a bunch of addresses, selected at random.
std::vector<CAddress> GetAddr()
{
Check();
std::vector<CAddress> vAddr;
{
LOCK(cs);
GetAddr_(vAddr);
}
Check();
return vAddr;
}
// Mark an entry as currently-connected-to.
void Connected(const CService &addr, int64 nTime = GetAdjustedTime())
{
{
LOCK(cs);
Check();
Connected_(addr, nTime);
Check();
}
}
};
#endif

124
src/allocators.h Normal file
View File

@@ -0,0 +1,124 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_ALLOCATORS_H
#define BITCOIN_ALLOCATORS_H
#include <string.h>
#include <string>
#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
// This is used to attempt to keep keying material out of swap
// Note that VirtualLock does not provide this as a guarantee on Windows,
// but, in practice, memory that has been VirtualLock'd almost never gets written to
// the pagefile except in rare circumstances where memory is extremely low.
#define mlock(p, n) VirtualLock((p), (n));
#define munlock(p, n) VirtualUnlock((p), (n));
#else
#include <sys/mman.h>
#include <limits.h>
/* This comes from limits.h if it's not defined there set a sane default */
#ifndef PAGESIZE
#include <unistd.h>
#define PAGESIZE sysconf(_SC_PAGESIZE)
#endif
#define mlock(a,b) \
mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
(((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
#define munlock(a,b) \
munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))),\
(((((size_t)(a)) + (b) - 1) | ((PAGESIZE) - 1)) + 1) - (((size_t)(a)) & (~((PAGESIZE) - 1))))
#endif
//
// Allocator that locks its contents from being paged
// out of memory and clears its contents before deletion.
//
template<typename T>
struct secure_allocator : public std::allocator<T>
{
// MSVC8 default copy constructor is broken
typedef std::allocator<T> base;
typedef typename base::size_type size_type;
typedef typename base::difference_type difference_type;
typedef typename base::pointer pointer;
typedef typename base::const_pointer const_pointer;
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
secure_allocator() throw() {}
secure_allocator(const secure_allocator& a) throw() : base(a) {}
template <typename U>
secure_allocator(const secure_allocator<U>& a) throw() : base(a) {}
~secure_allocator() throw() {}
template<typename _Other> struct rebind
{ typedef secure_allocator<_Other> other; };
T* allocate(std::size_t n, const void *hint = 0)
{
T *p;
p = std::allocator<T>::allocate(n, hint);
if (p != NULL)
mlock(p, sizeof(T) * n);
return p;
}
void deallocate(T* p, std::size_t n)
{
if (p != NULL)
{
memset(p, 0, sizeof(T) * n);
munlock(p, sizeof(T) * n);
}
std::allocator<T>::deallocate(p, n);
}
};
//
// Allocator that clears its contents before deletion.
//
template<typename T>
struct zero_after_free_allocator : public std::allocator<T>
{
// MSVC8 default copy constructor is broken
typedef std::allocator<T> base;
typedef typename base::size_type size_type;
typedef typename base::difference_type difference_type;
typedef typename base::pointer pointer;
typedef typename base::const_pointer const_pointer;
typedef typename base::reference reference;
typedef typename base::const_reference const_reference;
typedef typename base::value_type value_type;
zero_after_free_allocator() throw() {}
zero_after_free_allocator(const zero_after_free_allocator& a) throw() : base(a) {}
template <typename U>
zero_after_free_allocator(const zero_after_free_allocator<U>& a) throw() : base(a) {}
~zero_after_free_allocator() throw() {}
template<typename _Other> struct rebind
{ typedef zero_after_free_allocator<_Other> other; };
void deallocate(T* p, std::size_t n)
{
if (p != NULL)
memset(p, 0, sizeof(T) * n);
std::allocator<T>::deallocate(p, n);
}
};
// This is exactly like std::string, but with a custom allocator.
typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
#endif

468
src/base58.h Normal file
View File

@@ -0,0 +1,468 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin Developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING 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"
#include "key.h"
#include "script.h"
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
// Encode a byte sequence as a base58-encoded string
inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{
CAutoBN_CTX pctx;
CBigNum bn58 = 58;
CBigNum bn0 = 0;
// Convert big endian data to little endian
// Extra zero at the end make sure bignum will interpret as a positive number
std::vector<unsigned char> vchTmp(pend-pbegin+1, 0);
reverse_copy(pbegin, pend, vchTmp.begin());
// Convert little endian data to bignum
CBigNum bn;
bn.setvch(vchTmp);
// Convert bignum to std::string
std::string str;
// Expected size increase from base58 conversion is approximately 137%
// use 138% to be safe
str.reserve((pend - pbegin) * 138 / 100 + 1);
CBigNum dv;
CBigNum rem;
while (bn > bn0)
{
if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
throw bignum_error("EncodeBase58 : BN_div failed");
bn = dv;
unsigned int c = rem.getulong();
str += pszBase58[c];
}
// Leading zeroes encoded as base58 zeros
for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
str += pszBase58[0];
// Convert little endian std::string to big endian
reverse(str.begin(), str.end());
return str;
}
// Encode a byte vector as a base58-encoded string
inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
{
return EncodeBase58(&vch[0], &vch[0] + vch.size());
}
// Decode a base58-encoded string psz into byte vector vchRet
// returns true if decoding is successful
inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
{
CAutoBN_CTX pctx;
vchRet.clear();
CBigNum bn58 = 58;
CBigNum bn = 0;
CBigNum bnChar;
while (isspace(*psz))
psz++;
// Convert big endian string to bignum
for (const char* p = psz; *p; p++)
{
const char* p1 = strchr(pszBase58, *p);
if (p1 == NULL)
{
while (isspace(*p))
p++;
if (*p != '\0')
return false;
break;
}
bnChar.setulong(p1 - pszBase58);
if (!BN_mul(&bn, &bn, &bn58, pctx))
throw bignum_error("DecodeBase58 : BN_mul failed");
bn += bnChar;
}
// Get bignum as little endian data
std::vector<unsigned char> vchTmp = bn.getvch();
// Trim off sign byte if present
if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80)
vchTmp.erase(vchTmp.end()-1);
// Restore leading zeros
int nLeadingZeros = 0;
for (const char* p = psz; *p == pszBase58[0]; p++)
nLeadingZeros++;
vchRet.assign(nLeadingZeros + vchTmp.size(), 0);
// Convert little endian data to big endian
reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size());
return true;
}
// Decode a base58-encoded string str into byte vector vchRet
// returns true if decoding is successful
inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
{
return DecodeBase58(str.c_str(), vchRet);
}
// Encode a byte vector to a base58-encoded string, including checksum
inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
{
// add 4-byte hash check to the end
std::vector<unsigned char> vch(vchIn);
uint256 hash = Hash(vch.begin(), vch.end());
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
return EncodeBase58(vch);
}
// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet
// returns true if decoding is successful
inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
{
if (!DecodeBase58(psz, vchRet))
return false;
if (vchRet.size() < 4)
{
vchRet.clear();
return false;
}
uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)
{
vchRet.clear();
return false;
}
vchRet.resize(vchRet.size()-4);
return true;
}
// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet
// returns true if decoding is successful
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
{
return DecodeBase58Check(str.c_str(), vchRet);
}
/** Base class for all base58-encoded data */
class CBase58Data
{
protected:
// the version byte
unsigned char nVersion;
// the actually encoded data
std::vector<unsigned char> vchData;
CBase58Data()
{
nVersion = 0;
vchData.clear();
}
~CBase58Data()
{
// zero the memory, as it may contain sensitive data
if (!vchData.empty())
memset(&vchData[0], 0, vchData.size());
}
void SetData(int nVersionIn, const void* pdata, size_t nSize)
{
nVersion = nVersionIn;
vchData.resize(nSize);
if (!vchData.empty())
memcpy(&vchData[0], pdata, nSize);
}
void SetData(int nVersionIn, const unsigned char *pbegin, const unsigned char *pend)
{
SetData(nVersionIn, (void*)pbegin, pend - pbegin);
}
public:
bool SetString(const char* psz)
{
std::vector<unsigned char> vchTemp;
DecodeBase58Check(psz, vchTemp);
if (vchTemp.empty())
{
vchData.clear();
nVersion = 0;
return false;
}
nVersion = vchTemp[0];
vchData.resize(vchTemp.size() - 1);
if (!vchData.empty())
memcpy(&vchData[0], &vchTemp[1], vchData.size());
memset(&vchTemp[0], 0, vchTemp.size());
return true;
}
bool SetString(const std::string& str)
{
return SetString(str.c_str());
}
std::string ToString() const
{
std::vector<unsigned char> vch(1, nVersion);
vch.insert(vch.end(), vchData.begin(), vchData.end());
return EncodeBase58Check(vch);
}
int CompareTo(const CBase58Data& b58) const
{
if (nVersion < b58.nVersion) return -1;
if (nVersion > b58.nVersion) return 1;
if (vchData < b58.vchData) return -1;
if (vchData > b58.vchData) return 1;
return 0;
}
bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; }
bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; }
bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; }
bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; }
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};
/** base58-encoded Bitcoin addresses.
* Public-key-hash-addresses have version 0 (or 111 testnet).
* The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
* Script-hash-addresses have version 5 (or 196 testnet).
* The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
*/
class CBitcoinAddress;
class CBitcoinAddressVisitor : public boost::static_visitor<bool>
{
private:
CBitcoinAddress *addr;
public:
CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { }
bool operator()(const CKeyID &id) const;
bool operator()(const CScriptID &id) const;
bool operator()(const CNoDestination &no) const;
};
class CBitcoinAddress : public CBase58Data
{
public:
enum
{
PUBKEY_ADDRESS = 28, // CasinoCoin addresses start with C
SCRIPT_ADDRESS = 5,
PUBKEY_ADDRESS_TEST = 87,
SCRIPT_ADDRESS_TEST = 196,
};
bool Set(const CKeyID &id) {
SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &id, 20);
return true;
}
bool Set(const CScriptID &id) {
SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &id, 20);
return true;
}
bool Set(const CTxDestination &dest)
{
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
}
bool IsValid() const
{
unsigned int nExpectedSize = 20;
bool fExpectTestNet = false;
switch(nVersion)
{
case PUBKEY_ADDRESS:
nExpectedSize = 20; // Hash of public key
fExpectTestNet = false;
break;
case SCRIPT_ADDRESS:
nExpectedSize = 20; // Hash of CScript
fExpectTestNet = false;
break;
case PUBKEY_ADDRESS_TEST:
nExpectedSize = 20;
fExpectTestNet = true;
break;
case SCRIPT_ADDRESS_TEST:
nExpectedSize = 20;
fExpectTestNet = true;
break;
default:
return false;
}
return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize;
}
CBitcoinAddress()
{
}
CBitcoinAddress(const CTxDestination &dest)
{
Set(dest);
}
CBitcoinAddress(const std::string& strAddress)
{
SetString(strAddress);
}
CBitcoinAddress(const char* pszAddress)
{
SetString(pszAddress);
}
CTxDestination Get() const {
if (!IsValid())
return CNoDestination();
switch (nVersion) {
case PUBKEY_ADDRESS:
case PUBKEY_ADDRESS_TEST: {
uint160 id;
memcpy(&id, &vchData[0], 20);
return CKeyID(id);
}
case SCRIPT_ADDRESS:
case SCRIPT_ADDRESS_TEST: {
uint160 id;
memcpy(&id, &vchData[0], 20);
return CScriptID(id);
}
}
return CNoDestination();
}
bool GetKeyID(CKeyID &keyID) const {
if (!IsValid())
return false;
switch (nVersion) {
case PUBKEY_ADDRESS:
case PUBKEY_ADDRESS_TEST: {
uint160 id;
memcpy(&id, &vchData[0], 20);
keyID = CKeyID(id);
return true;
}
default: return false;
}
}
bool IsScript() const {
if (!IsValid())
return false;
switch (nVersion) {
case SCRIPT_ADDRESS:
case SCRIPT_ADDRESS_TEST: {
return true;
}
default: return false;
}
}
};
bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); }
bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); }
bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; }
/** A base58-encoded secret key */
class CBitcoinSecret : public CBase58Data
{
public:
enum
{
PRIVKEY_ADDRESS = CBitcoinAddress::PUBKEY_ADDRESS + 128,
PRIVKEY_ADDRESS_TEST = CBitcoinAddress::PUBKEY_ADDRESS_TEST + 128,
};
void SetSecret(const CSecret& vchSecret, bool fCompressed)
{
assert(vchSecret.size() == 32);
SetData(fTestNet ? PRIVKEY_ADDRESS_TEST : PRIVKEY_ADDRESS, &vchSecret[0], vchSecret.size());
if (fCompressed)
vchData.push_back(1);
}
CSecret GetSecret(bool &fCompressedOut)
{
CSecret vchSecret;
vchSecret.resize(32);
memcpy(&vchSecret[0], &vchData[0], 32);
fCompressedOut = vchData.size() == 33;
return vchSecret;
}
bool IsValid() const
{
bool fExpectTestNet = false;
switch(nVersion)
{
case PRIVKEY_ADDRESS:
break;
case PRIVKEY_ADDRESS_TEST:
fExpectTestNet = true;
break;
default:
return false;
}
return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1));
}
bool SetString(const char* pszSecret)
{
return CBase58Data::SetString(pszSecret) && IsValid();
}
bool SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}
CBitcoinSecret(const CSecret& vchSecret, bool fCompressed)
{
SetSecret(vchSecret, fCompressed);
}
CBitcoinSecret()
{
}
};
#endif

550
src/bignum.h Normal file
View File

@@ -0,0 +1,550 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING 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" // for uint64
/** Errors thrown by the bignum class */
class bignum_error : public std::runtime_error
{
public:
explicit bignum_error(const std::string& str) : std::runtime_error(str) {}
};
/** RAII encapsulated BN_CTX (OpenSSL bignum context) */
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); }
};
/** C++ wrapper for BIGNUM (OpenSSL bignum) */
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) is not portable. Use 'signed char' or 'unsigned char'.
CBigNum(signed 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 > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
else
return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
}
void setint64(int64 sn)
{
unsigned char pch[sizeof(sn) + 6];
unsigned char* p = pch + 4;
bool fNegative;
uint64 n;
if (sn < (int64)0)
{
// Since the minimum signed integer cannot be represented as positive so long as its type is signed, and it's not well-defined what happens if you make it unsigned before negating it, we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate
n = -(sn + 1);
++n;
fNegative = true;
} else {
n = sn;
fNegative = false;
}
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 (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
((unsigned char*)&n)[i] = vch[j];
return n;
}
void setvch(const std::vector<unsigned char>& vch)
{
std::vector<unsigned char> vch2(vch.size() + 4);
unsigned int nSize = vch.size();
// BIGNUM's byte stream format expects 4 bytes of
// big endian size data info at the front
vch2[0] = (nSize >> 24) & 0xff;
vch2[1] = (nSize >> 16) & 0xff;
vch2[2] = (nSize >> 8) & 0xff;
vch2[3] = (nSize >> 0) & 0xff;
// swap data to big endian
reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4);
BN_mpi2bn(&vch2[0], vch2.size(), this);
}
std::vector<unsigned char> getvch() const
{
unsigned int nSize = BN_bn2mpi(this, NULL);
if (nSize <= 4)
return std::vector<unsigned char>();
std::vector<unsigned char> vch(nSize);
BN_bn2mpi(this, &vch[0]);
vch.erase(vch.begin(), vch.begin() + 4);
reverse(vch.begin(), vch.end());
return vch;
}
CBigNum& SetCompact(unsigned int nCompact)
{
unsigned int nSize = nCompact >> 24;
std::vector<unsigned char> vch(4 + nSize);
vch[3] = nSize;
if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff;
if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff;
if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff;
BN_mpi2bn(&vch[0], vch.size(), this);
return *this;
}
unsigned int GetCompact() const
{
unsigned int nSize = BN_bn2mpi(this, NULL);
std::vector<unsigned char> vch(nSize);
nSize -= 4;
BN_bn2mpi(this, &vch[0]);
unsigned int nCompact = nSize << 24;
if (nSize >= 1) nCompact |= (vch[4] << 16);
if (nSize >= 2) nCompact |= (vch[5] << 8);
if (nSize >= 3) nCompact |= (vch[6] << 0);
return nCompact;
}
void SetHex(const std::string& str)
{
// skip 0x
const char* psz = str.c_str();
while (isspace(*psz))
psz++;
bool fNegative = false;
if (*psz == '-')
{
fNegative = true;
psz++;
}
if (psz[0] == '0' && tolower(psz[1]) == 'x')
psz += 2;
while (isspace(*psz))
psz++;
// hex string to bignum
static signed 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[(unsigned char)*psz++];
*this += n;
}
if (fNegative)
*this = 0 - *this;
}
std::string ToString(int nBase=10) const
{
CAutoBN_CTX pctx;
CBigNum bnBase = nBase;
CBigNum bn0 = 0;
std::string str;
CBigNum bn = *this;
BN_set_negative(&bn, false);
CBigNum dv;
CBigNum rem;
if (BN_cmp(&bn, &bn0) == 0)
return "0";
while (BN_cmp(&bn, &bn0) > 0)
{
if (!BN_div(&dv, &rem, &bn, &bnBase, pctx))
throw bignum_error("CBigNum::ToString() : BN_div failed");
bn = dv;
unsigned int c = rem.getulong();
str += "0123456789abcdef"[c];
}
if (BN_is_negative(this))
str += "-";
reverse(str.begin(), str.end());
return str;
}
std::string GetHex() const
{
return ToString(16);
}
unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
{
return ::GetSerializeSize(getvch(), nType, nVersion);
}
template<typename Stream>
void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
{
::Serialize(s, getvch(), nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
{
std::vector<unsigned char> vch;
::Unserialize(s, vch, nType, nVersion);
setvch(vch);
}
bool operator!() const
{
return BN_is_zero(this);
}
CBigNum& operator+=(const CBigNum& b)
{
if (!BN_add(this, this, &b))
throw bignum_error("CBigNum::operator+= : BN_add failed");
return *this;
}
CBigNum& operator-=(const CBigNum& b)
{
*this = *this - b;
return *this;
}
CBigNum& operator*=(const CBigNum& b)
{
CAutoBN_CTX pctx;
if (!BN_mul(this, this, &b, pctx))
throw bignum_error("CBigNum::operator*= : BN_mul failed");
return *this;
}
CBigNum& operator/=(const CBigNum& b)
{
*this = *this / b;
return *this;
}
CBigNum& operator%=(const CBigNum& b)
{
*this = *this % b;
return *this;
}
CBigNum& operator<<=(unsigned int shift)
{
if (!BN_lshift(this, this, shift))
throw bignum_error("CBigNum:operator<<= : BN_lshift failed");
return *this;
}
CBigNum& operator>>=(unsigned int shift)
{
// Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
// if built on ubuntu 9.04 or 9.10, probably depends on version of openssl
CBigNum a = 1;
a <<= shift;
if (BN_cmp(&a, this) > 0)
{
*this = 0;
return *this;
}
if (!BN_rshift(this, this, shift))
throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
return *this;
}
CBigNum& operator++()
{
// prefix operator
if (!BN_add(this, this, BN_value_one()))
throw bignum_error("CBigNum::operator++ : BN_add failed");
return *this;
}
const CBigNum operator++(int)
{
// postfix operator
const CBigNum ret = *this;
++(*this);
return ret;
}
CBigNum& operator--()
{
// prefix operator
CBigNum r;
if (!BN_sub(&r, this, BN_value_one()))
throw bignum_error("CBigNum::operator-- : BN_sub failed");
*this = r;
return *this;
}
const CBigNum operator--(int)
{
// postfix operator
const CBigNum ret = *this;
--(*this);
return ret;
}
friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b);
friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b);
};
inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
{
CBigNum r;
if (!BN_add(&r, &a, &b))
throw bignum_error("CBigNum::operator+ : BN_add failed");
return r;
}
inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
{
CBigNum r;
if (!BN_sub(&r, &a, &b))
throw bignum_error("CBigNum::operator- : BN_sub failed");
return r;
}
inline const CBigNum operator-(const CBigNum& a)
{
CBigNum r(a);
BN_set_negative(&r, !BN_is_negative(&r));
return r;
}
inline const CBigNum operator*(const CBigNum& a, const CBigNum& b)
{
CAutoBN_CTX pctx;
CBigNum r;
if (!BN_mul(&r, &a, &b, pctx))
throw bignum_error("CBigNum::operator* : BN_mul failed");
return r;
}
inline const CBigNum operator/(const CBigNum& a, const CBigNum& b)
{
CAutoBN_CTX pctx;
CBigNum r;
if (!BN_div(&r, NULL, &a, &b, pctx))
throw bignum_error("CBigNum::operator/ : BN_div failed");
return r;
}
inline const CBigNum operator%(const CBigNum& a, const CBigNum& b)
{
CAutoBN_CTX pctx;
CBigNum r;
if (!BN_mod(&r, &a, &b, pctx))
throw bignum_error("CBigNum::operator% : BN_div failed");
return r;
}
inline const CBigNum operator<<(const CBigNum& a, unsigned int shift)
{
CBigNum r;
if (!BN_lshift(&r, &a, shift))
throw bignum_error("CBigNum:operator<< : BN_lshift failed");
return r;
}
inline const CBigNum operator>>(const CBigNum& a, unsigned int shift)
{
CBigNum r = a;
r >>= shift;
return r;
}
inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); }
inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); }
inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); }
inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); }
inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); }
inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); }
#endif

3399
src/bitcoinrpc.cpp Normal file

File diff suppressed because it is too large Load Diff

75
src/bitcoinrpc.h Normal file
View File

@@ -0,0 +1,75 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _BITCOINRPC_H_
#define _BITCOINRPC_H_ 1
#include <string>
#include <list>
#include <map>
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"
json_spirit::Object JSONRPCError(int code, const std::string& message);
void ThreadRPCServer(void* parg);
int CommandLineRPC(int argc, char *argv[]);
/** Convert parameter values for RPC call from strings to command-specific JSON objects. */
json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams);
/*
Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
the right number of arguments are passed, just that any passed are the correct type.
Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type));
*/
void RPCTypeCheck(const json_spirit::Array& params,
const std::list<json_spirit::Value_type>& typesExpected);
/*
Check for expected keys/value types in an Object.
Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type));
*/
void RPCTypeCheck(const json_spirit::Object& o,
const std::map<std::string, json_spirit::Value_type>& typesExpected);
typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp);
class CRPCCommand
{
public:
std::string name;
rpcfn_type actor;
bool okSafeMode;
};
/**
* Bitcoin RPC command dispatcher.
*/
class CRPCTable
{
private:
std::map<std::string, const CRPCCommand*> mapCommands;
public:
CRPCTable();
const CRPCCommand* operator[](std::string name) const;
std::string help(std::string name) const;
/**
* Execute a method.
* @param method Method to execute
* @param params Array of arguments (JSON objects)
* @returns Result of the call.
* @throws an exception (json_spirit::Value) when an error happens.
*/
json_spirit::Value execute(const std::string &method, const json_spirit::Array &params) const;
};
extern const CRPCTable tableRPC;
#endif

60
src/checkpoints.cpp Normal file
View File

@@ -0,0 +1,60 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>
#include "checkpoints.h"
#include "main.h"
#include "uint256.h"
namespace Checkpoints
{
typedef std::map<int, uint256> MapCheckpoints;
//
// What makes a good checkpoint block?
// + Is surrounded by blocks with reasonable timestamps
// (no blocks before with a timestamp after, none after with
// timestamp before)
// + Contains no strange transactions
//
static MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 0, uint256("0x4f46c9af6d88a14114b7dc53a37d81ba4064cda5ae2ede1213ca28fea9b86e9c"))
;
bool CheckBlock(int nHeight, const uint256& hash)
{
if (fTestNet) return true; // Testnet has no checkpoints
MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight);
if (i == mapCheckpoints.end()) return true;
return hash == i->second;
}
int GetTotalBlocksEstimate()
{
if (fTestNet) return 0;
return mapCheckpoints.rbegin()->first;
}
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
{
if (fTestNet) return NULL;
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
{
const uint256& hash = i.second;
std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
if (t != mapBlockIndex.end())
return t->second;
}
return NULL;
}
}

29
src/checkpoints.h Normal file
View File

@@ -0,0 +1,29 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_CHECKPOINT_H
#define BITCOIN_CHECKPOINT_H
#include <map>
class uint256;
class CBlockIndex;
/** Block-chain checkpoints are compiled-in sanity checks.
* They are updated every release or three.
*/
namespace Checkpoints
{
// Returns true if block passes checkpoint checks
bool CheckBlock(int nHeight, const uint256& hash);
// Return conservative estimate of total number of blocks, 0 if unknown
int GetTotalBlocksEstimate();
// Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex);
}
#endif

65
src/compat.h Normal file
View File

@@ -0,0 +1,65 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _BITCOIN_COMPAT_H
#define _BITCOIN_COMPAT_H 1
#ifdef WIN32
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/fcntl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <netinet/in.h>
#include <ifaddrs.h>
#endif
typedef u_int SOCKET;
#ifdef WIN32
#define MSG_NOSIGNAL 0
#define MSG_DONTWAIT 0
typedef int socklen_t;
#else
#include "errno.h"
#define WSAGetLastError() errno
#define WSAEINVAL EINVAL
#define WSAEALREADY EALREADY
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEMSGSIZE EMSGSIZE
#define WSAEINTR EINTR
#define WSAEINPROGRESS EINPROGRESS
#define WSAEADDRINUSE EADDRINUSE
#define WSAENOTSOCK EBADF
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR -1
#endif
inline int myclosesocket(SOCKET& hSocket)
{
if (hSocket == INVALID_SOCKET)
return WSAENOTSOCK;
#ifdef WIN32
int ret = closesocket(hSocket);
#else
int ret = close(hSocket);
#endif
hSocket = INVALID_SOCKET;
return ret;
}
#define closesocket(s) myclosesocket(s)
#endif

135
src/crypter.cpp Normal file
View File

@@ -0,0 +1,135 @@
// Copyright (c) 2009-2012 The Bitcoin Developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <vector>
#include <string>
#ifdef WIN32
#include <windows.h>
#endif
#include "crypter.h"
bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
return false;
// Try to keep the keydata out of swap (and be a bit over-careful to keep the IV that we don't even use out of swap)
// Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
// Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
mlock(&chKey[0], sizeof chKey);
mlock(&chIV[0], sizeof chIV);
int i = 0;
if (nDerivationMethod == 0)
i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
(unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
if (i != (int)WALLET_CRYPTO_KEY_SIZE)
{
memset(&chKey, 0, sizeof chKey);
memset(&chIV, 0, sizeof chIV);
return false;
}
fKeySet = true;
return true;
}
bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
{
if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
return false;
// Try to keep the keydata out of swap
// Note that this does nothing about suspend-to-disk (which will put all our key data on disk)
// Note as well that at no point in this program is any attempt made to prevent stealing of keys by reading the memory of the running process.
mlock(&chKey[0], sizeof chKey);
mlock(&chIV[0], sizeof chIV);
memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
memcpy(&chIV[0], &chNewIV[0], sizeof chIV);
fKeySet = true;
return true;
}
bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext)
{
if (!fKeySet)
return false;
// max ciphertext len for a n bytes of plaintext is
// n + AES_BLOCK_SIZE - 1 bytes
int nLen = vchPlaintext.size();
int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
vchCiphertext = std::vector<unsigned char> (nCLen);
EVP_CIPHER_CTX ctx;
bool fOk = true;
EVP_CIPHER_CTX_init(&ctx);
if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen);
if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0])+nCLen, &nFLen);
EVP_CIPHER_CTX_cleanup(&ctx);
if (!fOk) return false;
vchCiphertext.resize(nCLen + nFLen);
return true;
}
bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
{
if (!fKeySet)
return false;
// plaintext will always be equal to or lesser than length of ciphertext
int nLen = vchCiphertext.size();
int nPLen = nLen, nFLen = 0;
vchPlaintext = CKeyingMaterial(nPLen);
EVP_CIPHER_CTX ctx;
bool fOk = true;
EVP_CIPHER_CTX_init(&ctx);
if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV);
if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen);
if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0])+nPLen, &nFLen);
EVP_CIPHER_CTX_cleanup(&ctx);
if (!fOk) return false;
vchPlaintext.resize(nPLen + nFLen);
return true;
}
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
}
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
}

102
src/crypter.h Normal file
View File

@@ -0,0 +1,102 @@
// Copyright (c) 2009-2012 The Bitcoin Developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef __CRYPTER_H__
#define __CRYPTER_H__
#include "allocators.h" /* for SecureString */
#include "key.h"
#include "serialize.h"
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
/*
Private key encryption is done based on a CMasterKey,
which holds a salt and random encryption key.
CMasterKeys are encrypted using AES-256-CBC using a key
derived using derivation method nDerivationMethod
(0 == EVP_sha512()) and derivation iterations nDeriveIterations.
vchOtherDerivationParameters is provided for alternative algorithms
which may require more parameters (such as scrypt).
Wallet Private Keys are then encrypted using AES-256-CBC
with the double-sha256 of the public key as the IV, and the
master key's key as the encryption key (see keystore.[ch]).
*/
/** Master key for wallet encryption */
class CMasterKey
{
public:
std::vector<unsigned char> vchCryptedKey;
std::vector<unsigned char> vchSalt;
// 0 = EVP_sha512()
// 1 = scrypt()
unsigned int nDerivationMethod;
unsigned int nDeriveIterations;
// Use this for more parameters to key derivation,
// such as the various parameters to scrypt
std::vector<unsigned char> vchOtherDerivationParameters;
IMPLEMENT_SERIALIZE
(
READWRITE(vchCryptedKey);
READWRITE(vchSalt);
READWRITE(nDerivationMethod);
READWRITE(nDeriveIterations);
READWRITE(vchOtherDerivationParameters);
)
CMasterKey()
{
// 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M
// ie slightly lower than the lowest hardware we need bother supporting
nDeriveIterations = 25000;
nDerivationMethod = 0;
vchOtherDerivationParameters = std::vector<unsigned char>(0);
}
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
/** Encryption/decryption context with key information */
class CCrypter
{
private:
unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
unsigned char chIV[WALLET_CRYPTO_KEY_SIZE];
bool fKeySet;
public:
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod);
bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext);
bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext);
bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV);
void CleanKey()
{
memset(&chKey, 0, sizeof chKey);
memset(&chIV, 0, sizeof chIV);
munlock(&chKey, sizeof chKey);
munlock(&chIV, sizeof chIV);
fKeySet = false;
}
CCrypter()
{
fKeySet = false;
}
~CCrypter()
{
CleanKey();
}
};
bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char> &vchCiphertext, const uint256& nIV, CSecret &vchPlaintext);
#endif

842
src/db.cpp Normal file
View File

@@ -0,0 +1,842 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "db.h"
#include "util.h"
#include "main.h"
#include "init.h"
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#ifndef WIN32
#include "sys/stat.h"
#endif
using namespace std;
using namespace boost;
unsigned int nWalletDBUpdated;
//
// CDB
//
CDBEnv bitdb;
void CDBEnv::EnvShutdown()
{
if (!fDbEnvInit)
return;
fDbEnvInit = false;
try
{
dbenv.close(0);
}
catch (const DbException& e)
{
printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno());
}
DbEnv(0).remove(GetDataDir().string().c_str(), 0);
}
CDBEnv::CDBEnv() : dbenv(0)
{
}
CDBEnv::~CDBEnv()
{
EnvShutdown();
}
void CDBEnv::Close()
{
EnvShutdown();
}
bool CDBEnv::Open(boost::filesystem::path pathEnv_)
{
if (fDbEnvInit)
return true;
if (fShutdown)
return false;
pathEnv = pathEnv_;
filesystem::path pathDataDir = pathEnv;
filesystem::path pathLogDir = pathDataDir / "database";
filesystem::create_directory(pathLogDir);
filesystem::path pathErrorFile = pathDataDir / "db.log";
printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str());
unsigned int nEnvFlags = 0;
if (GetBoolArg("-privdb", true))
nEnvFlags |= DB_PRIVATE;
int nDbCache = GetArg("-dbcache", 25);
dbenv.set_lg_dir(pathLogDir.string().c_str());
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
dbenv.set_lg_bsize(1048576);
dbenv.set_lg_max(10485760);
dbenv.set_lk_max_locks(537000);
dbenv.set_lk_max_objects(10000);
dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
dbenv.set_flags(DB_AUTO_COMMIT, 1);
dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
int ret = dbenv.open(pathDataDir.string().c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
DB_INIT_MPOOL |
DB_INIT_TXN |
DB_THREAD |
DB_RECOVER |
nEnvFlags,
S_IRUSR | S_IWUSR);
if (ret > 0)
return error("CDB() : error %d opening database environment", ret);
// Check that the number of locks is sufficient
u_int32_t nMaxLocks;
if (!dbenv.get_lk_max_locks(&nMaxLocks))
{
int nBlocks, nDeepReorg;
std::string strMessage;
nBlocks = nMaxLocks / 48768;
nDeepReorg = (nBlocks - 1) / 2;
printf("Final lk_max_locks is %lu, sufficient for (worst case) %d block%s in a single transaction (up to a %d-deep reorganization)\n", (unsigned long)nMaxLocks, nBlocks, (nBlocks == 1) ? "" : "s", nDeepReorg);
if (nDeepReorg < 3)
{
if (nBlocks < 1)
strMessage = strprintf(_("Warning: DB_CONFIG has set_lk_max_locks %lu, which may be too low for a single block. If this limit is reached, Bitcoin may stop working."), (unsigned long)nMaxLocks);
else
strMessage = strprintf(_("Warning: DB_CONFIG has set_lk_max_locks %lu, which may be too low for a common blockchain reorganization. If this limit is reached, Bitcoin may stop working."), (unsigned long)nMaxLocks);
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
}
}
fDbEnvInit = true;
return true;
}
void CDBEnv::CheckpointLSN(std::string strFile)
{
dbenv.txn_checkpoint(0, 0, 0);
dbenv.lsn_reset(strFile.c_str(), 0);
}
CDB::CDB(const char *pszFile, const char* pszMode) :
pdb(NULL), activeTxn(NULL)
{
int ret;
if (pszFile == NULL)
return;
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
bool fCreate = strchr(pszMode, 'c');
unsigned int nFlags = DB_THREAD;
if (fCreate)
nFlags |= DB_CREATE;
{
LOCK(bitdb.cs_db);
if (!bitdb.Open(GetDataDir()))
throw runtime_error("env open failed");
strFile = pszFile;
++bitdb.mapFileUseCount[strFile];
pdb = bitdb.mapDb[strFile];
if (pdb == NULL)
{
pdb = new Db(&bitdb.dbenv, 0);
ret = pdb->open(NULL, // Txn pointer
pszFile, // Filename
"main", // Logical db name
DB_BTREE, // Database type
nFlags, // Flags
0);
if (ret > 0)
{
delete pdb;
pdb = NULL;
{
LOCK(bitdb.cs_db);
--bitdb.mapFileUseCount[strFile];
}
strFile = "";
throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
}
if (fCreate && !Exists(string("version")))
{
bool fTmp = fReadOnly;
fReadOnly = false;
WriteVersion(CLIENT_VERSION);
fReadOnly = fTmp;
}
bitdb.mapDb[strFile] = pdb;
}
}
}
static bool IsChainFile(std::string strFile)
{
if (strFile == "blkindex.dat")
return true;
return false;
}
void CDB::Close()
{
if (!pdb)
return;
if (activeTxn)
activeTxn->abort();
activeTxn = NULL;
pdb = NULL;
// Flush database activity from memory pool to disk log
unsigned int nMinutes = 0;
if (fReadOnly)
nMinutes = 1;
if (IsChainFile(strFile))
nMinutes = 2;
if (IsChainFile(strFile) && IsInitialBlockDownload())
nMinutes = 5;
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
{
LOCK(bitdb.cs_db);
--bitdb.mapFileUseCount[strFile];
}
}
void CDBEnv::CloseDb(const string& strFile)
{
{
LOCK(cs_db);
if (mapDb[strFile] != NULL)
{
// Close the database handle
Db* pdb = mapDb[strFile];
pdb->close(0);
delete pdb;
mapDb[strFile] = NULL;
}
}
}
bool CDB::Rewrite(const string& strFile, const char* pszSkip)
{
while (!fShutdown)
{
{
LOCK(bitdb.cs_db);
if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0)
{
// Flush log data to the dat file
bitdb.CloseDb(strFile);
bitdb.CheckpointLSN(strFile);
bitdb.mapFileUseCount.erase(strFile);
bool fSuccess = true;
printf("Rewriting %s...\n", strFile.c_str());
string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {}
CDB db(strFile.c_str(), "r");
Db* pdbCopy = new Db(&bitdb.dbenv, 0);
int ret = pdbCopy->open(NULL, // Txn pointer
strFileRes.c_str(), // Filename
"main", // Logical db name
DB_BTREE, // Database type
DB_CREATE, // Flags
0);
if (ret > 0)
{
printf("Cannot create database file %s\n", strFileRes.c_str());
fSuccess = false;
}
Dbc* pcursor = db.GetCursor();
if (pcursor)
while (fSuccess)
{
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
if (ret == DB_NOTFOUND)
{
pcursor->close();
break;
}
else if (ret != 0)
{
pcursor->close();
fSuccess = false;
break;
}
if (pszSkip &&
strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
continue;
if (strncmp(&ssKey[0], "\x07version", 8) == 0)
{
// Update version:
ssValue.clear();
ssValue << CLIENT_VERSION;
}
Dbt datKey(&ssKey[0], ssKey.size());
Dbt datValue(&ssValue[0], ssValue.size());
int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
if (ret2 > 0)
fSuccess = false;
}
if (fSuccess)
{
db.Close();
bitdb.CloseDb(strFile);
if (pdbCopy->close(0))
fSuccess = false;
delete pdbCopy;
}
}
if (fSuccess)
{
Db dbA(&bitdb.dbenv, 0);
if (dbA.remove(strFile.c_str(), NULL, 0))
fSuccess = false;
Db dbB(&bitdb.dbenv, 0);
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
fSuccess = false;
}
if (!fSuccess)
printf("Rewriting of %s FAILED!\n", strFileRes.c_str());
return fSuccess;
}
}
Sleep(100);
}
return false;
}
void CDBEnv::Flush(bool fShutdown)
{
int64 nStart = GetTimeMillis();
// Flush log data to the actual data file
// on all files that are not in use
printf("Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
if (!fDbEnvInit)
return;
{
LOCK(cs_db);
map<string, int>::iterator mi = mapFileUseCount.begin();
while (mi != mapFileUseCount.end())
{
string strFile = (*mi).first;
int nRefCount = (*mi).second;
printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
if (nRefCount == 0)
{
// Move log data to the dat file
CloseDb(strFile);
printf("%s checkpoint\n", strFile.c_str());
dbenv.txn_checkpoint(0, 0, 0);
if (!IsChainFile(strFile) || fDetachDB) {
printf("%s detach\n", strFile.c_str());
dbenv.lsn_reset(strFile.c_str(), 0);
}
printf("%s closed\n", strFile.c_str());
mapFileUseCount.erase(mi++);
}
else
mi++;
}
printf("DBFlush(%s)%s ended %15"PRI64d"ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart);
if (fShutdown)
{
char** listp;
if (mapFileUseCount.empty())
{
dbenv.log_archive(&listp, DB_ARCH_REMOVE);
Close();
}
}
}
}
//
// CTxDB
//
bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
{
assert(!fClient);
txindex.SetNull();
return Read(make_pair(string("tx"), hash), txindex);
}
bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
{
assert(!fClient);
return Write(make_pair(string("tx"), hash), txindex);
}
bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
{
assert(!fClient);
// Add to tx index
uint256 hash = tx.GetHash();
CTxIndex txindex(pos, tx.vout.size());
return Write(make_pair(string("tx"), hash), txindex);
}
bool CTxDB::EraseTxIndex(const CTransaction& tx)
{
assert(!fClient);
uint256 hash = tx.GetHash();
return Erase(make_pair(string("tx"), hash));
}
bool CTxDB::ContainsTx(uint256 hash)
{
assert(!fClient);
return Exists(make_pair(string("tx"), hash));
}
bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
{
assert(!fClient);
tx.SetNull();
if (!ReadTxIndex(hash, txindex))
return false;
return (tx.ReadFromDisk(txindex.pos));
}
bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
{
CTxIndex txindex;
return ReadDiskTx(hash, tx, txindex);
}
bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
{
return ReadDiskTx(outpoint.hash, tx, txindex);
}
bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
{
CTxIndex txindex;
return ReadDiskTx(outpoint.hash, tx, txindex);
}
bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
{
return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
}
bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
{
return Read(string("hashBestChain"), hashBestChain);
}
bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
{
return Write(string("hashBestChain"), hashBestChain);
}
bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
{
return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
}
bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
{
return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
}
CBlockIndex static * InsertBlockIndex(uint256 hash)
{
if (hash == 0)
return NULL;
// Return existing
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
return (*mi).second;
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
if (!pindexNew)
throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
return pindexNew;
}
bool CTxDB::LoadBlockIndex()
{
if (!LoadBlockIndexGuts())
return false;
if (fRequestShutdown)
return true;
// Calculate bnChainWork
vector<pair<int, CBlockIndex*> > vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size());
BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
{
CBlockIndex* pindex = item.second;
vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
}
sort(vSortedByHeight.begin(), vSortedByHeight.end());
BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
{
CBlockIndex* pindex = item.second;
pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
}
// Load hashBestChain pointer to end of best chain
if (!ReadHashBestChain(hashBestChain))
{
if (pindexGenesisBlock == NULL)
return true;
return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
}
if (!mapBlockIndex.count(hashBestChain))
return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
pindexBest = mapBlockIndex[hashBestChain];
nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexBest->bnChainWork;
printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n",
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
// Load bnBestInvalidWork, OK if it doesn't exist
ReadBestInvalidWork(bnBestInvalidWork);
// Verify blocks in the best chain
int nCheckLevel = GetArg("-checklevel", 1);
int nCheckDepth = GetArg( "-checkblocks", 2500);
if (nCheckDepth == 0)
nCheckDepth = 1000000000; // suffices until the year 19000
if (nCheckDepth > nBestHeight)
nCheckDepth = nBestHeight;
printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
CBlockIndex* pindexFork = NULL;
map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{
if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
break;
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("LoadBlockIndex() : block.ReadFromDisk failed");
// check level 1: verify block validity
if (nCheckLevel>0 && !block.CheckBlock())
{
printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
pindexFork = pindex->pprev;
}
// check level 2: verify transaction index validity
if (nCheckLevel>1)
{
pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
mapBlockPos[pos] = pindex;
BOOST_FOREACH(const CTransaction &tx, block.vtx)
{
uint256 hashTx = tx.GetHash();
CTxIndex txindex;
if (ReadTxIndex(hashTx, txindex))
{
// check level 3: checker transaction hashes
if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
{
// either an error or a duplicate transaction
CTransaction txFound;
if (!txFound.ReadFromDisk(txindex.pos))
{
printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
pindexFork = pindex->pprev;
}
else
if (txFound.GetHash() != hashTx) // not a duplicate tx
{
printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
pindexFork = pindex->pprev;
}
}
// check level 4: check whether spent txouts were spent within the main chain
unsigned int nOutput = 0;
if (nCheckLevel>3)
{
BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
{
if (!txpos.IsNull())
{
pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
if (!mapBlockPos.count(posFind))
{
printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
pindexFork = pindex->pprev;
}
// check level 6: check whether spent txouts were spent by a valid transaction that consume them
if (nCheckLevel>5)
{
CTransaction txSpend;
if (!txSpend.ReadFromDisk(txpos))
{
printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
pindexFork = pindex->pprev;
}
else if (!txSpend.CheckTransaction())
{
printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
pindexFork = pindex->pprev;
}
else
{
bool fFound = false;
BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
fFound = true;
if (!fFound)
{
printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
pindexFork = pindex->pprev;
}
}
}
}
nOutput++;
}
}
}
// check level 5: check whether all prevouts are marked spent
if (nCheckLevel>4)
{
BOOST_FOREACH(const CTxIn &txin, tx.vin)
{
CTxIndex txindex;
if (ReadTxIndex(txin.prevout.hash, txindex))
if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
{
printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
pindexFork = pindex->pprev;
}
}
}
}
}
}
if (pindexFork && !fRequestShutdown)
{
// Reorg back to the fork
printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
CBlock block;
if (!block.ReadFromDisk(pindexFork))
return error("LoadBlockIndex() : block.ReadFromDisk failed");
CTxDB txdb;
block.SetBestChain(txdb, pindexFork);
}
return true;
}
bool CTxDB::LoadBlockIndexGuts()
{
// Get database cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
return false;
// Load mapBlockIndex
unsigned int fFlags = DB_SET_RANGE;
loop
{
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
if (fFlags == DB_SET_RANGE)
ssKey << make_pair(string("blockindex"), uint256(0));
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
fFlags = DB_NEXT;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
return false;
// Unserialize
try {
string strType;
ssKey >> strType;
if (strType == "blockindex" && !fRequestShutdown)
{
CDiskBlockIndex diskindex;
ssValue >> diskindex;
// Construct block index object
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
pindexNew->pnext = InsertBlockIndex(diskindex.hashNext);
pindexNew->nFile = diskindex.nFile;
pindexNew->nBlockPos = diskindex.nBlockPos;
pindexNew->nHeight = diskindex.nHeight;
pindexNew->nVersion = diskindex.nVersion;
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
pindexNew->nTime = diskindex.nTime;
pindexNew->nBits = diskindex.nBits;
pindexNew->nNonce = diskindex.nNonce;
// Watch for genesis block
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
pindexGenesisBlock = pindexNew;
if (!pindexNew->CheckIndex())
return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
}
else
{
break; // if shutdown requested or finished loading block index
}
} // try
catch (std::exception &e) {
return error("%s() : deserialize error", __PRETTY_FUNCTION__);
}
}
pcursor->close();
return true;
}
//
// CAddrDB
//
CAddrDB::CAddrDB()
{
pathAddr = GetDataDir() / "peers.dat";
}
bool CAddrDB::Write(const CAddrMan& addr)
{
// Generate random temporary filename
unsigned short randv = 0;
RAND_bytes((unsigned char *)&randv, sizeof(randv));
std::string tmpfn = strprintf("peers.dat.%04x", randv);
// serialize addresses, checksum data up to that point, then append csum
CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
ssPeers << FLATDATA(pchMessageStart);
ssPeers << addr;
uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
ssPeers << hash;
// open temp output file, and associate with CAutoFile
boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
FILE *file = fopen(pathTmp.string().c_str(), "wb");
CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION);
if (!fileout)
return error("CAddrman::Write() : open failed");
// Write and commit header, data
try {
fileout << ssPeers;
}
catch (std::exception &e) {
return error("CAddrman::Write() : I/O error");
}
FileCommit(fileout);
fileout.fclose();
// replace existing peers.dat, if any, with new peers.dat.XXXX
if (!RenameOver(pathTmp, pathAddr))
return error("CAddrman::Write() : Rename-into-place failed");
return true;
}
bool CAddrDB::Read(CAddrMan& addr)
{
// open input file, and associate with CAutoFile
FILE *file = fopen(pathAddr.string().c_str(), "rb");
CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION);
if (!filein)
return error("CAddrman::Read() : open failed");
// use file size to size memory buffer
int fileSize = GetFilesize(filein);
int dataSize = fileSize - sizeof(uint256);
vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
// read data and checksum from file
try {
filein.read((char *)&vchData[0], dataSize);
filein >> hashIn;
}
catch (std::exception &e) {
return error("CAddrman::Read() 2 : I/O error or stream data corrupted");
}
filein.fclose();
CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
// verify stored checksum matches input data
uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
if (hashIn != hashTmp)
return error("CAddrman::Read() : checksum mismatch; data corrupted");
// de-serialize address data
unsigned char pchMsgTmp[4];
try {
ssPeers >> FLATDATA(pchMsgTmp);
ssPeers >> addr;
}
catch (std::exception &e) {
return error("CAddrman::Read() : I/O error or stream data corrupted");
}
// finally, verify the network matches ours
if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp)))
return error("CAddrman::Read() : invalid network magic number");
return true;
}

340
src/db.h Normal file
View File

@@ -0,0 +1,340 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_DB_H
#define BITCOIN_DB_H
#include "main.h"
#include <map>
#include <string>
#include <vector>
#include <db_cxx.h>
class CAddress;
class CAddrMan;
class CBlockLocator;
class CDiskBlockIndex;
class CDiskTxPos;
class CMasterKey;
class COutPoint;
class CTxIndex;
class CWallet;
class CWalletTx;
extern unsigned int nWalletDBUpdated;
void ThreadFlushWalletDB(void* parg);
bool BackupWallet(const CWallet& wallet, const std::string& strDest);
class CDBEnv
{
private:
bool fDetachDB;
bool fDbEnvInit;
boost::filesystem::path pathEnv;
void EnvShutdown();
public:
mutable CCriticalSection cs_db;
DbEnv dbenv;
std::map<std::string, int> mapFileUseCount;
std::map<std::string, Db*> mapDb;
CDBEnv();
~CDBEnv();
bool Open(boost::filesystem::path pathEnv_);
void Close();
void Flush(bool fShutdown);
void CheckpointLSN(std::string strFile);
void SetDetach(bool fDetachDB_) { fDetachDB = fDetachDB_; }
bool GetDetach() { return fDetachDB; }
void CloseDb(const std::string& strFile);
DbTxn *TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
{
DbTxn* ptxn = NULL;
int ret = dbenv.txn_begin(NULL, &ptxn, flags);
if (!ptxn || ret != 0)
return NULL;
return ptxn;
}
};
extern CDBEnv bitdb;
/** RAII class that provides access to a Berkeley database */
class CDB
{
protected:
Db* pdb;
std::string strFile;
DbTxn *activeTxn;
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, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Read
Dbt datValue;
datValue.set_flags(DB_DBT_MALLOC);
int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
memset(datKey.get_data(), 0, datKey.get_size());
if (datValue.get_data() == NULL)
return false;
// Unserialize value
try {
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
ssValue >> value;
}
catch (std::exception &e) {
return false;
}
// Clear and free memory
memset(datValue.get_data(), 0, datValue.get_size());
free(datValue.get_data());
return (ret == 0);
}
template<typename K, typename T>
bool Write(const K& key, const T& value, bool fOverwrite=true)
{
if (!pdb)
return false;
if (fReadOnly)
assert(!"Write called on database in read-only mode");
// Key
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Value
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
ssValue.reserve(10000);
ssValue << value;
Dbt datValue(&ssValue[0], ssValue.size());
// Write
int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
// Clear memory in case it was a private key
memset(datKey.get_data(), 0, datKey.get_size());
memset(datValue.get_data(), 0, datValue.get_size());
return (ret == 0);
}
template<typename K>
bool Erase(const K& key)
{
if (!pdb)
return false;
if (fReadOnly)
assert(!"Erase called on database in read-only mode");
// Key
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Erase
int ret = pdb->del(activeTxn, &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, CLIENT_VERSION);
ssKey.reserve(1000);
ssKey << key;
Dbt datKey(&ssKey[0], ssKey.size());
// Exists
int ret = pdb->exists(activeTxn, &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;
}
public:
bool TxnBegin()
{
if (!pdb || activeTxn)
return false;
DbTxn* ptxn = bitdb.TxnBegin();
if (!ptxn)
return false;
activeTxn = ptxn;
return true;
}
bool TxnCommit()
{
if (!pdb || !activeTxn)
return false;
int ret = activeTxn->commit(0);
activeTxn = NULL;
return (ret == 0);
}
bool TxnAbort()
{
if (!pdb || !activeTxn)
return false;
int ret = activeTxn->abort();
activeTxn = NULL;
return (ret == 0);
}
bool ReadVersion(int& nVersion)
{
nVersion = 0;
return Read(std::string("version"), nVersion);
}
bool WriteVersion(int nVersion)
{
return Write(std::string("version"), nVersion);
}
bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
};
/** Access to the transaction database (blkindex.dat) */
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 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 ReadHashBestChain(uint256& hashBestChain);
bool WriteHashBestChain(uint256 hashBestChain);
bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
bool LoadBlockIndex();
private:
bool LoadBlockIndexGuts();
};
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
{
private:
boost::filesystem::path pathAddr;
public:
CAddrDB();
bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr);
};
#endif // BITCOIN_DB_H

774
src/init.cpp Normal file
View File

@@ -0,0 +1,774 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "db.h"
#include "walletdb.h"
#include "bitcoinrpc.h"
#include "net.h"
#include "init.h"
#include "util.h"
#include "ui_interface.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/algorithm/string/predicate.hpp>
#ifndef WIN32
#include <signal.h>
#endif
using namespace std;
using namespace boost;
CWallet* pwalletMain;
CClientUIInterface uiInterface;
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
//
void ExitTimeout(void* parg)
{
#ifdef WIN32
Sleep(5000);
ExitProcess(0);
#endif
}
void StartShutdown()
{
#ifdef QT_GUI
// ensure we leave the Qt main loop for a clean GUI exit (Shutdown() is called in bitcoin.cpp afterwards)
uiInterface.QueueShutdown();
#else
// Without UI, Shutdown() can simply be started in a new thread
CreateThread(Shutdown, NULL);
#endif
}
void Shutdown(void* parg)
{
static CCriticalSection cs_Shutdown;
static bool fTaken;
// Make this thread recognisable as the shutdown thread
RenameThread("bitcoin-shutoff");
bool fFirstThread = false;
{
TRY_LOCK(cs_Shutdown, lockShutdown);
if (lockShutdown)
{
fFirstThread = !fTaken;
fTaken = true;
}
}
static bool fExit;
if (fFirstThread)
{
fShutdown = true;
nTransactionsUpdated++;
bitdb.Flush(false);
StopNode();
bitdb.Flush(true);
boost::filesystem::remove(GetPidFile());
UnregisterWallet(pwalletMain);
delete pwalletMain;
CreateThread(ExitTimeout, NULL);
Sleep(50);
printf("CasinoCoin exited\n\n");
fExit = true;
#ifndef QT_GUI
// ensure non UI client get's exited here, but let Bitcoin-Qt reach return 0; in bitcoin.cpp
exit(0);
#endif
}
else
{
while (!fExit)
Sleep(500);
Sleep(100);
ExitThread(0);
}
}
void HandleSIGTERM(int)
{
fRequestShutdown = true;
}
void HandleSIGHUP(int)
{
fReopenDebugLog = true;
}
//////////////////////////////////////////////////////////////////////////////
//
// Start
//
#if !defined(QT_GUI)
bool AppInit(int argc, char* argv[])
{
bool fRet = false;
try
{
//
// Parameters
//
// If Qt is used, parameters/casinocoin.conf are parsed in qt/bitcoin.cpp's main()
ParseParameters(argc, argv);
if (!boost::filesystem::is_directory(GetDataDir(false)))
{
fprintf(stderr, "Error: Specified directory does not exist\n");
Shutdown(NULL);
}
ReadConfigFile(mapArgs, mapMultiArgs);
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
// First part of help message is specific to casinocoind / RPC client
std::string strUsage = _("CasinoCoin version") + " " + FormatFullVersion() + "\n\n" +
_("Usage:") + "\n" +
" casinocoind [options] " + "\n" +
" casinocoind [options] <command> [params] " + _("Send command to -server or casinocoind") + "\n" +
" casinocoind [options] help " + _("List commands") + "\n" +
" casinocoind [options] help <command> " + _("Get help for a command") + "\n";
strUsage += "\n" + HelpMessage();
fprintf(stderr, "%s", strUsage.c_str());
return false;
}
// Command-line RPC
for (int i = 1; i < argc; i++)
if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "casinocoin:"))
fCommandLine = true;
if (fCommandLine)
{
int ret = CommandLineRPC(argc, argv);
exit(ret);
}
fRet = AppInit2();
}
catch (std::exception& e) {
PrintException(&e, "AppInit()");
} catch (...) {
PrintException(NULL, "AppInit()");
}
if (!fRet)
Shutdown(NULL);
return fRet;
}
extern void noui_connect();
int main(int argc, char* argv[])
{
bool fRet = false;
// Connect casinocoind signal handlers
noui_connect();
fRet = AppInit(argc, argv);
if (fRet && fDaemon)
return 0;
return 1;
}
#endif
bool static InitError(const std::string &str)
{
uiInterface.ThreadSafeMessageBox(str, _("CasinoCoin"), CClientUIInterface::OK | CClientUIInterface::MODAL);
return false;
}
bool static InitWarning(const std::string &str)
{
uiInterface.ThreadSafeMessageBox(str, _("CasinoCoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
return true;
}
bool static Bind(const CService &addr, bool fError = true) {
if (IsLimited(addr))
return false;
std::string strError;
if (!BindListenPort(addr, strError)) {
if (fError)
return InitError(strError);
return false;
}
return true;
}
// Core-specific options shared between UI and daemon
std::string HelpMessage()
{
string strUsage = _("Options:") + "\n" +
" -conf=<file> " + _("Specify configuration file (default: casinocoin.conf)") + "\n" +
" -pid=<file> " + _("Specify pid file (default: casinocoind.pid)") + "\n" +
" -gen " + _("Generate coins") + "\n" +
" -gen=0 " + _("Don't generate coins") + "\n" +
" -datadir=<dir> " + _("Specify data directory") + "\n" +
" -dbcache=<n> " + _("Set database cache size in megabytes (default: 25)") + "\n" +
" -dblogsize=<n> " + _("Set database disk log size in megabytes (default: 100)") + "\n" +
" -timeout=<n> " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" +
" -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" +
" -tor=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"
" -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" +
" -port=<port> " + _("Listen for connections on <port> (default: 47950 or testnet: 17950)") + "\n" +
" -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" +
" -addnode=<ip> " + _("Add a node to connect to and attempt to keep the connection open") + "\n" +
" -connect=<ip> " + _("Connect only to the specified node(s)") + "\n" +
" -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" +
" -externalip=<ip> " + _("Specify your own public address") + "\n" +
" -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n" +
" -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" +
" -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" +
" -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
" -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n" +
" -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
" -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
" -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)") + "\n" +
" -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)") + "\n" +
#ifdef USE_UPNP
#if USE_UPNP
" -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n" +
#else
" -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n" +
#endif
#endif
" -detachdb " + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" +
" -paytxfee=<amt> " + _("Fee per KB to add to transactions you send") + "\n" +
" -mininput=<amt> " + _("When creating transactions, ignore inputs with value less than this (default: 0.0001)") + "\n" +
#ifdef QT_GUI
" -server " + _("Accept command line and JSON-RPC commands") + "\n" +
#endif
#if !defined(WIN32) && !defined(QT_GUI)
" -daemon " + _("Run in the background as a daemon and accept commands") + "\n" +
#endif
" -testnet " + _("Use the test network") + "\n" +
" -debug " + _("Output extra debugging information. Implies all other -debug* options") + "\n" +
" -debugnet " + _("Output extra network debugging information") + "\n" +
" -logtimestamps " + _("Prepend debug output with timestamp") + "\n" +
" -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n" +
#ifdef WIN32
" -printtodebugger " + _("Send trace/debug info to debugger") + "\n" +
#endif
" -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n" +
" -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n" +
" -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 47970)") + "\n" +
" -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
" -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
" -upgradewallet " + _("Upgrade wallet to latest format") + "\n" +
" -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" +
" -checkblocks=<n> " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
" -checklevel=<n> " + _("How thorough the block verification is (0-6, default: 1)") + "\n" +
" -loadblock=<file> " + _("Imports blocks from external blk000?.dat file") + "\n" +
" -? " + _("This help message") + "\n";
strUsage += string() +
_("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" +
" -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" +
" -rpcsslcertificatechainfile=<file.cert> " + _("Server certificate file (default: server.cert)") + "\n" +
" -rpcsslprivatekeyfile=<file.pem> " + _("Server private key (default: server.pem)") + "\n" +
" -rpcsslciphers=<ciphers> " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n";
return strUsage;
}
/** Initialize casinocoin.
* @pre Parameters should be parsed and config file should be read.
*/
bool AppInit2()
{
// ********************************************************* Step 1: setup
#ifdef _MSC_VER
// Turn off microsoft heap dump noise
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
#endif
#if _MSC_VER >= 1400
// Disable confusing "helpful" text message on abort, ctrl-c
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
#ifndef WIN32
umask(077);
#endif
#ifndef WIN32
// Clean shutdown on SIGTERM
struct sigaction sa;
sa.sa_handler = HandleSIGTERM;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
// Reopen debug.log on SIGHUP
struct sigaction sa_hup;
sa_hup.sa_handler = HandleSIGHUP;
sigemptyset(&sa_hup.sa_mask);
sa_hup.sa_flags = 0;
sigaction(SIGHUP, &sa_hup, NULL);
#endif
// ********************************************************* Step 2: parameter interactions
fTestNet = GetBoolArg("-testnet");
SoftSetBoolArg("-irc", false);
if (mapArgs.count("-bind")) {
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
SoftSetBoolArg("-listen", true);
}
if (mapArgs.count("-connect")) {
// when only connecting to trusted nodes, do not seed via DNS, or listen by default
SoftSetBoolArg("-dnsseed", false);
SoftSetBoolArg("-listen", false);
}
if (mapArgs.count("-proxy")) {
// to protect privacy, do not listen by default if a proxy server is specified
SoftSetBoolArg("-listen", false);
}
if (!GetBoolArg("-listen", true)) {
// do not map ports or try to retrieve public IP when not listening (pointless)
SoftSetBoolArg("-upnp", false);
SoftSetBoolArg("-discover", false);
}
if (mapArgs.count("-externalip")) {
// if an explicit public IP is specified, do not try to find others
SoftSetBoolArg("-discover", false);
}
// ********************************************************* Step 3: parameter-to-internal-flags
fDebug = GetBoolArg("-debug");
// -debug implies fDebug*
if (fDebug)
fDebugNet = true;
else
fDebugNet = GetBoolArg("-debugnet");
bitdb.SetDetach(GetBoolArg("-detachdb", false));
#if !defined(WIN32) && !defined(QT_GUI)
fDaemon = GetBoolArg("-daemon");
#else
fDaemon = false;
#endif
if (fDaemon)
fServer = true;
else
fServer = GetBoolArg("-server");
/* force fServer when running without GUI */
#if !defined(QT_GUI)
fServer = true;
#endif
fPrintToConsole = GetBoolArg("-printtoconsole");
fPrintToDebugger = GetBoolArg("-printtodebugger");
fLogTimestamps = GetBoolArg("-logtimestamps");
if (mapArgs.count("-timeout"))
{
int nNewTimeout = GetArg("-timeout", 5000);
if (nNewTimeout > 0 && nNewTimeout < 600000)
nConnectTimeout = nNewTimeout;
}
// Continue to put "/P2SH/" in the coinbase to monitor
// BIP16 support.
// This can be removed eventually...
const char* pszP2SH = "/P2SH/";
COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
if (mapArgs.count("-paytxfee"))
{
if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"].c_str()));
if (nTransactionFee > 0.25 * COIN)
InitWarning(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."));
}
if (mapArgs.count("-mininput"))
{
if (!ParseMoney(mapArgs["-mininput"], nMinimumInputValue))
return InitError(strprintf(_("Invalid amount for -mininput=<amount>: '%s'"), mapArgs["-mininput"].c_str()));
}
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
// Make sure only a single CasinoCoin process is using the data directory.
boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
if (file) fclose(file);
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock())
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. CasinoCoin is probably already running."), GetDataDir().string().c_str()));
#if !defined(WIN32) && !defined(QT_GUI)
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)
ShrinkDebugFile();
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
printf("CasinoCoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
printf("Used data directory %s\n", GetDataDir().string().c_str());
std::ostringstream strErrors;
if (fDaemon)
fprintf(stdout, "CasinoCoin server starting\n");
int64 nStart;
// ********************************************************* Step 5: network initialization
int nSocksVersion = GetArg("-socks", 5);
if (nSocksVersion != 4 && nSocksVersion != 5)
return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE)
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet.c_str()));
nets.insert(net);
}
for (int n = 0; n < NET_MAX; n++) {
enum Network net = (enum Network)n;
if (!nets.count(net))
SetLimited(net);
}
}
CService addrProxy;
bool fProxy = false;
if (mapArgs.count("-proxy")) {
addrProxy = CService(mapArgs["-proxy"], 9050);
if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str()));
if (!IsLimited(NET_IPV4))
SetProxy(NET_IPV4, addrProxy, nSocksVersion);
if (nSocksVersion > 4) {
#ifdef USE_IPV6
if (!IsLimited(NET_IPV6))
SetProxy(NET_IPV6, addrProxy, nSocksVersion);
#endif
SetNameProxy(addrProxy, nSocksVersion);
}
fProxy = true;
}
// -tor can override normal proxy, -notor disables tor entirely
if (!(mapArgs.count("-tor") && mapArgs["-tor"] == "0") && (fProxy || mapArgs.count("-tor"))) {
CService addrOnion;
if (!mapArgs.count("-tor"))
addrOnion = addrProxy;
else
addrOnion = CService(mapArgs["-tor"], 9050);
if (!addrOnion.IsValid())
return InitError(strprintf(_("Invalid -tor address: '%s'"), mapArgs["-tor"].c_str()));
SetProxy(NET_TOR, addrOnion, 5);
SetReachable(NET_TOR);
}
// see Step 2: parameter interactions for more information about these
fNoListen = !GetBoolArg("-listen", true);
fDiscover = GetBoolArg("-discover", true);
fNameLookup = GetBoolArg("-dns", true);
#ifdef USE_UPNP
fUseUPnP = GetBoolArg("-upnp", USE_UPNP);
#endif
bool fBound = false;
if (!fNoListen)
{
std::string strError;
if (mapArgs.count("-bind")) {
BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind.c_str()));
fBound |= Bind(addrBind);
}
} else {
struct in_addr inaddr_any;
inaddr_any.s_addr = INADDR_ANY;
#ifdef USE_IPV6
if (!IsLimited(NET_IPV6))
fBound |= Bind(CService(in6addr_any, GetListenPort()), false);
#endif
if (!IsLimited(NET_IPV4))
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound);
}
if (!fBound)
return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
}
if (mapArgs.count("-externalip"))
{
BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) {
CService addrLocal(strAddr, GetListenPort(), fNameLookup);
if (!addrLocal.IsValid())
return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr.c_str()));
AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
}
}
BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest);
// ********************************************************* Step 6: load blockchain
if (GetBoolArg("-loadblockindextest"))
{
CTxDB txdb("r");
txdb.LoadBlockIndex();
PrintBlockTree();
return false;
}
uiInterface.InitMessage(_("Loading block index..."));
printf("Loading block index...\n");
nStart = GetTimeMillis();
if (!LoadBlockIndex())
strErrors << _("Error loading blkindex.dat") << "\n";
// as LoadBlockIndex can take several minutes, it's possible the user
// requested to kill casinocoin-qt during the last operation. If so, exit.
// As the program has not fully started yet, Shutdown() is possibly overkill.
if (fRequestShutdown)
{
printf("Shutdown requested. Exiting.\n");
return false;
}
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
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;
}
// ********************************************************* Step 7: load wallet
uiInterface.InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n");
nStart = GetTimeMillis();
bool fFirstRun;
pwalletMain = new CWallet("wallet.dat");
int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT)
strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
else if (nLoadWalletRet == DB_TOO_NEW)
strErrors << _("Error loading wallet.dat: Wallet requires newer version of CasinoCoin") << "\n";
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
strErrors << _("Wallet needed to be rewritten: restart CasinoCoin to complete") << "\n";
printf("%s", strErrors.str().c_str());
return InitError(strErrors.str());
}
else
strErrors << _("Error loading wallet.dat") << "\n";
}
if (GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = GetArg("-upgradewallet", 0);
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
printf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = CLIENT_VERSION;
pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
}
else
printf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < pwalletMain->GetVersion())
{
printf("Max version: %i\n", nMaxVersion);
printf("Wallet version: %i\n", pwalletMain->GetVersion());
strErrors << _("Cannot downgrade wallet") << "\n";
}
pwalletMain->SetMaxVersion(nMaxVersion);
}
if (fFirstRun)
{
// Create new keyUser and set as default key
RandAddSeedPerfmon();
CPubKey newDefaultKey;
if (!pwalletMain->GetKeyFromPool(newDefaultKey, false))
strErrors << _("Cannot initialize keypool") << "\n";
pwalletMain->SetDefaultKey(newDefaultKey);
if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), ""))
strErrors << _("Cannot write default address") << "\n";
}
printf("%s", strErrors.str().c_str());
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
RegisterWallet(pwalletMain);
CBlockIndex *pindexRescan = pindexBest;
if (GetBoolArg("-rescan"))
pindexRescan = pindexGenesisBlock;
else
{
CWalletDB walletdb("wallet.dat");
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = locator.GetBlockIndex();
}
if (pindexBest != pindexRescan)
{
uiInterface.InitMessage(_("Rescanning..."));
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
}
// ********************************************************* Step 8: import blocks
if (mapArgs.count("-loadblock"))
{
BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
{
FILE *file = fopen(strFile.c_str(), "rb");
if (file)
LoadExternalBlockFile(file);
}
}
// ********************************************************* Step 9: load peers
uiInterface.InitMessage(_("Loading addresses..."));
printf("Loading addresses...\n");
nStart = GetTimeMillis();
{
CAddrDB adb;
if (!adb.Read(addrman))
printf("Invalid or missing peers.dat; recreating\n");
}
printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n",
addrman.size(), GetTimeMillis() - nStart);
// ********************************************************* Step 10: start node
if (!CheckDiskSpace())
return false;
RandAddSeedPerfmon();
//// debug print
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight);
printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size());
if (!CreateThread(StartNode, NULL))
InitError(_("Error: could not start node"));
if (fServer)
CreateThread(ThreadRPCServer, NULL);
// ********************************************************* Step 11: finished
uiInterface.InitMessage(_("Done loading"));
printf("Done loading\n");
if (!strErrors.str().empty())
return InitError(strErrors.str());
// Add wallet transactions that aren't already in a block to mapTransactions
pwalletMain->ReacceptWalletTransactions();
#if !defined(QT_GUI)
// Loop until process is exit()ed from shutdown() function,
// called from ThreadRPCServer thread when a "stop" command is received.
while (1)
Sleep(5000);
#endif
return true;
}

19
src/init.h Normal file
View File

@@ -0,0 +1,19 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_INIT_H
#define BITCOIN_INIT_H
#include "wallet.h"
extern CWallet* pwalletMain;
void StartShutdown();
void Shutdown(void* parg);
bool AppInit2();
std::string HelpMessage();
#endif

396
src/irc.cpp Normal file
View File

@@ -0,0 +1,396 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "irc.h"
#include "net.h"
#include "strlcpy.h"
#include "base58.h"
using namespace std;
using namespace boost;
int nGotIRCAddresses = 0;
void ThreadIRCSeed2(void* parg);
#pragma pack(push, 1)
struct ircaddr
{
struct in_addr ip;
short port;
};
#pragma pack(pop)
string EncodeAddress(const CService& addr)
{
struct ircaddr tmp;
if (addr.GetInAddr(&tmp.ip))
{
tmp.port = htons(addr.GetPort());
vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
return string("u") + EncodeBase58Check(vch);
}
return "";
}
bool DecodeAddress(string str, CService& 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 = CService(tmp.ip, ntohs(tmp.port));
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 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) != string::npos)
return 1;
if (psz2 && strLine.find(psz2) != string::npos)
return 2;
if (psz3 && strLine.find(psz3) != string::npos)
return 3;
if (psz4 && strLine.find(psz4) != string::npos)
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, CNetAddr& 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());
CNetAddr addr(strHost, true);
if (!addr.IsValid())
return false;
ipRet = addr;
return true;
}
void ThreadIRCSeed(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
// Make this thread recognisable as the IRC seeding thread
RenameThread("bitcoin-ircseed");
try
{
ThreadIRCSeed2(parg);
}
catch (std::exception& e) {
PrintExceptionContinue(&e, "ThreadIRCSeed()");
} catch (...) {
PrintExceptionContinue(NULL, "ThreadIRCSeed()");
}
printf("ThreadIRCSeed exited\n");
}
void ThreadIRCSeed2(void* parg)
{
/* Disable IRC Seeding Entirely */
return;
/* Dont advertise on IRC if we don't allow incoming connections */
if (mapArgs.count("-connect") || fNoListen)
return;
printf("ThreadIRCSeed started\n");
int nErrorWait = 10;
int nRetryWait = 10;
while (!fShutdown)
{
CService addrConnect("92.243.23.21", 6667); // irc.lfnet.org
CService 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;
}
CNetAddr addrIPv4("1.2.3.4"); // arbitrary IPv4 address to make GetLocal prefer IPv4 addresses
CService addrLocal;
string strMyName;
if (GetLocal(addrLocal, &addrIPv4))
strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
if (strMyName == "")
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");
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
CNetAddr addrFromIRC;
if (GetIPFromIRC(hSocket, strMyName, addrFromIRC))
{
printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str());
if (addrFromIRC.IsRoutable())
{
// IRC lets you to re-nick
AddLocal(addrFromIRC, LOCAL_IRC);
strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
}
}
if (fTestNet) {
Send(hSocket, "JOIN #casinocoinTEST3\r");
Send(hSocket, "WHO #casinocoinTEST3\r");
} else {
// randomly join #casinocoin00-#casinocoin99
int channel_number = GetRandInt(100);
channel_number = 0; // CasinoCoin: for now, just use one channel
Send(hSocket, strprintf("JOIN #casinocoin%02d\r", channel_number).c_str());
Send(hSocket, strprintf("WHO #casinocoin%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 (addrman.Add(addr, addrConnect, 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;
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

14
src/irc.h Normal file
View File

@@ -0,0 +1,14 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_IRC_H
#define BITCOIN_IRC_H
void ThreadIRCSeed(void* parg);
extern int nGotIRCAddresses;
#endif

24
src/json/LICENSE.txt Normal file
View File

@@ -0,0 +1,24 @@
The MIT License
Copyright (c) 2007 - 2009 John W. Wilkinson
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

18
src/json/json_spirit.h Normal file
View 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

View 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

View 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_spirit_reader.h"
#include "json_spirit_reader_template.h"
using namespace json_spirit;
bool json_spirit::read( const std::string& s, Value& value )
{
return read_string( s, value );
}
void json_spirit::read_or_throw( const std::string& s, Value& value )
{
read_string_or_throw( s, value );
}
bool json_spirit::read( std::istream& is, Value& value )
{
return read_stream( is, value );
}
void json_spirit::read_or_throw( std::istream& is, Value& value )
{
read_stream_or_throw( is, value );
}
bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value )
{
return read_range( begin, end, value );
}
void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value )
{
begin = read_range_or_throw( begin, end, value );
}
#ifndef BOOST_NO_STD_WSTRING
bool json_spirit::read( const std::wstring& s, wValue& value )
{
return read_string( s, value );
}
void json_spirit::read_or_throw( const std::wstring& s, wValue& value )
{
read_string_or_throw( s, value );
}
bool json_spirit::read( std::wistream& is, wValue& value )
{
return read_stream( is, value );
}
void json_spirit::read_or_throw( std::wistream& is, wValue& value )
{
read_stream_or_throw( is, value );
}
bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value )
{
return read_range( begin, end, value );
}
void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value )
{
begin = read_range_or_throw( begin, end, value );
}
#endif
bool json_spirit::read( const std::string& s, mValue& value )
{
return read_string( s, value );
}
void json_spirit::read_or_throw( const std::string& s, mValue& value )
{
read_string_or_throw( s, value );
}
bool json_spirit::read( std::istream& is, mValue& value )
{
return read_stream( is, value );
}
void json_spirit::read_or_throw( std::istream& is, mValue& value )
{
read_stream_or_throw( is, value );
}
bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value )
{
return read_range( begin, end, value );
}
void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value )
{
begin = read_range_or_throw( begin, end, value );
}
#ifndef BOOST_NO_STD_WSTRING
bool json_spirit::read( const std::wstring& s, wmValue& value )
{
return read_string( s, value );
}
void json_spirit::read_or_throw( const std::wstring& s, wmValue& value )
{
read_string_or_throw( s, value );
}
bool json_spirit::read( std::wistream& is, wmValue& value )
{
return read_stream( is, value );
}
void json_spirit::read_or_throw( std::wistream& is, wmValue& value )
{
read_stream_or_throw( is, value );
}
bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value )
{
return read_range( begin, end, value );
}
void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value )
{
begin = read_range_or_throw( begin, end, value );
}
#endif

View 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

View 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 &current_p_->get_array().back();
}
assert( current_p_->type() == obj_type );
return &Config_type::add( current_p_->get_obj(), name_, value );
}
Value_type& value_; // this is the object or array that is being created
Value_type* current_p_; // the child object or array that is currently being constructed
std::vector< Value_type* > stack_; // previous child objects and arrays
String_type name_; // of current name/value pair
};
template< typename Iter_type >
void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason )
{
throw Error_position( i.get_position().line, i.get_position().column, reason );
}
template< typename Iter_type >
void throw_error( Iter_type i, const std::string& reason )
{
throw reason;
}
// the spirit grammer
//
template< class Value_type, class Iter_type >
class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > >
{
public:
typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t;
Json_grammer( Semantic_actions_t& semantic_actions )
: actions_( semantic_actions )
{
}
static void throw_not_value( Iter_type begin, Iter_type end )
{
throw_error( begin, "not a value" );
}
static void throw_not_array( Iter_type begin, Iter_type end )
{
throw_error( begin, "not an array" );
}
static void throw_not_object( Iter_type begin, Iter_type end )
{
throw_error( begin, "not an object" );
}
static void throw_not_pair( Iter_type begin, Iter_type end )
{
throw_error( begin, "not a pair" );
}
static void throw_not_colon( Iter_type begin, Iter_type end )
{
throw_error( begin, "no colon in pair" );
}
static void throw_not_string( Iter_type begin, Iter_type end )
{
throw_error( begin, "not a string" );
}
template< typename ScannerT >
class definition
{
public:
definition( const Json_grammer& self )
{
using namespace spirit_namespace;
typedef typename Value_type::String_type::value_type Char_type;
// first we convert the semantic action class methods to functors with the
// parameter signature expected by spirit
typedef boost::function< void( Char_type ) > Char_action;
typedef boost::function< void( Iter_type, Iter_type ) > Str_action;
typedef boost::function< void( double ) > Real_action;
typedef boost::function< void( boost::int64_t ) > Int_action;
typedef boost::function< void( boost::uint64_t ) > Uint64_action;
Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) );
Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) );
Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) );
Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) );
Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) );
Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) );
Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) );
Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) );
Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) );
Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) );
Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) );
Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) );
// actual grammer
json_
= value_ | eps_p[ &throw_not_value ]
;
value_
= string_[ new_str ]
| number_
| object_
| array_
| str_p( "true" ) [ new_true ]
| str_p( "false" )[ new_false ]
| str_p( "null" ) [ new_null ]
;
object_
= ch_p('{')[ begin_obj ]
>> !members_
>> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] )
;
members_
= pair_ >> *( ',' >> pair_ )
;
pair_
= string_[ new_name ]
>> ( ':' | eps_p[ &throw_not_colon ] )
>> ( value_ | eps_p[ &throw_not_value ] )
;
array_
= ch_p('[')[ begin_array ]
>> !elements_
>> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] )
;
elements_
= value_ >> *( ',' >> value_ )
;
string_
= lexeme_d // this causes white space inside a string to be retained
[
confix_p
(
'"',
*lex_escape_ch_p,
'"'
)
]
;
number_
= strict_real_p[ new_real ]
| int64_p [ new_int ]
| uint64_p [ new_uint64 ]
;
}
spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_;
const spirit_namespace::rule< ScannerT >& start() const { return json_; }
};
private:
Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning
Semantic_actions_t& actions_;
};
template< class Iter_type, class Value_type >
Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
{
Semantic_actions< Value_type, Iter_type > semantic_actions( value );
const spirit_namespace::parse_info< Iter_type > info =
spirit_namespace::parse( begin, end,
Json_grammer< Value_type, Iter_type >( semantic_actions ),
spirit_namespace::space_p );
if( !info.hit )
{
assert( false ); // in theory exception should already have been thrown
throw_error( info.stop, "error" );
}
return info.stop;
}
template< class Iter_type, class Value_type >
void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
{
typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t;
const Posn_iter_t posn_begin( begin, end );
const Posn_iter_t posn_end( end, end );
read_range_or_throw( posn_begin, posn_end, value );
}
template< class Iter_type, class Value_type >
bool read_range( Iter_type& begin, Iter_type end, Value_type& value )
{
try
{
begin = read_range_or_throw( begin, end, value );
return true;
}
catch( ... )
{
return false;
}
}
template< class String_type, class Value_type >
void read_string_or_throw( const String_type& s, Value_type& value )
{
add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value );
}
template< class String_type, class Value_type >
bool read_string( const String_type& s, Value_type& value )
{
typename String_type::const_iterator begin = s.begin();
return read_range( begin, s.end(), value );
}
template< class Istream_type >
struct Multi_pass_iters
{
typedef typename Istream_type::char_type Char_type;
typedef std::istream_iterator< Char_type, Char_type > istream_iter;
typedef spirit_namespace::multi_pass< istream_iter > Mp_iter;
Multi_pass_iters( Istream_type& is )
{
is.unsetf( std::ios::skipws );
begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) );
end_ = spirit_namespace::make_multi_pass( istream_iter() );
}
Mp_iter begin_;
Mp_iter end_;
};
template< class Istream_type, class Value_type >
bool read_stream( Istream_type& is, Value_type& value )
{
Multi_pass_iters< Istream_type > mp_iters( is );
return read_range( mp_iters.begin_, mp_iters.end_, value );
}
template< class Istream_type, class Value_type >
void read_stream_or_throw( Istream_type& is, Value_type& value )
{
const Multi_pass_iters< Istream_type > mp_iters( is );
add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value );
}
}
#endif

View 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

View 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

View 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_spirit_value.h"

View 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

View 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_spirit_writer.h"
#include "json_spirit_writer_template.h"
void json_spirit::write( const Value& value, std::ostream& os )
{
write_stream( value, os, false );
}
void json_spirit::write_formatted( const Value& value, std::ostream& os )
{
write_stream( value, os, true );
}
std::string json_spirit::write( const Value& value )
{
return write_string( value, false );
}
std::string json_spirit::write_formatted( const Value& value )
{
return write_string( value, true );
}
#ifndef BOOST_NO_STD_WSTRING
void json_spirit::write( const wValue& value, std::wostream& os )
{
write_stream( value, os, false );
}
void json_spirit::write_formatted( const wValue& value, std::wostream& os )
{
write_stream( value, os, true );
}
std::wstring json_spirit::write( const wValue& value )
{
return write_string( value, false );
}
std::wstring json_spirit::write_formatted( const wValue& value )
{
return write_string( value, true );
}
#endif
void json_spirit::write( const mValue& value, std::ostream& os )
{
write_stream( value, os, false );
}
void json_spirit::write_formatted( const mValue& value, std::ostream& os )
{
write_stream( value, os, true );
}
std::string json_spirit::write( const mValue& value )
{
return write_string( value, false );
}
std::string json_spirit::write_formatted( const mValue& value )
{
return write_string( value, true );
}
#ifndef BOOST_NO_STD_WSTRING
void json_spirit::write( const wmValue& value, std::wostream& os )
{
write_stream( value, os, false );
}
void json_spirit::write_formatted( const wmValue& value, std::wostream& os )
{
write_stream( value, os, true );
}
std::wstring json_spirit::write( const wmValue& value )
{
return write_string( value, false );
}
std::wstring json_spirit::write_formatted( const wmValue& value )
{
return write_string( value, true );
}
#endif

View 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

View 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

387
src/key.cpp Normal file
View File

@@ -0,0 +1,387 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <map>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include "key.h"
// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
int ok = 0;
BN_CTX *ctx = NULL;
EC_POINT *pub_key = NULL;
if (!eckey) return 0;
const EC_GROUP *group = EC_KEY_get0_group(eckey);
if ((ctx = BN_CTX_new()) == NULL)
goto err;
pub_key = EC_POINT_new(group);
if (pub_key == NULL)
goto err;
if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
goto err;
EC_KEY_set_private_key(eckey,priv_key);
EC_KEY_set_public_key(eckey,pub_key);
ok = 1;
err:
if (pub_key)
EC_POINT_free(pub_key);
if (ctx != NULL)
BN_CTX_free(ctx);
return(ok);
}
// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
// recid selects which key is recovered
// if check is nonzero, additional checks are performed
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
{
if (!eckey) return 0;
int ret = 0;
BN_CTX *ctx = NULL;
BIGNUM *x = NULL;
BIGNUM *e = NULL;
BIGNUM *order = NULL;
BIGNUM *sor = NULL;
BIGNUM *eor = NULL;
BIGNUM *field = NULL;
EC_POINT *R = NULL;
EC_POINT *O = NULL;
EC_POINT *Q = NULL;
BIGNUM *rr = NULL;
BIGNUM *zero = NULL;
int n = 0;
int i = recid / 2;
const EC_GROUP *group = EC_KEY_get0_group(eckey);
if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
BN_CTX_start(ctx);
order = BN_CTX_get(ctx);
if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
x = BN_CTX_get(ctx);
if (!BN_copy(x, order)) { ret=-1; goto err; }
if (!BN_mul_word(x, i)) { ret=-1; goto err; }
if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
field = BN_CTX_get(ctx);
if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
if (check)
{
if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
}
if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
n = EC_GROUP_get_degree(group);
e = BN_CTX_get(ctx);
if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
zero = BN_CTX_get(ctx);
if (!BN_zero(zero)) { ret=-1; goto err; }
if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
rr = BN_CTX_get(ctx);
if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
sor = BN_CTX_get(ctx);
if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
eor = BN_CTX_get(ctx);
if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
ret = 1;
err:
if (ctx) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
if (R != NULL) EC_POINT_free(R);
if (O != NULL) EC_POINT_free(O);
if (Q != NULL) EC_POINT_free(Q);
return ret;
}
void CKey::SetCompressedPubKey()
{
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
fCompressedPubKey = true;
}
void CKey::Reset()
{
fCompressedPubKey = false;
if (pkey != NULL)
EC_KEY_free(pkey);
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::CKey()
{
pkey = NULL;
Reset();
}
CKey::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& 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::~CKey()
{
EC_KEY_free(pkey);
}
bool CKey::IsNull() const
{
return !fSet;
}
bool CKey::IsCompressed() const
{
return fCompressedPubKey;
}
void CKey::MakeNewKey(bool fCompressed)
{
if (!EC_KEY_generate_key(pkey))
throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
if (fCompressed)
SetCompressedPubKey();
fSet = true;
}
bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
{
const unsigned char* pbegin = &vchPrivKey[0];
if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
return false;
fSet = true;
return true;
}
bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)
{
EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (pkey == NULL)
throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
if (vchSecret.size() != 32)
throw key_error("CKey::SetSecret() : secret must be 32 bytes");
BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
if (bn == NULL)
throw key_error("CKey::SetSecret() : BN_bin2bn failed");
if (!EC_KEY_regenerate_key(pkey,bn))
{
BN_clear_free(bn);
throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
}
BN_clear_free(bn);
fSet = true;
if (fCompressed || fCompressedPubKey)
SetCompressedPubKey();
return true;
}
CSecret CKey::GetSecret(bool &fCompressed) const
{
CSecret vchRet;
vchRet.resize(32);
const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
int nBytes = BN_num_bytes(bn);
if (bn == NULL)
throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
if (n != nBytes)
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
fCompressed = fCompressedPubKey;
return vchRet;
}
CPrivKey CKey::GetPrivKey() const
{
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 CKey::SetPubKey(const CPubKey& vchPubKey)
{
const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
return false;
fSet = true;
if (vchPubKey.vchPubKey.size() == 33)
SetCompressedPubKey();
return true;
}
CPubKey CKey::GetPubKey() const
{
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 CPubKey(vchPubKey);
}
bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
{
unsigned int nSize = ECDSA_size(pkey);
vchSig.resize(nSize); // Make sure it is big enough
if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
{
vchSig.clear();
return false;
}
vchSig.resize(nSize); // Shrink to fit actual size
return true;
}
// create a compact signature (65 bytes), which allows reconstructing the used public key
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
// 0x1D = second key with even y, 0x1E = second key with odd y
bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
{
bool fOk = false;
ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
if (sig==NULL)
return false;
vchSig.clear();
vchSig.resize(65,0);
int nBitsR = BN_num_bits(sig->r);
int nBitsS = BN_num_bits(sig->s);
if (nBitsR <= 256 && nBitsS <= 256)
{
int nRecId = -1;
for (int i=0; i<4; i++)
{
CKey keyRec;
keyRec.fSet = true;
if (fCompressedPubKey)
keyRec.SetCompressedPubKey();
if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
if (keyRec.GetPubKey() == this->GetPubKey())
{
nRecId = i;
break;
}
}
if (nRecId == -1)
throw key_error("CKey::SignCompact() : unable to construct recoverable key");
vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
fOk = true;
}
ECDSA_SIG_free(sig);
return fOk;
}
// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
{
if (vchSig.size() != 65)
return false;
int nV = vchSig[0];
if (nV<27 || nV>=35)
return false;
ECDSA_SIG *sig = ECDSA_SIG_new();
BN_bin2bn(&vchSig[1],32,sig->r);
BN_bin2bn(&vchSig[33],32,sig->s);
EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (nV >= 31)
{
SetCompressedPubKey();
nV -= 4;
}
if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
{
fSet = true;
ECDSA_SIG_free(sig);
return true;
}
return false;
}
bool CKey::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;
}
bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
{
CKey key;
if (!key.SetCompactSignature(hash, vchSig))
return false;
if (GetPubKey() != key.GetPubKey())
return false;
return true;
}
bool CKey::IsValid()
{
if (!fSet)
return false;
bool fCompr;
CSecret secret = GetSecret(fCompr);
CKey key2;
key2.SetSecret(secret, fCompr);
return GetPubKey() == key2.GetPubKey();
}

164
src/key.h Normal file
View File

@@ -0,0 +1,164 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEY_H
#define BITCOIN_KEY_H
#include <stdexcept>
#include <vector>
#include "allocators.h"
#include "serialize.h"
#include "uint256.h"
#include "util.h"
#include <openssl/ec.h> // for EC_KEY definition
// 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) {}
};
/** A reference to a CKey: the Hash160 of its serialized public key */
class CKeyID : public uint160
{
public:
CKeyID() : uint160(0) { }
CKeyID(const uint160 &in) : uint160(in) { }
};
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
class CScriptID : public uint160
{
public:
CScriptID() : uint160(0) { }
CScriptID(const uint160 &in) : uint160(in) { }
};
/** An encapsulated public key. */
class CPubKey {
private:
std::vector<unsigned char> vchPubKey;
friend class CKey;
public:
CPubKey() { }
CPubKey(const std::vector<unsigned char> &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { }
friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; }
friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; }
friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; }
IMPLEMENT_SERIALIZE(
READWRITE(vchPubKey);
)
CKeyID GetID() const {
return CKeyID(Hash160(vchPubKey));
}
uint256 GetHash() const {
return Hash(vchPubKey.begin(), vchPubKey.end());
}
bool IsValid() const {
return vchPubKey.size() == 33 || vchPubKey.size() == 65;
}
bool IsCompressed() const {
return vchPubKey.size() == 33;
}
std::vector<unsigned char> Raw() const {
return vchPubKey;
}
};
// secure_allocator is defined in serialize.h
// CPrivKey is a serialized private key, with all parameters included (279 bytes)
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
// CSecret is a serialization of just the secret parameter (32 bytes)
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */
class CKey
{
protected:
EC_KEY* pkey;
bool fSet;
bool fCompressedPubKey;
void SetCompressedPubKey();
public:
void Reset();
CKey();
CKey(const CKey& b);
CKey& operator=(const CKey& b);
~CKey();
bool IsNull() const;
bool IsCompressed() const;
void MakeNewKey(bool fCompressed);
bool SetPrivKey(const CPrivKey& vchPrivKey);
bool SetSecret(const CSecret& vchSecret, bool fCompressed = false);
CSecret GetSecret(bool &fCompressed) const;
CPrivKey GetPrivKey() const;
bool SetPubKey(const CPubKey& vchPubKey);
CPubKey GetPubKey() const;
bool Sign(uint256 hash, std::vector<unsigned char>& vchSig);
// create a compact signature (65 bytes), which allows reconstructing the used public key
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
// 0x1D = second key with even y, 0x1E = second key with odd y
bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig);
// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig);
bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig);
// Verify a compact signature
bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig);
bool IsValid();
};
#endif

223
src/keystore.cpp Normal file
View File

@@ -0,0 +1,223 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "keystore.h"
#include "script.h"
bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
{
CKey key;
if (!GetKey(address, key))
return false;
vchPubKeyOut = key.GetPubKey();
return true;
}
bool CBasicKeyStore::AddKey(const CKey& key)
{
bool fCompressed = false;
CSecret secret = key.GetSecret(fCompressed);
{
LOCK(cs_KeyStore);
mapKeys[key.GetPubKey().GetID()] = make_pair(secret, fCompressed);
}
return true;
}
bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
{
{
LOCK(cs_KeyStore);
mapScripts[redeemScript.GetID()] = redeemScript;
}
return true;
}
bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
{
bool result;
{
LOCK(cs_KeyStore);
result = (mapScripts.count(hash) > 0);
}
return result;
}
bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
{
{
LOCK(cs_KeyStore);
ScriptMap::const_iterator mi = mapScripts.find(hash);
if (mi != mapScripts.end())
{
redeemScriptOut = (*mi).second;
return true;
}
}
return false;
}
bool CCryptoKeyStore::SetCrypted()
{
{
LOCK(cs_KeyStore);
if (fUseCrypto)
return true;
if (!mapKeys.empty())
return false;
fUseCrypto = true;
}
return true;
}
bool CCryptoKeyStore::Lock()
{
if (!SetCrypted())
return false;
{
LOCK(cs_KeyStore);
vMasterKey.clear();
}
NotifyStatusChanged(this);
return true;
}
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
{
LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CSecret vchSecret;
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false;
if (vchSecret.size() != 32)
return false;
CKey key;
key.SetPubKey(vchPubKey);
key.SetSecret(vchSecret);
if (key.GetPubKey() == vchPubKey)
break;
return false;
}
vMasterKey = vMasterKeyIn;
}
NotifyStatusChanged(this);
return true;
}
bool CCryptoKeyStore::AddKey(const CKey& key)
{
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::AddKey(key);
if (IsLocked())
return false;
std::vector<unsigned char> vchCryptedSecret;
CPubKey vchPubKey = key.GetPubKey();
bool fCompressed;
if (!EncryptSecret(vMasterKey, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
return false;
}
return true;
}
bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
{
LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
}
return true;
}
bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::GetKey(address, keyOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
const CPubKey &vchPubKey = (*mi).second.first;
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CSecret vchSecret;
if (!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
return false;
if (vchSecret.size() != 32)
return false;
keyOut.SetPubKey(vchPubKey);
keyOut.SetSecret(vchSecret);
return true;
}
}
return false;
}
bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return CKeyStore::GetPubKey(address, vchPubKeyOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
{
vchPubKeyOut = (*mi).second.first;
return true;
}
}
return false;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
{
LOCK(cs_KeyStore);
if (!mapCryptedKeys.empty() || IsCrypted())
return false;
fUseCrypto = true;
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
{
CKey key;
if (!key.SetSecret(mKey.second.first, mKey.second.second))
return false;
const CPubKey vchPubKey = key.GetPubKey();
std::vector<unsigned char> vchCryptedSecret;
bool fCompressed;
if (!EncryptSecret(vMasterKeyIn, key.GetSecret(fCompressed), vchPubKey.GetHash(), vchCryptedSecret))
return false;
if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
}
mapKeys.clear();
}
return true;
}

186
src/keystore.h Normal file
View File

@@ -0,0 +1,186 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
#include "crypter.h"
#include "sync.h"
#include <boost/signals2/signal.hpp>
class CScript;
/** A virtual base class for key stores */
class CKeyStore
{
protected:
mutable CCriticalSection cs_KeyStore;
public:
virtual ~CKeyStore() {}
// Add a key to the store.
virtual bool AddKey(const CKey& key) =0;
// Check whether a key corresponding to a given address is present in the store.
virtual bool HaveKey(const CKeyID &address) const =0;
virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0;
virtual void GetKeys(std::set<CKeyID> &setAddress) const =0;
virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
// Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
virtual bool AddCScript(const CScript& redeemScript) =0;
virtual bool HaveCScript(const CScriptID &hash) const =0;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const
{
CKey key;
if (!GetKey(address, key))
return false;
vchSecret = key.GetSecret(fCompressed);
return true;
}
};
typedef std::map<CKeyID, std::pair<CSecret, bool> > KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore
{
protected:
KeyMap mapKeys;
ScriptMap mapScripts;
public:
bool AddKey(const CKey& key);
bool HaveKey(const CKeyID &address) const
{
bool result;
{
LOCK(cs_KeyStore);
result = (mapKeys.count(address) > 0);
}
return result;
}
void GetKeys(std::set<CKeyID> &setAddress) const
{
setAddress.clear();
{
LOCK(cs_KeyStore);
KeyMap::const_iterator mi = mapKeys.begin();
while (mi != mapKeys.end())
{
setAddress.insert((*mi).first);
mi++;
}
}
}
bool GetKey(const CKeyID &address, CKey &keyOut) const
{
{
LOCK(cs_KeyStore);
KeyMap::const_iterator mi = mapKeys.find(address);
if (mi != mapKeys.end())
{
keyOut.Reset();
keyOut.SetSecret((*mi).second.first, (*mi).second.second);
return true;
}
}
return false;
}
virtual bool AddCScript(const CScript& redeemScript);
virtual bool HaveCScript(const CScriptID &hash) const;
virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;
};
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
/** Keystore which keeps the private keys encrypted.
* It derives from the basic key store, which is used if no encryption is active.
*/
class CCryptoKeyStore : public CBasicKeyStore
{
private:
CryptedKeyMap mapCryptedKeys;
CKeyingMaterial vMasterKey;
// if fUseCrypto is true, mapKeys must be empty
// if fUseCrypto is false, vMasterKey must be empty
bool fUseCrypto;
protected:
bool SetCrypted();
// will encrypt previously unencrypted keys
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
public:
CCryptoKeyStore() : fUseCrypto(false)
{
}
bool IsCrypted() const
{
return fUseCrypto;
}
bool IsLocked() const
{
if (!IsCrypted())
return false;
bool result;
{
LOCK(cs_KeyStore);
result = vMasterKey.empty();
}
return result;
}
bool Lock();
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKey(const CKey& key);
bool HaveKey(const CKeyID &address) const
{
{
LOCK(cs_KeyStore);
if (!IsCrypted())
return CBasicKeyStore::HaveKey(address);
return mapCryptedKeys.count(address) > 0;
}
return false;
}
bool GetKey(const CKeyID &address, CKey& keyOut) const;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
void GetKeys(std::set<CKeyID> &setAddress) const
{
if (!IsCrypted())
{
CBasicKeyStore::GetKeys(setAddress);
return;
}
setAddress.clear();
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
while (mi != mapCryptedKeys.end())
{
setAddress.insert((*mi).first);
mi++;
}
}
/* Wallet status (encrypted, locked) changed.
* Note: Called without locks held.
*/
boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
};
#endif

3883
src/main.cpp Normal file

File diff suppressed because it is too large Load Diff

1640
src/main.h Normal file

File diff suppressed because it is too large Load Diff

105
src/makefile.linux-mingw Normal file
View File

@@ -0,0 +1,105 @@
# 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.
DEPSDIR:=/usr/i586-mingw32msvc
USE_UPNP:=0
INCLUDEPATHS= \
-I"$(DEPSDIR)/boost_1_49_0" \
-I"$(DEPSDIR)/db-4.8.30.NC/build_unix" \
-I"$(DEPSDIR)/openssl-1.0.1b/include" \
-I"$(DEPSDIR)" \
-I"$(CURDIR)"/obj \
LIBPATHS= \
-L"$(DEPSDIR)/boost_1_49_0/stage/lib" \
-L"$(DEPSDIR)/db-4.8.30.NC/build_unix" \
-L"$(DEPSDIR)/openssl-1.0.1b"
LIBS= \
-l boost_system-mt-s \
-l boost_filesystem-mt-s \
-l boost_program_options-mt-s \
-l boost_thread_win32-mt-s \
-l db_cxx \
-l ssl \
-l crypto
DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6
DEBUGFLAGS=-g
CFLAGS=-O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
ifdef USE_UPNP
LIBPATHS += -L"$(DEPSDIR)/miniupnpc"
LIBS += -l miniupnpc -l iphlpapi
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi
# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are
HEADERS = $(wildcard *.h)
OBJS= \
obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
obj/bitcoinrpc.o \
obj/rpcdump.o \
obj/rpcnet.o \
obj/rpcrawtransaction.o \
obj/script.o \
obj/scrypt.o \
obj/sync.o \
obj/util.o \
obj/wallet.o \
obj/walletdb.o \
obj/noui.o
all: casinocoind.exe
obj/scrypt.o: scrypt.c
i586-mingw32msvc-gcc -c $(CFLAGS) -o $@ $^
obj/build.h: FORCE
/bin/sh ../share/genbuild.sh obj/build.h
version.cpp: obj/build.h
DEFS += -DHAVE_BUILD_INFO
obj/%.o: %.cpp $(HEADERS)
i586-mingw32msvc-g++ -c $(CFLAGS) -o $@ $<
casinocoind.exe: $(OBJS:obj/%=obj/%)
i586-mingw32msvc-g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp $(HEADERS)
i586-mingw32msvc-g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
test_casinocoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
i586-mingw32msvc-g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS)
clean:
-rm -f obj/*.o
-rm -f casinocoind.exe
-rm -f obj-test/*.o
-rm -f test_casinocoin.exe
-rm -f src/build.h
FORCE:

95
src/makefile.mingw Normal file
View File

@@ -0,0 +1,95 @@
# 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.
USE_UPNP:=
INCLUDEPATHS= \
-I"E:\crypto\deps\boost_1_53_0" \
-I"E:\crypto\deps\db-4.8.30.NC\build_unix" \
-I"E:\crypto\deps\openssl-1.0.1b\include"
LIBPATHS= \
-L"E:\crypto\deps\boost_1_53_0\stage\lib" \
-L"E:\crypto\deps\db-4.8.30.NC\build_unix" \
-L"E:\crypto\deps\openssl-1.0.1b"
LIBS= \
-l boost_system-mgw46-mt-s-1_53 \
-l boost_filesystem-mgw46-mt-s-1_53 \
-l boost_program_options-mgw46-mt-s-1_53 \
-l boost_thread-mgw46-mt-s-1_53 \
-l db_cxx \
-l ssl \
-l crypto
DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6 -D__NO_SYSTEM_INCLUDES
DEBUGFLAGS=-g
CFLAGS=-mthreads -O2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS) -static
TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
ifdef USE_UPNP
INCLUDEPATHS += -I"C:\miniupnpc-1.6-mgw"
LIBPATHS += -L"C:\miniupnpc-1.6-mgw"
LIBS += -l miniupnpc -l iphlpapi
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi
# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are
HEADERS = $(wildcard *.h)
OBJS= \
obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
obj/bitcoinrpc.o \
obj/rpcdump.o \
obj/rpcnet.o \
obj/rpcrawtransaction.o \
obj/script.o \
obj/scrypt.o \
obj/sync.o \
obj/util.o \
obj/wallet.o \
obj/walletdb.o \
obj/noui.o
all: casinocoind.exe
obj/scrypt.o: scrypt.c
gcc -c $(CFLAGS) -o $@ $^
obj/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -o $@ $<
casinocoind.exe: $(OBJS:obj/%=obj/%)
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp $(HEADERS)
g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
test_casinocoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
g++ $(CFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS)
clean:
-del /Q casinocoind test_casinocoin
-del /Q obj\*
-del /Q obj-test\*
-del /Q build.h

154
src/makefile.osx Normal file
View File

@@ -0,0 +1,154 @@
# -*- mode: Makefile; -*-
# Copyright (c) 2011 Bitcoin Developers
# Distributed under the MIT/X11 software license, see the accompanying
# file license.txt or http://www.opensource.org/licenses/mit-license.php.
# Mac OS X makefile for casinocoin
# Originally by Laszlo Hanyecz (solar@heliacal.net)
CXX=llvm-g++
DEPSDIR=/opt/local
INCLUDEPATHS= \
-I"$(CURDIR)" \
-I"$(CURDIR)"/obj \
-I"$(DEPSDIR)/include" \
-I"$(DEPSDIR)/include/db48"
LIBPATHS= \
-L"$(DEPSDIR)/lib" \
-L"$(DEPSDIR)/lib/db48"
USE_UPNP:=1
LIBS= -dead_strip
TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
ifdef STATIC
# Build STATIC if you are redistributing the casinocoind binary
TESTLIBS += \
$(DEPSDIR)/lib/libboost_unit_test_framework-mt.a
LIBS += \
$(DEPSDIR)/lib/db48/libdb_cxx-4.8.a \
$(DEPSDIR)/lib/libboost_system-mt.a \
$(DEPSDIR)/lib/libboost_filesystem-mt.a \
$(DEPSDIR)/lib/libboost_program_options-mt.a \
$(DEPSDIR)/lib/libboost_thread-mt.a \
$(DEPSDIR)/lib/libssl.a \
$(DEPSDIR)/lib/libcrypto.a \
-lz
else
TESTLIBS += \
-lboost_unit_test_framework-mt
LIBS += \
-ldb_cxx-4.8 \
-lboost_system-mt \
-lboost_filesystem-mt \
-lboost_program_options-mt \
-lboost_thread-mt \
-lssl \
-lcrypto \
-lz
TESTDEFS += -DBOOST_TEST_DYN_LINK
endif
DEFS=-DMAC_OSX -DMSG_NOSIGNAL=0 -DBOOST_SPIRIT_THREADSAFE -DUSE_IPV6
ifdef RELEASE
# Compile for maximum compatibility and smallest size.
# This requires that dependencies are compiled
# the same way.
CFLAGS = -mmacosx-version-min=10.5 -arch i386 -O3
else
CFLAGS = -g
endif
# ppc doesn't work because we don't support big-endian
CFLAGS += -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
$(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
OBJS= \
obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
obj/bitcoinrpc.o \
obj/rpcdump.o \
obj/rpcnet.o \
obj/rpcrawtransaction.o \
obj/script.o \
obj/scrypt.o \
obj/sync.o \
obj/util.o \
obj/wallet.o \
obj/walletdb.o \
obj/noui.o
ifdef USE_UPNP
DEFS += -DUSE_UPNP=$(USE_UPNP)
ifdef STATIC
LIBS += $(DEPSDIR)/lib/libminiupnpc.a
else
LIBS += -lminiupnpc
endif
endif
all: casinocoind
# auto-generated dependencies:
-include obj/*.P
-include obj-test/*.P
obj/scrypt.o: scrypt.c
gcc -c $(CFLAGS) -MMD -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
obj/build.h: FORCE
/bin/sh ../share/genbuild.sh obj/build.h
version.cpp: obj/build.h
DEFS += -DHAVE_BUILD_INFO
obj/%.o: %.cpp
$(CXX) -c $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
casinocoind: $(OBJS:obj/%=obj/%)
$(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp
$(CXX) -c $(TESTDEFS) $(CFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
test_casinocoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
$(CXX) $(CFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) $(TESTLIBS)
clean:
-rm -f casinocoind test_casinocoin
-rm -f obj/*.o
-rm -f obj-test/*.o
-rm -f obj/*.P
-rm -f obj-test/*.P
-rm -f src/build.h
FORCE:

167
src/makefile.unix Normal file
View File

@@ -0,0 +1,167 @@
# 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.
USE_UPNP:=0
DEFS=-DUSE_IPV6 -DBOOST_SPIRIT_THREADSAFE
DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
LMODE = dynamic
LMODE2 = dynamic
ifdef STATIC
LMODE = static
ifeq (${STATIC}, all)
LMODE2 = static
endif
else
TESTDEFS += -DBOOST_TEST_DYN_LINK
endif
# for boost 1.37, add -mt to the boost libraries
LIBS += \
-Wl,-B$(LMODE) \
-l boost_system$(BOOST_LIB_SUFFIX) \
-l boost_filesystem$(BOOST_LIB_SUFFIX) \
-l boost_program_options$(BOOST_LIB_SUFFIX) \
-l boost_thread$(BOOST_LIB_SUFFIX) \
-l db_cxx$(BDB_LIB_SUFFIX) \
-l ssl \
-l crypto
ifndef USE_UPNP
override USE_UPNP = -
endif
ifneq (${USE_UPNP}, -)
LIBS += -l miniupnpc
DEFS += -DUSE_UPNP=$(USE_UPNP)
endif
LIBS+= \
-Wl,-B$(LMODE2) \
-l z \
-l dl \
-l pthread
# Hardening
# Make some classes of vulnerabilities unexploitable in case one is discovered.
#
# This is a workaround for Ubuntu bug #691722, the default -fstack-protector causes
# -fstack-protector-all to be ignored unless -fno-stack-protector is used first.
# see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722
HARDENING=-fno-stack-protector
# Stack Canaries
# Put numbers at the beginning of each stack frame and check that they are the same.
# If a stack buffer if overflowed, it writes over the canary number and then on return
# when that number is checked, it won't be the same and the program will exit with
# a "Stack smashing detected" error instead of being exploited.
HARDENING+=-fstack-protector-all -Wstack-protector
# Make some important things such as the global offset table read only as soon as
# the dynamic linker is finished building it. This will prevent overwriting of addresses
# which would later be jumped to.
LDHARDENING+=-Wl,-z,relro -Wl,-z,now
# Build position independent code to take advantage of Address Space Layout Randomization
# offered by some kernels.
# see doc/build-unix.txt for more information.
ifdef PIE
HARDENING+=-fPIE
LDHARDENING+=-pie
endif
# -D_FORTIFY_SOURCE=2 does some checking for potentially exploitable code patterns in
# the source such overflowing a statically defined buffer.
HARDENING+=-D_FORTIFY_SOURCE=2
#
DEBUGFLAGS=-g
# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only
# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work.
xCXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
$(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
# LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only
# adds some defaults in front. Unfortunately, LDFLAGS=... $(LDFLAGS) does not work.
xLDFLAGS=$(LDHARDENING) $(LDFLAGS)
OBJS= \
obj/version.o \
obj/checkpoints.o \
obj/netbase.o \
obj/addrman.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
obj/main.o \
obj/net.o \
obj/protocol.o \
obj/bitcoinrpc.o \
obj/rpcdump.o \
obj/rpcnet.o \
obj/rpcrawtransaction.o \
obj/script.o \
obj/scrypt.o \
obj/sync.o \
obj/util.o \
obj/wallet.o \
obj/walletdb.o \
obj/noui.o
all: casinocoind
# auto-generated dependencies:
-include obj/*.P
-include obj-test/*.P
obj/scrypt.o: scrypt.c
gcc -c -o $@ $^
obj/build.h: FORCE
/bin/sh ../share/genbuild.sh obj/build.h
version.cpp: obj/build.h
DEFS += -DHAVE_BUILD_INFO
obj/%.o: %.cpp
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
casinocoind: $(OBJS:obj/%=obj/%)
$(CXX) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp
$(CXX) -c $(TESTDEFS) $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
rm -f $(@:%.o=%.d)
test_casinocoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
$(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-B$(LMODE) -lboost_unit_test_framework $(xLDFLAGS) $(LIBS)
clean:
-rm -f casinocoind test_casinocoin
-rm -f obj/*.o
-rm -f obj-test/*.o
-rm -f obj/*.P
-rm -f obj-test/*.P
-rm -f src/build.h
FORCE:

65
src/mruset.h Normal file
View File

@@ -0,0 +1,65 @@
// Copyright (c) 2012 The Bitcoin developers
// Copyright (c) 2012 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_MRUSET_H
#define BITCOIN_MRUSET_H
#include <set>
#include <deque>
/** STL-like set container that only keeps the most recent N elements. */
template <typename T> class mruset
{
public:
typedef T key_type;
typedef T value_type;
typedef typename std::set<T>::iterator iterator;
typedef typename std::set<T>::const_iterator const_iterator;
typedef typename std::set<T>::size_type size_type;
protected:
std::set<T> set;
std::deque<T> queue;
size_type nMaxSize;
public:
mruset(size_type nMaxSizeIn = 0) { nMaxSize = nMaxSizeIn; }
iterator begin() const { return set.begin(); }
iterator end() const { return set.end(); }
size_type size() const { return set.size(); }
bool empty() const { return set.empty(); }
iterator find(const key_type& k) const { return set.find(k); }
size_type count(const key_type& k) const { return set.count(k); }
bool inline friend operator==(const mruset<T>& a, const mruset<T>& b) { return a.set == b.set; }
bool inline friend operator==(const mruset<T>& a, const std::set<T>& b) { return a.set == b; }
bool inline friend operator<(const mruset<T>& a, const mruset<T>& b) { return a.set < b.set; }
std::pair<iterator, bool> insert(const key_type& x)
{
std::pair<iterator, bool> ret = set.insert(x);
if (ret.second)
{
if (nMaxSize && queue.size() == nMaxSize)
{
set.erase(queue.front());
queue.pop_front();
}
queue.push_back(x);
}
return ret;
}
size_type max_size() const { return nMaxSize; }
size_type max_size(size_type s)
{
if (s)
while (queue.size() > s)
{
set.erase(queue.front());
queue.pop_front();
}
nMaxSize = s;
return nMaxSize;
}
};
#endif

1983
src/net.cpp Normal file

File diff suppressed because it is too large Load Diff

692
src/net.h Normal file
View File

@@ -0,0 +1,692 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
#include <deque>
#include <boost/array.hpp>
#include <boost/foreach.hpp>
#include <openssl/rand.h>
#ifndef WIN32
#include <arpa/inet.h>
#endif
#include "mruset.h"
#include "netbase.h"
#include "protocol.h"
#include "addrman.h"
class CRequestTracker;
class CNode;
class CBlockIndex;
extern int nBestHeight;
inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
void AddOneShot(std::string strDest);
bool RecvLine(SOCKET hSocket, std::string& strLine);
bool GetMyExternalIP(CNetAddr& ipRet);
void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *strDest = NULL, int64 nTimeout=0);
void MapPort();
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError=REF(std::string()));
void StartNode(void* parg);
bool StopNode();
enum
{
LOCAL_NONE, // unknown
LOCAL_IF, // address a local interface listens on
LOCAL_BIND, // address explicit bound to
LOCAL_UPNP, // address reported by UPnP
LOCAL_IRC, // address reported by IRC (deprecated)
LOCAL_HTTP, // address reported by whatismyip.com and similars
LOCAL_MANUAL, // address explicitly specified (-externalip=)
LOCAL_MAX
};
void SetLimited(enum Network net, bool fLimited = true);
bool IsLimited(enum Network net);
bool IsLimited(const CNetAddr& addr);
bool AddLocal(const CService& addr, int nScore = LOCAL_NONE);
bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(const CNetAddr &addr);
void SetReachable(enum Network net, bool fFlag = true);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
enum
{
MSG_TX = 1,
MSG_BLOCK,
};
class CRequestTracker
{
public:
void (*fn)(void*, CDataStream&);
void* param1;
explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
{
fn = fnIn;
param1 = param1In;
}
bool IsNull()
{
return fn == NULL;
}
};
/** Thread types */
enum threadId
{
THREAD_SOCKETHANDLER,
THREAD_OPENCONNECTIONS,
THREAD_MESSAGEHANDLER,
THREAD_MINER,
THREAD_RPCLISTENER,
THREAD_UPNP,
THREAD_DNSSEED,
THREAD_ADDEDCONNECTIONS,
THREAD_DUMPADDRESS,
THREAD_RPCHANDLER,
THREAD_MAX
};
extern bool fClient;
extern bool fDiscover;
extern bool fUseUPnP;
extern uint64 nLocalServices;
extern uint64 nLocalHostNonce;
extern boost::array<int, THREAD_MAX> vnThreadsRunning;
extern CAddrMan addrman;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
extern std::map<CInv, CDataStream> mapRelay;
extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
extern std::map<CInv, int64> mapAlreadyAskedFor;
class CNodeStats
{
public:
uint64 nServices;
int64 nLastSend;
int64 nLastRecv;
int64 nTimeConnected;
std::string addrName;
int nVersion;
std::string strSubVer;
bool fInbound;
int64 nReleaseTime;
int nStartingHeight;
int nMisbehavior;
};
/** Information about a peer */
class CNode
{
public:
// socket
uint64 nServices;
SOCKET hSocket;
CDataStream vSend;
CDataStream vRecv;
CCriticalSection cs_vSend;
CCriticalSection cs_vRecv;
int64 nLastSend;
int64 nLastRecv;
int64 nLastSendEmpty;
int64 nTimeConnected;
int nHeaderStart;
unsigned int nMessageStart;
CAddress addr;
std::string addrName;
CService addrLocal;
int nVersion;
std::string strSubVer;
bool fOneShot;
bool fClient;
bool fInbound;
bool fNetworkNode;
bool fSuccessfullyConnected;
bool fDisconnect;
CSemaphoreGrant grantOutbound;
protected:
int nRefCount;
// Denial-of-service detection/prevention
// Key is ip address, value is banned-until-time
static std::map<CNetAddr, int64> setBanned;
static CCriticalSection cs_setBanned;
int nMisbehavior;
public:
int64 nReleaseTime;
std::map<uint256, CRequestTracker> mapRequests;
CCriticalSection cs_mapRequests;
uint256 hashContinue;
CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd;
int nStartingHeight;
// flood relay
std::vector<CAddress> vAddrToSend;
std::set<CAddress> setAddrKnown;
bool fGetAddr;
std::set<uint256> setKnown;
// inventory based relay
mruset<CInv> setInventoryKnown;
std::vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory;
std::multimap<int64, CInv> mapAskFor;
CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : vSend(SER_NETWORK, MIN_PROTO_VERSION), vRecv(SER_NETWORK, MIN_PROTO_VERSION)
{
nServices = 0;
hSocket = hSocketIn;
nLastSend = 0;
nLastRecv = 0;
nLastSendEmpty = GetTime();
nTimeConnected = GetTime();
nHeaderStart = -1;
nMessageStart = -1;
addr = addrIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
nVersion = 0;
strSubVer = "";
fOneShot = false;
fClient = false; // set by version message
fInbound = fInboundIn;
fNetworkNode = false;
fSuccessfullyConnected = false;
fDisconnect = false;
nRefCount = 0;
nReleaseTime = 0;
hashContinue = 0;
pindexLastGetBlocksBegin = 0;
hashLastGetBlocksEnd = 0;
nStartingHeight = -1;
fGetAddr = false;
nMisbehavior = 0;
setInventoryKnown.max_size(SendBufferSize() / 1000);
// Be shy and don't send version until we hear
if (!fInbound)
PushVersion();
}
~CNode()
{
if (hSocket != INVALID_SOCKET)
{
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
}
private:
CNode(const CNode&);
void operator=(const CNode&);
public:
int GetRefCount()
{
return std::max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
}
CNode* AddRef(int64 nTimeout=0)
{
if (nTimeout != 0)
nReleaseTime = std::max(nReleaseTime, GetTime() + nTimeout);
else
nRefCount++;
return this;
}
void Release()
{
nRefCount--;
}
void AddAddressKnown(const CAddress& addr)
{
setAddrKnown.insert(addr);
}
void PushAddress(const CAddress& addr)
{
// Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added
// after addresses were pushed.
if (addr.IsValid() && !setAddrKnown.count(addr))
vAddrToSend.push_back(addr);
}
void AddInventoryKnown(const CInv& inv)
{
{
LOCK(cs_inventory);
setInventoryKnown.insert(inv);
}
}
void PushInventory(const CInv& inv)
{
{
LOCK(cs_inventory);
if (!setInventoryKnown.count(inv))
vInventoryToSend.push_back(inv);
}
}
void AskFor(const CInv& inv)
{
// We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent
int64& nRequestTime = mapAlreadyAskedFor[inv];
if (fDebugNet)
printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
// Make sure not to reuse time indexes to keep things in the same order
int64 nNow = (GetTime() - 1) * 1000000;
static int64 nLastTime;
++nLastTime;
nNow = std::max(nNow, nLastTime);
nLastTime = nNow;
// Each retry is 2 minutes after the last
nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
mapAskFor.insert(std::make_pair(nRequestTime, inv));
}
void BeginMessage(const char* pszCommand)
{
ENTER_CRITICAL_SECTION(cs_vSend);
if (nHeaderStart != -1)
AbortMessage();
nHeaderStart = vSend.size();
vSend << CMessageHeader(pszCommand, 0);
nMessageStart = vSend.size();
if (fDebug)
printf("sending: %s ", pszCommand);
}
void AbortMessage()
{
if (nHeaderStart < 0)
return;
vSend.resize(nHeaderStart);
nHeaderStart = -1;
nMessageStart = -1;
LEAVE_CRITICAL_SECTION(cs_vSend);
if (fDebug)
printf("(aborted)\n");
}
void EndMessage()
{
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
printf("dropmessages DROPPING SEND MESSAGE\n");
AbortMessage();
return;
}
if (nHeaderStart < 0)
return;
// Set the size
unsigned int nSize = vSend.size() - nMessageStart;
memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::MESSAGE_SIZE_OFFSET, &nSize, sizeof(nSize));
// Set the checksum
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end());
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
assert(nMessageStart - nHeaderStart >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
memcpy((char*)&vSend[nHeaderStart] + CMessageHeader::CHECKSUM_OFFSET, &nChecksum, sizeof(nChecksum));
if (fDebug) {
printf("(%d bytes)\n", nSize);
}
nHeaderStart = -1;
nMessageStart = -1;
LEAVE_CRITICAL_SECTION(cs_vSend);
}
void EndMessageAbortIfEmpty()
{
if (nHeaderStart < 0)
return;
int nSize = vSend.size() - nMessageStart;
if (nSize > 0)
EndMessage();
else
AbortMessage();
}
void PushVersion();
void PushMessage(const char* pszCommand)
{
try
{
BeginMessage(pszCommand);
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1>
void PushMessage(const char* pszCommand, const T1& a1)
{
try
{
BeginMessage(pszCommand);
vSend << a1;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)
{
try
{
BeginMessage(pszCommand);
vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
EndMessage();
}
catch (...)
{
AbortMessage();
throw;
}
}
void PushRequest(const char* pszCommand,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
{
LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
}
PushMessage(pszCommand, hashReply);
}
template<typename T1>
void PushRequest(const char* pszCommand, const T1& a1,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
{
LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
}
PushMessage(pszCommand, hashReply, a1);
}
template<typename T1, typename T2>
void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
void (*fn)(void*, CDataStream&), void* param1)
{
uint256 hashReply;
RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
{
LOCK(cs_mapRequests);
mapRequests[hashReply] = CRequestTracker(fn, param1);
}
PushMessage(pszCommand, hashReply, a1, a2);
}
void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
bool IsSubscribed(unsigned int nChannel);
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel);
void CloseSocketDisconnect();
void Cleanup();
// Denial-of-service detection/prevention
// The idea is to detect peers that are behaving
// badly and disconnect/ban them, but do it in a
// one-coding-mistake-won't-shatter-the-entire-network
// way.
// IMPORTANT: There should be nothing I can give a
// node that it will forward on that will make that
// node's peers drop it. If there is, an attacker
// can isolate a node and/or try to split the network.
// Dropping a node for sending stuff that is invalid
// now but might be valid in a later version is also
// dangerous, because it can cause a network split
// between nodes running old code and nodes running
// new code.
static void ClearBanned(); // needed for unit testing
static bool IsBanned(CNetAddr ip);
bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
void copyStats(CNodeStats &stats);
};
inline void RelayInventory(const CInv& inv)
{
// Put on lists to offer to the other nodes
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
pnode->PushInventory(inv);
}
}
template<typename T>
void RelayMessage(const CInv& inv, const T& a)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(10000);
ss << a;
RelayMessage(inv, ss);
}
template<>
inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
{
{
LOCK(cs_mapRelay);
// Expire old relay messages
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
{
mapRelay.erase(vRelayExpiration.front().second);
vRelayExpiration.pop_front();
}
// Save original serialized message so newer versions are preserved
mapRelay.insert(std::make_pair(inv, ss));
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv));
}
RelayInventory(inv);
}
#endif

1165
src/netbase.cpp Normal file

File diff suppressed because it is too large Load Diff

153
src/netbase.h Normal file
View File

@@ -0,0 +1,153 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NETBASE_H
#define BITCOIN_NETBASE_H
#include <string>
#include <vector>
#include "serialize.h"
#include "compat.h"
extern int nConnectTimeout;
#ifdef WIN32
// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error
#undef SetPort
#endif
enum Network
{
NET_UNROUTABLE,
NET_IPV4,
NET_IPV6,
NET_TOR,
NET_I2P,
NET_MAX,
};
extern int nConnectTimeout;
extern bool fNameLookup;
/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
class CNetAddr
{
protected:
unsigned char ip[16]; // in network byte order
public:
CNetAddr();
CNetAddr(const struct in_addr& ipv4Addr);
explicit CNetAddr(const char *pszIp, bool fAllowLookup = false);
explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false);
void Init();
void SetIP(const CNetAddr& ip);
bool SetSpecial(const std::string &strName); // for Tor and I2P addresses
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
bool IsRFC3964() const; // IPv6 6to4 tunneling (2002::/16)
bool IsRFC4193() const; // IPv6 unique local (FC00::/15)
bool IsRFC4380() const; // IPv6 Teredo tunneling (2001::/32)
bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
bool IsTor() const;
bool IsI2P() const;
bool IsLocal() const;
bool IsRoutable() const;
bool IsValid() const;
bool IsMulticast() const;
enum Network GetNetwork() const;
std::string ToString() const;
std::string ToStringIP() const;
int GetByte(int n) const;
uint64 GetHash() const;
bool GetInAddr(struct in_addr* pipv4Addr) const;
std::vector<unsigned char> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
void print() const;
#ifdef USE_IPV6
CNetAddr(const struct in6_addr& pipv6Addr);
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
#endif
friend bool operator==(const CNetAddr& a, const CNetAddr& b);
friend bool operator!=(const CNetAddr& a, const CNetAddr& b);
friend bool operator<(const CNetAddr& a, const CNetAddr& b);
IMPLEMENT_SERIALIZE
(
READWRITE(FLATDATA(ip));
)
};
/** A combination of a network address (CNetAddr) and a (TCP) port */
class CService : public CNetAddr
{
protected:
unsigned short port; // host order
public:
CService();
CService(const CNetAddr& ip, unsigned short port);
CService(const struct in_addr& ipv4Addr, unsigned short port);
CService(const struct sockaddr_in& addr);
explicit CService(const char *pszIpPort, int portDefault, bool fAllowLookup = false);
explicit CService(const char *pszIpPort, bool fAllowLookup = false);
explicit CService(const std::string& strIpPort, int portDefault, bool fAllowLookup = false);
explicit CService(const std::string& strIpPort, bool fAllowLookup = false);
void Init();
void SetPort(unsigned short portIn);
unsigned short GetPort() const;
bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
bool SetSockAddr(const struct sockaddr* paddr);
friend bool operator==(const CService& a, const CService& b);
friend bool operator!=(const CService& a, const CService& b);
friend bool operator<(const CService& a, const CService& b);
std::vector<unsigned char> GetKey() const;
std::string ToString() const;
std::string ToStringPort() const;
std::string ToStringIPPort() const;
void print() const;
#ifdef USE_IPV6
CService(const struct in6_addr& ipv6Addr, unsigned short port);
CService(const struct sockaddr_in6& addr);
#endif
IMPLEMENT_SERIALIZE
(
CService* pthis = const_cast<CService*>(this);
READWRITE(FLATDATA(ip));
unsigned short portN = htons(port);
READWRITE(portN);
if (fRead)
pthis->port = ntohs(portN);
)
};
enum Network ParseNetwork(std::string net);
void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
bool GetProxy(enum Network net, CService &addrProxy);
bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(CService addrProxy, int nSocksVersion = 5);
bool GetNameProxy();
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true);
bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0);
bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true);
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0);
bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0);
bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout);
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout);
#endif

30
src/noui.cpp Normal file
View File

@@ -0,0 +1,30 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "ui_interface.h"
#include "init.h"
#include "bitcoinrpc.h"
#include <string>
static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
{
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
return 4;
}
static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
{
return true;
}
void noui_connect()
{
// Connect bitcoind signal handlers
uiInterface.ThreadSafeMessageBox.connect(noui_ThreadSafeMessageBox);
uiInterface.ThreadSafeAskFee.connect(noui_ThreadSafeAskFee);
}

152
src/protocol.cpp Normal file
View File

@@ -0,0 +1,152 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "protocol.h"
#include "util.h"
#include "netbase.h"
#ifndef WIN32
# include <arpa/inet.h>
#endif
static const char* ppszTypeName[] =
{
"ERROR",
"tx",
"block",
};
CMessageHeader::CMessageHeader()
{
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
memset(pchCommand, 0, sizeof(pchCommand));
pchCommand[1] = 1;
nMessageSize = -1;
nChecksum = 0;
}
CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
{
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
strncpy(pchCommand, pszCommand, COMMAND_SIZE);
nMessageSize = nMessageSizeIn;
nChecksum = 0;
}
std::string CMessageHeader::GetCommand() const
{
if (pchCommand[COMMAND_SIZE-1] == 0)
return std::string(pchCommand, pchCommand + strlen(pchCommand));
else
return std::string(pchCommand, pchCommand + COMMAND_SIZE);
}
bool CMessageHeader::IsValid() const
{
// Check start string
if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
return false;
// Check the command string for errors
for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
{
if (*p1 == 0)
{
// Must be all zeros after the first zero
for (; p1 < pchCommand + COMMAND_SIZE; p1++)
if (*p1 != 0)
return false;
}
else if (*p1 < ' ' || *p1 > 0x7E)
return false;
}
// Message size
if (nMessageSize > MAX_SIZE)
{
printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize);
return false;
}
return true;
}
CAddress::CAddress() : CService()
{
Init();
}
CAddress::CAddress(CService ipIn, uint64 nServicesIn) : CService(ipIn)
{
Init();
nServices = nServicesIn;
}
void CAddress::Init()
{
nServices = NODE_NETWORK;
nTime = 100000000;
nLastTry = 0;
}
CInv::CInv()
{
type = 0;
hash = 0;
}
CInv::CInv(int typeIn, const uint256& hashIn)
{
type = typeIn;
hash = hashIn;
}
CInv::CInv(const std::string& strType, const uint256& hashIn)
{
unsigned int i;
for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
{
if (strType == ppszTypeName[i])
{
type = i;
break;
}
}
if (i == ARRAYLEN(ppszTypeName))
throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
hash = hashIn;
}
bool operator<(const CInv& a, const CInv& b)
{
return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
}
bool CInv::IsKnownType() const
{
return (type >= 1 && type < (int)ARRAYLEN(ppszTypeName));
}
const char* CInv::GetCommand() const
{
if (!IsKnownType())
throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
return ppszTypeName[type];
}
std::string CInv::ToString() const
{
return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
}
void CInv::print() const
{
printf("CInv(%s)\n", ToString().c_str());
}

139
src/protocol.h Normal file
View File

@@ -0,0 +1,139 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef __cplusplus
# error This header can only be compiled as C++.
#endif
#ifndef __INCLUDED_PROTOCOL_H__
#define __INCLUDED_PROTOCOL_H__
#include "serialize.h"
#include "netbase.h"
#include <string>
#include "uint256.h"
extern bool fTestNet;
static inline unsigned short GetDefaultPort(const bool testnet = fTestNet)
{
return testnet ? 17950 : 47950;
}
extern unsigned char pchMessageStart[4];
/** Message header.
* (4) message start.
* (12) command.
* (4) size.
* (4) checksum.
*/
class CMessageHeader
{
public:
CMessageHeader();
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn);
std::string GetCommand() const;
bool IsValid() const;
IMPLEMENT_SERIALIZE
(
READWRITE(FLATDATA(pchMessageStart));
READWRITE(FLATDATA(pchCommand));
READWRITE(nMessageSize);
READWRITE(nChecksum);
)
// TODO: make private (improves encapsulation)
public:
enum {
MESSAGE_START_SIZE=sizeof(::pchMessageStart),
COMMAND_SIZE=12,
MESSAGE_SIZE_SIZE=sizeof(int),
CHECKSUM_SIZE=sizeof(int),
MESSAGE_SIZE_OFFSET=MESSAGE_START_SIZE+COMMAND_SIZE,
CHECKSUM_OFFSET=MESSAGE_SIZE_OFFSET+MESSAGE_SIZE_SIZE
};
char pchMessageStart[MESSAGE_START_SIZE];
char pchCommand[COMMAND_SIZE];
unsigned int nMessageSize;
unsigned int nChecksum;
};
/** nServices flags */
enum
{
NODE_NETWORK = (1 << 0),
};
/** A CService with information about it as peer */
class CAddress : public CService
{
public:
CAddress();
explicit CAddress(CService ipIn, uint64 nServicesIn=NODE_NETWORK);
void Init();
IMPLEMENT_SERIALIZE
(
CAddress* pthis = const_cast<CAddress*>(this);
CService* pip = (CService*)pthis;
if (fRead)
pthis->Init();
if (nType & SER_DISK)
READWRITE(nVersion);
if ((nType & SER_DISK) ||
(nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH)))
READWRITE(nTime);
READWRITE(nServices);
READWRITE(*pip);
)
void print() const;
// TODO: make private (improves encapsulation)
public:
uint64 nServices;
// disk and network only
unsigned int nTime;
// memory only
int64 nLastTry;
};
/** inv message data */
class CInv
{
public:
CInv();
CInv(int typeIn, const uint256& hashIn);
CInv(const std::string& strType, const uint256& hashIn);
IMPLEMENT_SERIALIZE
(
READWRITE(type);
READWRITE(hash);
)
friend bool operator<(const CInv& a, const CInv& b);
bool IsKnownType() const;
const char* GetCommand() const;
std::string ToString() const;
void print() const;
// TODO: make private (improves encapsulation)
public:
int type;
uint256 hash;
};
#endif // __INCLUDED_PROTOCOL_H__

30
src/qt/aboutdialog.cpp Normal file
View File

@@ -0,0 +1,30 @@
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include "clientmodel.h"
#include "version.h"
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutDialog)
{
ui->setupUi(this);
}
void AboutDialog::setModel(ClientModel *model)
{
if(model)
{
ui->versionLabel->setText(model->formatFullVersion());
}
}
AboutDialog::~AboutDialog()
{
delete ui;
}
void AboutDialog::on_buttonBox_accepted()
{
close();
}

28
src/qt/aboutdialog.h Normal file
View File

@@ -0,0 +1,28 @@
#ifndef ABOUTDIALOG_H
#define ABOUTDIALOG_H
#include <QDialog>
namespace Ui {
class AboutDialog;
}
class ClientModel;
/** "About" dialog box */
class AboutDialog : public QDialog
{
Q_OBJECT
public:
explicit AboutDialog(QWidget *parent = 0);
~AboutDialog();
void setModel(ClientModel *model);
private:
Ui::AboutDialog *ui;
private slots:
void on_buttonBox_accepted();
};
#endif // ABOUTDIALOG_H

374
src/qt/addressbookpage.cpp Normal file
View File

@@ -0,0 +1,374 @@
#include "addressbookpage.h"
#include "ui_addressbookpage.h"
#include "addresstablemodel.h"
#include "optionsmodel.h"
#include "bitcoingui.h"
#include "editaddressdialog.h"
#include "csvmodelwriter.h"
#include "guiutil.h"
#include <QSortFilterProxyModel>
#include <QClipboard>
#include <QMessageBox>
#include <QMenu>
#ifdef USE_QRCODE
#include "qrcodedialog.h"
#endif
AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
QDialog(parent),
ui(new Ui::AddressBookPage),
model(0),
optionsModel(0),
mode(mode),
tab(tab)
{
ui->setupUi(this);
#ifdef Q_WS_MAC // Icons on push buttons are very uncommon on Mac
ui->newAddressButton->setIcon(QIcon());
ui->copyToClipboard->setIcon(QIcon());
ui->deleteButton->setIcon(QIcon());
#endif
#ifndef USE_QRCODE
ui->showQRCode->setVisible(false);
#endif
switch(mode)
{
case ForSending:
connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->tableView->setFocus();
break;
case ForEditing:
ui->buttonBox->setVisible(false);
break;
}
switch(tab)
{
case SendingTab:
ui->labelExplanation->setVisible(false);
ui->deleteButton->setVisible(true);
ui->signMessage->setVisible(false);
break;
case ReceivingTab:
ui->deleteButton->setVisible(false);
ui->signMessage->setVisible(true);
break;
}
// Context menu actions
QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
QAction *copyAddressAction = new QAction(ui->copyToClipboard->text(), this);
QAction *editAction = new QAction(tr("&Edit"), this);
QAction *showQRCodeAction = new QAction(ui->showQRCode->text(), this);
QAction *signMessageAction = new QAction(ui->signMessage->text(), this);
QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this);
deleteAction = new QAction(ui->deleteButton->text(), this);
// Build context menu
contextMenu = new QMenu();
contextMenu->addAction(copyAddressAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(editAction);
if(tab == SendingTab)
contextMenu->addAction(deleteAction);
contextMenu->addSeparator();
contextMenu->addAction(showQRCodeAction);
if(tab == ReceivingTab)
contextMenu->addAction(signMessageAction);
else if(tab == SendingTab)
contextMenu->addAction(verifyMessageAction);
// Connect signals for context menu actions
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked()));
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked()));
connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked()));
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked()));
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked()));
connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
// Pass through accept action from button box
connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
}
AddressBookPage::~AddressBookPage()
{
delete ui;
}
void AddressBookPage::setModel(AddressTableModel *model)
{
this->model = model;
if(!model)
return;
proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(model);
proxyModel->setDynamicSortFilter(true);
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
switch(tab)
{
case ReceivingTab:
// Receive filter
proxyModel->setFilterRole(AddressTableModel::TypeRole);
proxyModel->setFilterFixedString(AddressTableModel::Receive);
break;
case SendingTab:
// Send filter
proxyModel->setFilterRole(AddressTableModel::TypeRole);
proxyModel->setFilterFixedString(AddressTableModel::Send);
break;
}
ui->tableView->setModel(proxyModel);
ui->tableView->sortByColumn(0, Qt::AscendingOrder);
// Set column widths
ui->tableView->horizontalHeader()->resizeSection(
AddressTableModel::Address, 320);
ui->tableView->horizontalHeader()->setResizeMode(
AddressTableModel::Label, QHeaderView::Stretch);
connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(selectionChanged()));
// Select row for newly created address
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(selectNewAddress(QModelIndex,int,int)));
selectionChanged();
}
void AddressBookPage::setOptionsModel(OptionsModel *optionsModel)
{
this->optionsModel = optionsModel;
}
void AddressBookPage::on_copyToClipboard_clicked()
{
GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
}
void AddressBookPage::onCopyLabelAction()
{
GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
}
void AddressBookPage::onEditAction()
{
if(!ui->tableView->selectionModel())
return;
QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
if(indexes.isEmpty())
return;
EditAddressDialog dlg(
tab == SendingTab ?
EditAddressDialog::EditSendingAddress :
EditAddressDialog::EditReceivingAddress);
dlg.setModel(model);
QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
dlg.loadRow(origIndex.row());
dlg.exec();
}
void AddressBookPage::on_signMessage_clicked()
{
QTableView *table = ui->tableView;
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
QString addr;
foreach (QModelIndex index, indexes)
{
QVariant address = index.data();
addr = address.toString();
}
emit signMessage(addr);
}
void AddressBookPage::on_verifyMessage_clicked()
{
QTableView *table = ui->tableView;
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
QString addr;
foreach (QModelIndex index, indexes)
{
QVariant address = index.data();
addr = address.toString();
}
emit verifyMessage(addr);
}
void AddressBookPage::on_newAddressButton_clicked()
{
if(!model)
return;
EditAddressDialog dlg(
tab == SendingTab ?
EditAddressDialog::NewSendingAddress :
EditAddressDialog::NewReceivingAddress, this);
dlg.setModel(model);
if(dlg.exec())
{
newAddressToSelect = dlg.getAddress();
}
}
void AddressBookPage::on_deleteButton_clicked()
{
QTableView *table = ui->tableView;
if(!table->selectionModel())
return;
QModelIndexList indexes = table->selectionModel()->selectedRows();
if(!indexes.isEmpty())
{
table->model()->removeRow(indexes.at(0).row());
}
}
void AddressBookPage::selectionChanged()
{
// Set button states based on selected tab and selection
QTableView *table = ui->tableView;
if(!table->selectionModel())
return;
if(table->selectionModel()->hasSelection())
{
switch(tab)
{
case SendingTab:
// In sending tab, allow deletion of selection
ui->deleteButton->setEnabled(true);
ui->deleteButton->setVisible(true);
deleteAction->setEnabled(true);
ui->signMessage->setEnabled(false);
ui->signMessage->setVisible(false);
ui->verifyMessage->setEnabled(true);
ui->verifyMessage->setVisible(true);
break;
case ReceivingTab:
// Deleting receiving addresses, however, is not allowed
ui->deleteButton->setEnabled(false);
ui->deleteButton->setVisible(false);
deleteAction->setEnabled(false);
ui->signMessage->setEnabled(true);
ui->signMessage->setVisible(true);
ui->verifyMessage->setEnabled(false);
ui->verifyMessage->setVisible(false);
break;
}
ui->copyToClipboard->setEnabled(true);
ui->showQRCode->setEnabled(true);
}
else
{
ui->deleteButton->setEnabled(false);
ui->showQRCode->setEnabled(false);
ui->copyToClipboard->setEnabled(false);
ui->signMessage->setEnabled(false);
ui->verifyMessage->setEnabled(false);
}
}
void AddressBookPage::done(int retval)
{
QTableView *table = ui->tableView;
if(!table->selectionModel() || !table->model())
return;
// When this is a tab/widget and not a model dialog, ignore "done"
if(mode == ForEditing)
return;
// Figure out which address was selected, and return it
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
foreach (QModelIndex index, indexes)
{
QVariant address = table->model()->data(index);
returnValue = address.toString();
}
if(returnValue.isEmpty())
{
// If no address entry selected, return rejected
retval = Rejected;
}
QDialog::done(retval);
}
void AddressBookPage::exportClicked()
{
// CSV is currently the only supported format
QString filename = GUIUtil::getSaveFileName(
this,
tr("Export Address Book Data"), QString(),
tr("Comma separated file (*.csv)"));
if (filename.isNull()) return;
CSVModelWriter writer(filename);
// name, column, role
writer.setModel(proxyModel);
writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
if(!writer.write())
{
QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
QMessageBox::Abort, QMessageBox::Abort);
}
}
void AddressBookPage::on_showQRCode_clicked()
{
#ifdef USE_QRCODE
QTableView *table = ui->tableView;
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
foreach (QModelIndex index, indexes)
{
QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString();
QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this);
if(optionsModel)
dialog->setModel(optionsModel);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
}
#endif
}
void AddressBookPage::contextualMenu(const QPoint &point)
{
QModelIndex index = ui->tableView->indexAt(point);
if(index.isValid())
{
contextMenu->exec(QCursor::pos());
}
}
void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int end)
{
QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
{
// Select row of newly created address, once
ui->tableView->setFocus();
ui->tableView->selectRow(idx.row());
newAddressToSelect.clear();
}
}

85
src/qt/addressbookpage.h Normal file
View File

@@ -0,0 +1,85 @@
#ifndef ADDRESSBOOKPAGE_H
#define ADDRESSBOOKPAGE_H
#include <QDialog>
namespace Ui {
class AddressBookPage;
}
class AddressTableModel;
class OptionsModel;
QT_BEGIN_NAMESPACE
class QTableView;
class QItemSelection;
class QSortFilterProxyModel;
class QMenu;
class QModelIndex;
QT_END_NAMESPACE
/** Widget that shows a list of sending or receiving addresses.
*/
class AddressBookPage : public QDialog
{
Q_OBJECT
public:
enum Tabs {
SendingTab = 0,
ReceivingTab = 1
};
enum Mode {
ForSending, /**< Open address book to pick address for sending */
ForEditing /**< Open address book for editing */
};
explicit AddressBookPage(Mode mode, Tabs tab, QWidget *parent = 0);
~AddressBookPage();
void setModel(AddressTableModel *model);
void setOptionsModel(OptionsModel *optionsModel);
const QString &getReturnValue() const { return returnValue; }
public slots:
void done(int retval);
void exportClicked();
private:
Ui::AddressBookPage *ui;
AddressTableModel *model;
OptionsModel *optionsModel;
Mode mode;
Tabs tab;
QString returnValue;
QSortFilterProxyModel *proxyModel;
QMenu *contextMenu;
QAction *deleteAction;
QString newAddressToSelect;
private slots:
void on_deleteButton_clicked();
void on_newAddressButton_clicked();
/** Copy address of currently selected address entry to clipboard */
void on_copyToClipboard_clicked();
void on_signMessage_clicked();
void on_verifyMessage_clicked();
void selectionChanged();
void on_showQRCode_clicked();
/** Spawn contextual menu (right mouse menu) for address book entry */
void contextualMenu(const QPoint &point);
/** Copy label of currently selected address entry to clipboard */
void onCopyLabelAction();
/** Edit currently selected address entry */
void onEditAction();
/** New entry/entries were added to address table */
void selectNewAddress(const QModelIndex &parent, int begin, int end);
signals:
void signMessage(QString addr);
void verifyMessage(QString addr);
};
#endif // ADDRESSBOOKDIALOG_H

View File

@@ -0,0 +1,406 @@
#include "addresstablemodel.h"
#include "guiutil.h"
#include "walletmodel.h"
#include "wallet.h"
#include "base58.h"
#include <QFont>
#include <QColor>
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) {}
};
struct AddressTableEntryLessThan
{
bool operator()(const AddressTableEntry &a, const AddressTableEntry &b) const
{
return a.address < b.address;
}
bool operator()(const AddressTableEntry &a, const QString &b) const
{
return a.address < b;
}
bool operator()(const QString &a, const AddressTableEntry &b) const
{
return a < b.address;
}
};
// Private implementation
class AddressTablePriv
{
public:
CWallet *wallet;
QList<AddressTableEntry> cachedAddressTable;
AddressTableModel *parent;
AddressTablePriv(CWallet *wallet, AddressTableModel *parent):
wallet(wallet), parent(parent) {}
void refreshAddressTable()
{
cachedAddressTable.clear();
{
LOCK(wallet->cs_wallet);
BOOST_FOREACH(const PAIRTYPE(CTxDestination, std::string)& item, wallet->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
const std::string& strName = item.second;
bool fMine = IsMine(*wallet, address.Get());
cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending,
QString::fromStdString(strName),
QString::fromStdString(address.ToString())));
}
}
}
void updateEntry(const QString &address, const QString &label, bool isMine, int status)
{
// Find address / label in model
QList<AddressTableEntry>::iterator lower = qLowerBound(
cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan());
QList<AddressTableEntry>::iterator upper = qUpperBound(
cachedAddressTable.begin(), cachedAddressTable.end(), address, AddressTableEntryLessThan());
int lowerIndex = (lower - cachedAddressTable.begin());
int upperIndex = (upper - cachedAddressTable.begin());
bool inModel = (lower != upper);
AddressTableEntry::Type newEntryType = isMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending;
switch(status)
{
case CT_NEW:
if(inModel)
{
OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_NOW, but entry is already in model\n");
break;
}
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex);
cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address));
parent->endInsertRows();
break;
case CT_UPDATED:
if(!inModel)
{
OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_UPDATED, but entry is not in model\n");
break;
}
lower->type = newEntryType;
lower->label = label;
parent->emitDataChanged(lowerIndex);
break;
case CT_DELETED:
if(!inModel)
{
OutputDebugStringF("Warning: AddressTablePriv::updateEntry: Got CT_DELETED, but entry is not in model\n");
break;
}
parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
cachedAddressTable.erase(lower, upper);
parent->endRemoveRows();
break;
}
}
int size()
{
return cachedAddressTable.size();
}
AddressTableEntry *index(int idx)
{
if(idx >= 0 && idx < cachedAddressTable.size())
{
return &cachedAddressTable[idx];
}
else
{
return 0;
}
}
};
AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) :
QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0)
{
columns << tr("Label") << tr("Address");
priv = new AddressTablePriv(wallet, this);
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:
if(rec->label.isEmpty() && role == Qt::DisplayRole)
{
return tr("(no label)");
}
else
{
return rec->label;
}
case Address:
return rec->address;
}
}
else if (role == Qt::FontRole)
{
QFont font;
if(index.column() == Address)
{
font = GUIUtil::bitcoinAddressFont();
}
return font;
}
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());
editStatus = OK;
if(role == Qt::EditRole)
{
switch(index.column())
{
case Label:
wallet->SetAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get(), value.toString().toStdString());
rec->label = value.toString();
break;
case Address:
// Refuse to set invalid address, set error status and return false
if(!walletModel->validateAddress(value.toString()))
{
editStatus = INVALID_ADDRESS;
return false;
}
// Double-check that we're not overwriting a receiving address
if(rec->type == AddressTableEntry::Sending)
{
{
LOCK(wallet->cs_wallet);
// Remove old entry
wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get());
// Add new entry with new address
wallet->SetAddressBookName(CBitcoinAddress(value.toString().toStdString()).Get(), rec->label.toStdString());
}
}
break;
}
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();
}
Qt::ItemFlags AddressTableModel::flags(const QModelIndex & index) const
{
if(!index.isValid())
return 0;
AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
// Can edit address and label for sending addresses,
// and only label for receiving addresses.
if(rec->type == AddressTableEntry::Sending ||
(rec->type == AddressTableEntry::Receiving && index.column()==Label))
{
retval |= Qt::ItemIsEditable;
}
return retval;
}
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::updateEntry(const QString &address, const QString &label, bool isMine, int status)
{
// Update address book model from Bitcoin core
priv->updateEntry(address, label, isMine, status);
}
QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address)
{
std::string strLabel = label.toStdString();
std::string strAddress = address.toStdString();
editStatus = OK;
if(type == Send)
{
if(!walletModel->validateAddress(address))
{
editStatus = INVALID_ADDRESS;
return QString();
}
// Check for duplicate addresses
{
LOCK(wallet->cs_wallet);
if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get()))
{
editStatus = DUPLICATE_ADDRESS;
return QString();
}
}
}
else if(type == Receive)
{
// Generate a new address to associate with given label
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
if(!ctx.isValid())
{
// Unlock wallet failed or was cancelled
editStatus = WALLET_UNLOCK_FAILURE;
return QString();
}
CPubKey newKey;
if(!wallet->GetKeyFromPool(newKey, true))
{
editStatus = KEY_GENERATION_FAILURE;
return QString();
}
strAddress = CBitcoinAddress(newKey.GetID()).ToString();
}
else
{
return QString();
}
// Add entry
{
LOCK(wallet->cs_wallet);
wallet->SetAddressBookName(CBitcoinAddress(strAddress).Get(), strLabel);
}
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;
}
{
LOCK(wallet->cs_wallet);
wallet->DelAddressBookName(CBitcoinAddress(rec->address.toStdString()).Get());
}
return true;
}
/* Look up label for address in address book, if not found return empty string.
*/
QString AddressTableModel::labelForAddress(const QString &address) const
{
{
LOCK(wallet->cs_wallet);
CBitcoinAddress address_parsed(address.toStdString());
std::map<CTxDestination, std::string>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get());
if (mi != wallet->mapAddressBook.end())
{
return QString::fromStdString(mi->second);
}
}
return QString();
}
int AddressTableModel::lookupAddress(const QString &address) const
{
QModelIndexList lst = match(index(0, Address, QModelIndex()),
Qt::EditRole, address, 1, Qt::MatchExactly);
if(lst.isEmpty())
{
return -1;
}
else
{
return lst.at(0).row();
}
}
void AddressTableModel::emitDataChanged(int idx)
{
emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
}

View File

@@ -0,0 +1,91 @@
#ifndef ADDRESSTABLEMODEL_H
#define ADDRESSTABLEMODEL_H
#include <QAbstractTableModel>
#include <QStringList>
class AddressTablePriv;
class CWallet;
class WalletModel;
/**
Qt model of the address book in the core. This allows views to access and modify the address book.
*/
class AddressTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit AddressTableModel(CWallet *wallet, WalletModel *parent = 0);
~AddressTableModel();
enum ColumnIndex {
Label = 0, /**< User specified label */
Address = 1 /**< Bitcoin address */
};
enum RoleIndex {
TypeRole = Qt::UserRole /**< Type of address (#Send or #Receive) */
};
/** Return status of edit/insert operation */
enum EditStatus {
OK,
INVALID_ADDRESS, /**< Unparseable address */
DUPLICATE_ADDRESS, /**< Address already in address book */
WALLET_UNLOCK_FAILURE, /**< Wallet could not be unlocked to create new receiving address */
KEY_GENERATION_FAILURE /**< Generating a new public key for a receiving address failed */
};
static const QString Send; /**< Specifies send address */
static const QString Receive; /**< Specifies receive address */
/** @name Methods overridden 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());
Qt::ItemFlags flags(const QModelIndex & index) const;
/*@}*/
/* 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);
/* Look up label for address in address book, if not found return empty string.
*/
QString labelForAddress(const QString &address) const;
/* Look up row index of an address in the model.
Return -1 if not found.
*/
int lookupAddress(const QString &address) const;
EditStatus getEditStatus() const { return editStatus; }
private:
WalletModel *walletModel;
CWallet *wallet;
AddressTablePriv *priv;
QStringList columns;
EditStatus editStatus;
/** Notify listeners that data changed. */
void emitDataChanged(int index);
signals:
void defaultAddressChanged(const QString &address);
public slots:
/* Update address list from core.
*/
void updateEntry(const QString &address, const QString &label, bool isMine, int status);
friend class AddressTablePriv;
};
#endif // ADDRESSTABLEMODEL_H

View File

@@ -0,0 +1,239 @@
#include "askpassphrasedialog.h"
#include "ui_askpassphrasedialog.h"
#include "guiconstants.h"
#include "walletmodel.h"
#include <QMessageBox>
#include <QPushButton>
#include <QKeyEvent>
AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
QDialog(parent),
ui(new Ui::AskPassphraseDialog),
mode(mode),
model(0),
fCapsLock(false)
{
ui->setupUi(this);
ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
// Setup Caps Lock detection.
ui->passEdit1->installEventFilter(this);
ui->passEdit2->installEventFilter(this);
ui->passEdit3->installEventFilter(this);
switch(mode)
{
case Encrypt: // Ask passphrase x2
ui->passLabel1->hide();
ui->passEdit1->hide();
ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>."));
setWindowTitle(tr("Encrypt wallet"));
break;
case Unlock: // Ask passphrase
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
ui->passLabel2->hide();
ui->passEdit2->hide();
ui->passLabel3->hide();
ui->passEdit3->hide();
setWindowTitle(tr("Unlock wallet"));
break;
case Decrypt: // Ask passphrase
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
ui->passLabel2->hide();
ui->passEdit2->hide();
ui->passLabel3->hide();
ui->passEdit3->hide();
setWindowTitle(tr("Decrypt wallet"));
break;
case ChangePass: // Ask old passphrase + new passphrase x2
setWindowTitle(tr("Change passphrase"));
ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
break;
}
textChanged();
connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
}
AskPassphraseDialog::~AskPassphraseDialog()
{
// Attempt to overwrite text so that they do not linger around in memory
ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
delete ui;
}
void AskPassphraseDialog::setModel(WalletModel *model)
{
this->model = model;
}
void AskPassphraseDialog::accept()
{
SecureString oldpass, newpass1, newpass2;
if(!model)
return;
oldpass.reserve(MAX_PASSPHRASE_SIZE);
newpass1.reserve(MAX_PASSPHRASE_SIZE);
newpass2.reserve(MAX_PASSPHRASE_SIZE);
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
// Alternately, find a way to make this input mlock()'d to begin with.
oldpass.assign(ui->passEdit1->text().toStdString().c_str());
newpass1.assign(ui->passEdit2->text().toStdString().c_str());
newpass2.assign(ui->passEdit3->text().toStdString().c_str());
switch(mode)
{
case Encrypt: {
if(newpass1.empty() || newpass2.empty())
{
// Cannot encrypt with empty passphrase
break;
}
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
tr("WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR CASINOCOINS</b>!\nAre you sure you wish to encrypt your wallet?"),
QMessageBox::Yes|QMessageBox::Cancel,
QMessageBox::Cancel);
if(retval == QMessageBox::Yes)
{
if(newpass1 == newpass2)
{
if(model->setWalletEncrypted(true, newpass1))
{
QMessageBox::warning(this, tr("Wallet encrypted"),
tr("CasinoCoin will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your casinocoins from being stolen by malware infecting your computer."));
QApplication::quit();
}
else
{
QMessageBox::critical(this, tr("Wallet encryption failed"),
tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
}
QDialog::accept(); // Success
}
else
{
QMessageBox::critical(this, tr("Wallet encryption failed"),
tr("The supplied passphrases do not match."));
}
}
else
{
QDialog::reject(); // Cancelled
}
} break;
case Unlock:
if(!model->setWalletLocked(false, oldpass))
{
QMessageBox::critical(this, tr("Wallet unlock failed"),
tr("The passphrase entered for the wallet decryption was incorrect."));
}
else
{
QDialog::accept(); // Success
}
break;
case Decrypt:
if(!model->setWalletEncrypted(false, oldpass))
{
QMessageBox::critical(this, tr("Wallet decryption failed"),
tr("The passphrase entered for the wallet decryption was incorrect."));
}
else
{
QDialog::accept(); // Success
}
break;
case ChangePass:
if(newpass1 == newpass2)
{
if(model->changePassphrase(oldpass, newpass1))
{
QMessageBox::information(this, tr("Wallet encrypted"),
tr("Wallet passphrase was successfully changed."));
QDialog::accept(); // Success
}
else
{
QMessageBox::critical(this, tr("Wallet encryption failed"),
tr("The passphrase entered for the wallet decryption was incorrect."));
}
}
else
{
QMessageBox::critical(this, tr("Wallet encryption failed"),
tr("The supplied passphrases do not match."));
}
break;
}
}
void AskPassphraseDialog::textChanged()
{
// Validate input, set Ok button to enabled when accepable
bool acceptable = false;
switch(mode)
{
case Encrypt: // New passphrase x2
acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
break;
case Unlock: // Old passphrase x1
case Decrypt:
acceptable = !ui->passEdit1->text().isEmpty();
break;
case ChangePass: // Old passphrase x1, new passphrase x2
acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
break;
}
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
}
bool AskPassphraseDialog::event(QEvent *event)
{
// Detect Caps Lock key press.
if (event->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_CapsLock) {
fCapsLock = !fCapsLock;
}
if (fCapsLock) {
ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
} else {
ui->capsLabel->clear();
}
}
return QWidget::event(event);
}
bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event)
{
/* Detect Caps Lock.
* There is no good OS-independent way to check a key state in Qt, but we
* can detect Caps Lock by checking for the following condition:
* Shift key is down and the result is a lower case character, or
* Shift key is not down and the result is an upper case character.
*/
if (event->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
QString str = ke->text();
if (str.length() != 0) {
const QChar *psz = str.unicode();
bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) {
fCapsLock = true;
ui->capsLabel->setText(tr("Warning: The Caps Lock key is on."));
} else if (psz->isLetter()) {
fCapsLock = false;
ui->capsLabel->clear();
}
}
}
return false;
}

View File

@@ -0,0 +1,45 @@
#ifndef ASKPASSPHRASEDIALOG_H
#define ASKPASSPHRASEDIALOG_H
#include <QDialog>
namespace Ui {
class AskPassphraseDialog;
}
class WalletModel;
/** Multifunctional dialog to ask for passphrases. Used for encryption, unlocking, and changing the passphrase.
*/
class AskPassphraseDialog : public QDialog
{
Q_OBJECT
public:
enum Mode {
Encrypt, /**< Ask passphrase twice and encrypt */
Unlock, /**< Ask passphrase and unlock */
ChangePass, /**< Ask old passphrase + new passphrase twice */
Decrypt /**< Ask passphrase and decrypt wallet */
};
explicit AskPassphraseDialog(Mode mode, QWidget *parent = 0);
~AskPassphraseDialog();
void accept();
void setModel(WalletModel *model);
private:
Ui::AskPassphraseDialog *ui;
Mode mode;
WalletModel *model;
bool fCapsLock;
private slots:
void textChanged();
bool event(QEvent *event);
bool eventFilter(QObject *, QEvent *event);
};
#endif // ASKPASSPHRASEDIALOG_H

316
src/qt/bitcoin.cpp Normal file
View File

@@ -0,0 +1,316 @@
/*
* W.J. van der Laan 2011-2012
*/
#include "bitcoingui.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "guiutil.h"
#include "guiconstants.h"
#include "init.h"
#include "ui_interface.h"
#include "qtipcserver.h"
#include <QApplication>
#include <QMessageBox>
#include <QTextCodec>
#include <QLocale>
#include <QTranslator>
#include <QSplashScreen>
#include <QLibraryInfo>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/algorithm/string/predicate.hpp>
#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
#define _BITCOIN_QT_PLUGINS_INCLUDED
#define __INSURE__
#include <QtPlugin>
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#endif
// Need a global reference for the notifications to find the GUI
static BitcoinGUI *guiref;
static QSplashScreen *splashref;
static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
{
// Message from network thread
if(guiref)
{
bool modal = (style & CClientUIInterface::MODAL);
// in case of modal message, use blocking connection to wait for user to click OK
QMetaObject::invokeMethod(guiref, "error",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(bool, modal));
}
else
{
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
}
}
static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
{
if(!guiref)
return false;
if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
return true;
bool payFee = false;
QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(),
Q_ARG(qint64, nFeeRequired),
Q_ARG(bool*, &payFee));
return payFee;
}
static void ThreadSafeHandleURI(const std::string& strURI)
{
if(!guiref)
return;
QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(),
Q_ARG(QString, QString::fromStdString(strURI)));
}
static void InitMessage(const std::string &message)
{
if(splashref)
{
splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(255,255,200));
QApplication::instance()->processEvents();
}
}
static void QueueShutdown()
{
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
}
/*
Translate string to current locale using Qt.
*/
static std::string Translate(const char* psz)
{
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
}
/* Handle runaway exceptions. Shows a message box with the problem and quits the program.
*/
static void handleRunawayException(std::exception *e)
{
PrintExceptionContinue(e, "Runaway exception");
QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occured. CasinoCoin can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning));
exit(1);
}
#ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[])
{
// TODO: implement URI support on the Mac.
#if !defined(MAC_OSX)
// Do this early as we don't want to bother initializing if we are just calling IPC
for (int i = 1; i < argc; i++)
{
if (boost::algorithm::istarts_with(argv[i], "casinocoin:"))
{
const char *strURI = argv[i];
try {
boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME);
if (mq.try_send(strURI, strlen(strURI), 0))
// if URI could be sent to the message queue exit here
exit(0);
else
// if URI could not be sent to the message queue do a normal Bitcoin-Qt startup
break;
}
catch (boost::interprocess::interprocess_exception &ex) {
// don't log the "file not found" exception, because that's normal for
// the first start of the first instance
if (ex.get_error_code() != boost::interprocess::not_found_error)
{
printf("main() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what());
break;
}
}
}
}
#endif
// Internal string conversion is all UTF-8
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
Q_INIT_RESOURCE(bitcoin);
QApplication app(argc, argv);
// Install global event filter that makes sure that long tooltips can be word-wrapped
app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
// Command-line options take precedence:
ParseParameters(argc, argv);
// ... then bitcoin.conf:
if (!boost::filesystem::is_directory(GetDataDir(false)))
{
fprintf(stderr, "Error: Specified directory does not exist\n");
return 1;
}
ReadConfigFile(mapArgs, mapMultiArgs);
// Application identification (must be set before OptionsModel is initialized,
// as it is used to locate QSettings)
app.setOrganizationName("CasinoCoin");
app.setOrganizationDomain("casinocoin.org");
if(GetBoolArg("-testnet")) // Separate UI settings for testnet
app.setApplicationName("CasinoCoin-Qt-testnet");
else
app.setApplicationName("CasinoCoin-Qt");
// ... then GUI settings:
OptionsModel optionsModel;
// Get desired locale (e.g. "de_DE") from command line or use system locale
QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString()));
QString lang = lang_territory;
// Convert to "de" only by truncating "_DE"
lang.truncate(lang_territory.lastIndexOf('_'));
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
// Load language files for configured locale:
// - First load the translator for the base language, without territory
// - Then load the more specific locale translator
// Load e.g. qt_de.qm
if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
app.installTranslator(&qtTranslatorBase);
// Load e.g. qt_de_DE.qm
if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
app.installTranslator(&qtTranslator);
// Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
if (translatorBase.load(lang, ":/translations/"))
app.installTranslator(&translatorBase);
// Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
if (translator.load(lang_territory, ":/translations/"))
app.installTranslator(&translator);
// Subscribe to global signals from core
uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee);
uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI);
uiInterface.InitMessage.connect(InitMessage);
uiInterface.QueueShutdown.connect(QueueShutdown);
uiInterface.Translate.connect(Translate);
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen.
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
GUIUtil::HelpMessageBox help;
help.showOrPrint();
return 1;
}
QSplashScreen splash(QPixmap(":/images/splash"), 0);
if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
{
splash.show();
splash.setAutoFillBackground(true);
splashref = &splash;
}
app.processEvents();
app.setQuitOnLastWindowClosed(false);
try
{
// Regenerate startup link, to fix links to old versions
if (GUIUtil::GetStartOnSystemStartup())
GUIUtil::SetStartOnSystemStartup(true);
BitcoinGUI window;
guiref = &window;
if(AppInit2())
{
{
// Put this in a block, so that the Model objects are cleaned up before
// calling Shutdown().
optionsModel.Upgrade(); // Must be done after AppInit2
if (splashref)
splash.finish(&window);
ClientModel clientModel(&optionsModel);
WalletModel walletModel(pwalletMain, &optionsModel);
window.setClientModel(&clientModel);
window.setWalletModel(&walletModel);
// If -min option passed, start window minimized.
if(GetBoolArg("-min"))
{
window.showMinimized();
}
else
{
window.show();
}
// TODO: implement URI support on the Mac.
#if !defined(MAC_OSX)
// Place this here as guiref has to be defined if we dont want to lose URIs
ipcInit();
// Check for URI in argv
for (int i = 1; i < argc; i++)
{
if (boost::algorithm::istarts_with(argv[i], "casinocoin:"))
{
const char *strURI = argv[i];
try {
boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME);
mq.try_send(strURI, strlen(strURI), 0);
}
catch (boost::interprocess::interprocess_exception &ex) {
printf("main() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what());
break;
}
}
}
#endif
app.exec();
window.hide();
window.setClientModel(0);
window.setWalletModel(0);
guiref = 0;
}
// Shutdown the core and it's threads, but don't exit Bitcoin-Qt here
Shutdown(NULL);
}
else
{
return 1;
}
} catch (std::exception& e) {
handleRunawayException(&e);
} catch (...) {
handleRunawayException(NULL);
}
return 0;
}
#endif // BITCOIN_QT_TEST

89
src/qt/bitcoin.qrc Normal file
View File

@@ -0,0 +1,89 @@
<RCC>
<qresource prefix="/icons">
<file alias="bitcoin">res/icons/bitcoin.png</file>
<file alias="address-book">res/icons/address-book.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>
<file alias="connect_0">res/icons/connect0_16.png</file>
<file alias="connect_1">res/icons/connect1_16.png</file>
<file alias="connect_2">res/icons/connect2_16.png</file>
<file alias="connect_3">res/icons/connect3_16.png</file>
<file alias="connect_4">res/icons/connect4_16.png</file>
<file alias="transaction_0">res/icons/transaction0.png</file>
<file alias="transaction_confirmed">res/icons/transaction2.png</file>
<file alias="transaction_1">res/icons/clock1.png</file>
<file alias="transaction_2">res/icons/clock2.png</file>
<file alias="transaction_3">res/icons/clock3.png</file>
<file alias="transaction_4">res/icons/clock4.png</file>
<file alias="transaction_5">res/icons/clock5.png</file>
<file alias="options">res/icons/configure.png</file>
<file alias="receiving_addresses">res/icons/receive.png</file>
<file alias="editpaste">res/icons/editpaste.png</file>
<file alias="editcopy">res/icons/editcopy.png</file>
<file alias="add">res/icons/add.png</file>
<file alias="bitcoin_testnet">res/icons/bitcoin_testnet.png</file>
<file alias="toolbar_testnet">res/icons/toolbar_testnet.png</file>
<file alias="edit">res/icons/edit.png</file>
<file alias="history">res/icons/history.png</file>
<file alias="overview">res/icons/overview.png</file>
<file alias="export">res/icons/export.png</file>
<file alias="synced">res/icons/synced.png</file>
<file alias="remove">res/icons/remove.png</file>
<file alias="tx_input">res/icons/tx_input.png</file>
<file alias="tx_output">res/icons/tx_output.png</file>
<file alias="tx_inout">res/icons/tx_inout.png</file>
<file alias="tx_mined">res/icons/tx_mined.png</file>
<file alias="lock_closed">res/icons/lock_closed.png</file>
<file alias="lock_open">res/icons/lock_open.png</file>
<file alias="key">res/icons/key.png</file>
<file alias="filesave">res/icons/filesave.png</file>
<file alias="qrcode">res/icons/qrcode.png</file>
<file alias="debugwindow">res/icons/debugwindow.png</file>
</qresource>
<qresource prefix="/images">
<file alias="about">res/images/about.png</file>
<file alias="splash">res/images/splash2.jpg</file>
<file alias="backg">res/images/wallet.png</file>
</qresource>
<qresource prefix="/movies">
<file alias="update_spinner">res/movies/update_spinner.mng</file>
</qresource>
<qresource prefix="/translations">
<file alias="bg">locale/bitcoin_bg.qm</file>
<file alias="ca_ES">locale/bitcoin_ca_ES.qm</file>
<file alias="cs">locale/bitcoin_cs.qm</file>
<file alias="da">locale/bitcoin_da.qm</file>
<file alias="de">locale/bitcoin_de.qm</file>
<file alias="el_GR">locale/bitcoin_el_GR.qm</file>
<file alias="en">locale/bitcoin_en.qm</file>
<file alias="es">locale/bitcoin_es.qm</file>
<file alias="es_CL">locale/bitcoin_es_CL.qm</file>
<file alias="et">locale/bitcoin_et.qm</file>
<file alias="eu_ES">locale/bitcoin_eu_ES.qm</file>
<file alias="fa">locale/bitcoin_fa.qm</file>
<file alias="fa_IR">locale/bitcoin_fa_IR.qm</file>
<file alias="fi">locale/bitcoin_fi.qm</file>
<file alias="fr">locale/bitcoin_fr.qm</file>
<file alias="fr_CA">locale/bitcoin_fr_CA.qm</file>
<file alias="he">locale/bitcoin_he.qm</file>
<file alias="hr">locale/bitcoin_hr.qm</file>
<file alias="hu">locale/bitcoin_hu.qm</file>
<file alias="it">locale/bitcoin_it.qm</file>
<file alias="lt">locale/bitcoin_lt.qm</file>
<file alias="nb">locale/bitcoin_nb.qm</file>
<file alias="nl">locale/bitcoin_nl.qm</file>
<file alias="pl">locale/bitcoin_pl.qm</file>
<file alias="pt_BR">locale/bitcoin_pt_BR.qm</file>
<file alias="pt_PT">locale/bitcoin_pt_PT.qm</file>
<file alias="ro_RO">locale/bitcoin_ro_RO.qm</file>
<file alias="ru">locale/bitcoin_ru.qm</file>
<file alias="sk">locale/bitcoin_sk.qm</file>
<file alias="sr">locale/bitcoin_sr.qm</file>
<file alias="sv">locale/bitcoin_sv.qm</file>
<file alias="tr">locale/bitcoin_tr.qm</file>
<file alias="uk">locale/bitcoin_uk.qm</file>
<file alias="zh_CN">locale/bitcoin_zh_CN.qm</file>
<file alias="zh_TW">locale/bitcoin_zh_TW.qm</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,77 @@
#include "bitcoinaddressvalidator.h"
/* 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();)
{
bool removeChar = false;
QChar ch = input.at(idx);
// Corrections made are very conservative on purpose, to avoid
// users unexpectedly getting away with typos that would normally
// be detected, and thus sending to the wrong address.
switch(ch.unicode())
{
// Qt categorizes these as "Other_Format" not "Separator_Space"
case 0x200B: // ZERO WIDTH SPACE
case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
removeChar = true;
break;
default:
break;
}
// Remove whitespace
if(ch.isSpace())
removeChar = true;
// To next character
if(removeChar)
input.remove(idx, 1);
else
++idx;
}
// 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;
}
}
// Empty address is "intermediate" input
if(input.isEmpty())
{
state = QValidator::Intermediate;
}
return state;
}

View 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 = 35;
signals:
public slots:
};
#endif // BITCOINADDRESSVALIDATOR_H

View File

@@ -0,0 +1,168 @@
#include "bitcoinamountfield.h"
#include "qvaluecombobox.h"
#include "bitcoinunits.h"
#include "guiconstants.h"
#include <QLabel>
#include <QLineEdit>
#include <QRegExpValidator>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QApplication>
#include <qmath.h>
BitcoinAmountField::BitcoinAmountField(QWidget *parent):
QWidget(parent), amount(0), currentUnit(-1)
{
amount = new QDoubleSpinBox(this);
amount->setLocale(QLocale::c());
amount->setDecimals(8);
amount->installEventFilter(this);
amount->setMaximumWidth(170);
amount->setSingleStep(0.001);
QHBoxLayout *layout = new QHBoxLayout(this);
layout->addWidget(amount);
unit = new QValueComboBox(this);
unit->setModel(new BitcoinUnits(this));
layout->addWidget(unit);
layout->addStretch(1);
layout->setContentsMargins(0,0,0,0);
setLayout(layout);
setFocusPolicy(Qt::TabFocus);
setFocusProxy(amount);
// If one if the widgets changes, the combined content changes as well
connect(amount, SIGNAL(valueChanged(QString)), this, SIGNAL(textChanged()));
connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
// Set default based on configuration
unitChanged(unit->currentIndex());
}
void BitcoinAmountField::setText(const QString &text)
{
if (text.isEmpty())
amount->clear();
else
amount->setValue(text.toDouble());
}
void BitcoinAmountField::clear()
{
amount->clear();
unit->setCurrentIndex(0);
}
bool BitcoinAmountField::validate()
{
bool valid = true;
if (amount->value() == 0.0)
valid = false;
if (valid && !BitcoinUnits::parse(currentUnit, text(), 0))
valid = false;
setValid(valid);
return valid;
}
void BitcoinAmountField::setValid(bool valid)
{
if (valid)
amount->setStyleSheet("");
else
amount->setStyleSheet(STYLE_INVALID);
}
QString BitcoinAmountField::text() const
{
if (amount->text().isEmpty())
return QString();
else
return amount->text();
}
bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::FocusIn)
{
// Clear invalid flag on focus
setValid(true);
}
else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Comma)
{
// Translate a comma into a period
QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count());
qApp->sendEvent(object, &periodKeyEvent);
return true;
}
}
return QWidget::eventFilter(object, event);
}
QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
{
QWidget::setTabOrder(prev, amount);
return amount;
}
qint64 BitcoinAmountField::value(bool *valid_out) const
{
qint64 val_out = 0;
bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
if(valid_out)
{
*valid_out = valid;
}
return val_out;
}
void BitcoinAmountField::setValue(qint64 value)
{
setText(BitcoinUnits::format(currentUnit, value));
}
void BitcoinAmountField::unitChanged(int idx)
{
// Use description tooltip for current unit for the combobox
unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
// Determine new unit ID
int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
// Parse current value and convert to new unit
bool valid = false;
qint64 currentValue = value(&valid);
currentUnit = newUnit;
// Set max length after retrieving the value, to prevent truncation
amount->setDecimals(BitcoinUnits::decimals(currentUnit));
amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals()));
if(valid)
{
// If value was valid, re-place it in the widget with the new unit
setValue(currentValue);
}
else
{
// If current value is invalid, just clear field
setText("");
}
setValid(true);
}
void BitcoinAmountField::setDisplayUnit(int newUnit)
{
unit->setValue(newUnit);
}

View File

@@ -0,0 +1,60 @@
#ifndef BITCOINFIELD_H
#define BITCOINFIELD_H
#include <QWidget>
QT_BEGIN_NAMESPACE
class QDoubleSpinBox;
class QValueComboBox;
QT_END_NAMESPACE
/** Widget for entering bitcoin amounts.
*/
class BitcoinAmountField: public QWidget
{
Q_OBJECT
Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY textChanged USER true)
public:
explicit BitcoinAmountField(QWidget *parent = 0);
qint64 value(bool *valid=0) const;
void setValue(qint64 value);
/** Mark current value as invalid in UI. */
void setValid(bool valid);
/** Perform input validation, mark field as invalid if entered value is not valid. */
bool validate();
/** Change unit used to display amount. */
void setDisplayUnit(int unit);
/** Make field empty and ready for new input. */
void clear();
/** Qt messes up the tab chain by default in some cases (issue http://bugreports.qt.nokia.com/browse/QTBUG-10907),
in these cases we have to set it up manually.
*/
QWidget *setupTabChain(QWidget *prev);
signals:
void textChanged();
protected:
/** Intercept focus-in event and ',' keypresses */
bool eventFilter(QObject *object, QEvent *event);
private:
QDoubleSpinBox *amount;
QValueComboBox *unit;
int currentUnit;
void setText(const QString &text);
QString text() const;
private slots:
void unitChanged(int idx);
};
#endif // BITCOINFIELD_H

919
src/qt/bitcoingui.cpp Normal file
View File

@@ -0,0 +1,919 @@
/*
* Qt4 bitcoin GUI.
*
* W.J. van der Laan 2011-2012
* The Bitcoin Developers 2011-2012
* The CasinoCoin Developers 201-2013
*/
#include "bitcoingui.h"
#include "transactiontablemodel.h"
#include "addressbookpage.h"
#include "sendcoinsdialog.h"
#include "signverifymessagedialog.h"
#include "optionsdialog.h"
#include "aboutdialog.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "editaddressdialog.h"
#include "optionsmodel.h"
#include "transactiondescdialog.h"
#include "addresstablemodel.h"
#include "transactionview.h"
#include "overviewpage.h"
#include "bitcoinunits.h"
#include "guiconstants.h"
#include "askpassphrasedialog.h"
#include "notificator.h"
#include "guiutil.h"
#include "rpcconsole.h"
#ifdef Q_WS_MAC
#include "macdockiconhandler.h"
#endif
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QIcon>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QToolBar>
#include <QStatusBar>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QLocale>
#include <QMessageBox>
#include <QProgressBar>
#include <QStackedWidget>
#include <QDateTime>
#include <QMovie>
#include <QFileDialog>
#include <QDesktopServices>
#include <QTimer>
#include <QDragEnterEvent>
#include <QUrl>
#include <iostream>
BitcoinGUI::BitcoinGUI(QWidget *parent):
QMainWindow(parent),
clientModel(0),
walletModel(0),
encryptWalletAction(0),
changePassphraseAction(0),
aboutQtAction(0),
trayIcon(0),
notificator(0),
rpcConsole(0)
{
resize(850, 550);
setWindowTitle(tr("CasinoCoin") + " - " + tr("Wallet"));
#ifndef Q_WS_MAC
qApp->setWindowIcon(QIcon(":icons/bitcoin"));
setWindowIcon(QIcon(":icons/bitcoin"));
#else
setUnifiedTitleAndToolBarOnMac(true);
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
#endif
// Accept D&D of URIs
setAcceptDrops(true);
// Create actions for the toolbar, menu bar and tray/dock icon
createActions();
// Create application menu bar
createMenuBar();
// Create the toolbars
createToolBars();
// Create the tray icon (or setup the dock icon)
createTrayIcon();
// Create tabs
overviewPage = new OverviewPage();
transactionsPage = new QWidget(this);
QVBoxLayout *vbox = new QVBoxLayout();
transactionView = new TransactionView(this);
vbox->addWidget(transactionView);
transactionsPage->setLayout(vbox);
addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab);
receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab);
sendCoinsPage = new SendCoinsDialog(this);
signVerifyMessageDialog = new SignVerifyMessageDialog(this);
centralWidget = new QStackedWidget(this);
centralWidget->addWidget(overviewPage);
centralWidget->addWidget(transactionsPage);
centralWidget->addWidget(addressBookPage);
centralWidget->addWidget(receiveCoinsPage);
centralWidget->addWidget(sendCoinsPage);
#ifdef FIRST_CLASS_MESSAGING
centralWidget->addWidget(signVerifyMessageDialog);
#endif
setCentralWidget(centralWidget);
// Create status bar
statusBar();
// Status bar notification icons
QFrame *frameBlocks = new QFrame();
frameBlocks->setContentsMargins(0,0,0,0);
frameBlocks->setMinimumWidth(73);
frameBlocks->setMaximumWidth(73);
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
labelEncryptionIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelEncryptionIcon);
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelConnectionsIcon);
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelBlocksIcon);
frameBlocksLayout->addStretch();
// Progress bar and label for blocks download
progressBarLabel = new QLabel();
progressBarLabel->setVisible(false);
progressBar = new QProgressBar();
progressBar->setAlignment(Qt::AlignCenter);
progressBar->setVisible(false);
statusBar()->addWidget(progressBarLabel);
statusBar()->addWidget(progressBar);
statusBar()->addPermanentWidget(frameBlocks);
syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this);
// Clicking on a transaction on the overview page simply sends you to transaction history page
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage()));
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex)));
// Doubleclicking on a transaction on the transaction history page shows details
connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
rpcConsole = new RPCConsole(this);
connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
// Clicking on "Verify Message" in the address book sends you to the verify message tab
connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString)));
// Clicking on "Sign Message" in the receive coins page sends you to the sign message tab
connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString)));
gotoOverviewPage();
}
BitcoinGUI::~BitcoinGUI()
{
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
trayIcon->hide();
#ifdef Q_WS_MAC
delete appMenuBar;
#endif
}
void BitcoinGUI::createActions()
{
QActionGroup *tabGroup = new QActionGroup(this);
overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
overviewAction->setToolTip(tr("Show general overview of wallet"));
overviewAction->setCheckable(true);
overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
tabGroup->addAction(overviewAction);
historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
historyAction->setToolTip(tr("Browse transaction history"));
historyAction->setCheckable(true);
historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
tabGroup->addAction(historyAction);
addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels"));
addressBookAction->setCheckable(true);
addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5));
tabGroup->addAction(addressBookAction);
receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this);
receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments"));
receiveCoinsAction->setCheckable(true);
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
sendCoinsAction->setToolTip(tr("Send coins to a CasinoCoin address"));
sendCoinsAction->setCheckable(true);
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this);
signMessageAction->setToolTip(tr("Sign a message to prove you own a Bitcoin address"));
tabGroup->addAction(signMessageAction);
verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this);
verifyMessageAction->setToolTip(tr("Verify a message to ensure it was signed with a specified Bitcoin address"));
tabGroup->addAction(verifyMessageAction);
#ifdef FIRST_CLASS_MESSAGING
firstClassMessagingAction = new QAction(QIcon(":/icons/edit"), tr("S&ignatures"), this);
firstClassMessagingAction->setToolTip(signMessageAction->toolTip() + QString(". / ") + verifyMessageAction->toolTip() + QString("."));
firstClassMessagingAction->setCheckable(true);
tabGroup->addAction(firstClassMessagingAction);
#endif
connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
#ifdef FIRST_CLASS_MESSAGING
connect(firstClassMessagingAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
// Always start with the sign message tab for FIRST_CLASS_MESSAGING
connect(firstClassMessagingAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
#endif
quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
quitAction->setToolTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About CasinoCoin"), this);
aboutAction->setToolTip(tr("Show information about CasinoCoin"));
aboutAction->setMenuRole(QAction::AboutRole);
aboutQtAction = new QAction(tr("About &Qt"), this);
aboutQtAction->setToolTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setToolTip(tr("Modify configuration options for CasinoCoin"));
optionsAction->setMenuRole(QAction::PreferencesRole);
toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("Show/Hide &CasinoCoin"), this);
toggleHideAction->setToolTip(tr("Show or hide the CasinoCoin window"));
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
exportAction->setToolTip(tr("Export the data in the current tab to a file"));
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
encryptWalletAction->setCheckable(true);
backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
backupWalletAction->setToolTip(tr("Backup wallet to another location"));
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this);
changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this);
openRPCConsoleAction->setToolTip(tr("Open debugging and diagnostic console"));
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden()));
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
}
void BitcoinGUI::createMenuBar()
{
#ifdef Q_WS_MAC
// Create a decoupled menu bar on Mac which stays even if the window is closed
appMenuBar = new QMenuBar();
#else
// Get the main window's menu bar on other platforms
appMenuBar = menuBar();
#endif
// Configure the menus
QMenu *file = appMenuBar->addMenu(tr("&File"));
file->addAction(backupWalletAction);
file->addAction(exportAction);
#ifndef FIRST_CLASS_MESSAGING
file->addAction(signMessageAction);
file->addAction(verifyMessageAction);
#endif
file->addSeparator();
file->addAction(quitAction);
QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
settings->addAction(encryptWalletAction);
settings->addAction(changePassphraseAction);
settings->addSeparator();
settings->addAction(optionsAction);
QMenu *help = appMenuBar->addMenu(tr("&Help"));
help->addAction(openRPCConsoleAction);
help->addSeparator();
help->addAction(aboutAction);
help->addAction(aboutQtAction);
}
void BitcoinGUI::createToolBars()
{
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar->addAction(overviewAction);
toolbar->addAction(sendCoinsAction);
toolbar->addAction(receiveCoinsAction);
toolbar->addAction(historyAction);
toolbar->addAction(addressBookAction);
#ifdef FIRST_CLASS_MESSAGING
toolbar->addAction(firstClassMessagingAction);
#endif
QToolBar *toolbar2 = addToolBar(tr("Actions toolbar"));
toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar2->addAction(exportAction);
}
void BitcoinGUI::setClientModel(ClientModel *clientModel)
{
this->clientModel = clientModel;
if(clientModel)
{
// Replace some strings and icons, when using the testnet
if(clientModel->isTestNet())
{
setWindowTitle(windowTitle() + QString(" ") + tr("[testnet]"));
#ifndef Q_WS_MAC
qApp->setWindowIcon(QIcon(":icons/bitcoin_testnet"));
setWindowIcon(QIcon(":icons/bitcoin_testnet"));
#else
MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
#endif
if(trayIcon)
{
trayIcon->setToolTip(tr("CasinoCoin client") + QString(" ") + tr("[testnet]"));
trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet"));
}
aboutAction->setIcon(QIcon(":/icons/toolbar_testnet"));
}
// Keep up to date with client
setNumConnections(clientModel->getNumConnections());
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers());
connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
// Report errors from network/worker thread
connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
rpcConsole->setClientModel(clientModel);
addressBookPage->setOptionsModel(clientModel->getOptionsModel());
receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel());
}
}
void BitcoinGUI::setWalletModel(WalletModel *walletModel)
{
this->walletModel = walletModel;
if(walletModel)
{
// Report errors from wallet thread
connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
// Put transaction list in tabs
transactionView->setModel(walletModel);
overviewPage->setModel(walletModel);
addressBookPage->setModel(walletModel->getAddressTableModel());
receiveCoinsPage->setModel(walletModel->getAddressTableModel());
sendCoinsPage->setModel(walletModel);
signVerifyMessageDialog->setModel(walletModel);
setEncryptionStatus(walletModel->getEncryptionStatus());
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
// Balloon popup for new transaction
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(incomingTransaction(QModelIndex,int,int)));
// Ask for passphrase if needed
connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
}
}
void BitcoinGUI::createTrayIcon()
{
QMenu *trayIconMenu;
#ifndef Q_WS_MAC
trayIcon = new QSystemTrayIcon(this);
trayIconMenu = new QMenu(this);
trayIcon->setContextMenu(trayIconMenu);
trayIcon->setToolTip(tr("CasinoCoin client"));
trayIcon->setIcon(QIcon(":/icons/toolbar"));
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
trayIcon->show();
#else
// Note: On Mac, the dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
trayIconMenu = dockIconHandler->dockMenu();
#endif
// Configuration of the tray icon (or dock icon) icon menu
trayIconMenu->addAction(toggleHideAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(sendCoinsAction);
trayIconMenu->addAction(receiveCoinsAction);
#ifndef FIRST_CLASS_MESSAGING
trayIconMenu->addSeparator();
#endif
trayIconMenu->addAction(signMessageAction);
trayIconMenu->addAction(verifyMessageAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(optionsAction);
trayIconMenu->addAction(openRPCConsoleAction);
#ifndef Q_WS_MAC // This is built-in on Mac
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
#endif
notificator = new Notificator(qApp->applicationName(), trayIcon);
}
#ifndef Q_WS_MAC
void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
{
if(reason == QSystemTrayIcon::Trigger)
{
// Click on system tray icon triggers "show/hide CasinoCoin"
toggleHideAction->trigger();
}
}
#endif
void BitcoinGUI::optionsClicked()
{
if(!clientModel || !clientModel->getOptionsModel())
return;
OptionsDialog dlg;
dlg.setModel(clientModel->getOptionsModel());
dlg.exec();
}
void BitcoinGUI::aboutClicked()
{
AboutDialog dlg;
dlg.setModel(clientModel);
dlg.exec();
}
void BitcoinGUI::setNumConnections(int count)
{
QString icon;
switch(count)
{
case 0: icon = ":/icons/connect_0"; break;
case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
default: icon = ":/icons/connect_4"; break;
}
labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to CasinoCoin network", "", count));
}
void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
{
// don't show / hide progressBar and it's label if we have no connection(s) to the network
if (!clientModel || clientModel->getNumConnections() == 0)
{
progressBarLabel->setVisible(false);
progressBar->setVisible(false);
return;
}
QString tooltip;
if(count < nTotalBlocks)
{
int nRemainingBlocks = nTotalBlocks - count;
float nPercentageDone = count / (nTotalBlocks * 0.01f);
if (clientModel->getStatusBarWarnings() == "")
{
progressBarLabel->setText(tr("Synchronizing with network..."));
progressBarLabel->setVisible(true);
progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
progressBar->setMaximum(nTotalBlocks);
progressBar->setValue(count);
progressBar->setVisible(true);
}
else
{
progressBarLabel->setText(clientModel->getStatusBarWarnings());
progressBarLabel->setVisible(true);
progressBar->setVisible(false);
}
tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
}
else
{
if (clientModel->getStatusBarWarnings() == "")
progressBarLabel->setVisible(false);
else
{
progressBarLabel->setText(clientModel->getStatusBarWarnings());
progressBarLabel->setVisible(true);
}
progressBar->setVisible(false);
tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count);
}
tooltip = tr("Current difficulty is %1.").arg(clientModel->GetDifficulty()) + QString("<br>") + tooltip;
QDateTime now = QDateTime::currentDateTime();
QDateTime lastBlockDate = clientModel->getLastBlockDate();
int secs = lastBlockDate.secsTo(now);
QString text;
// Represent time from last generated block in human readable text
if(secs <= 0)
{
// Fully up to date. Leave text empty.
}
else if(secs < 60)
{
text = tr("%n second(s) ago","",secs);
}
else if(secs < 60*60)
{
text = tr("%n minute(s) ago","",secs/60);
}
else if(secs < 24*60*60)
{
text = tr("%n hour(s) ago","",secs/(60*60));
}
else
{
text = tr("%n day(s) ago","",secs/(60*60*24));
}
// Set icon state: spinning if catching up, tick otherwise
if(secs < 90*60 && count >= nTotalBlocks)
{
tooltip = tr("Up to date") + QString(".<br>") + tooltip;
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
overviewPage->showOutOfSyncWarning(false);
}
else
{
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
labelBlocksIcon->setMovie(syncIconMovie);
syncIconMovie->start();
overviewPage->showOutOfSyncWarning(true);
}
if(!text.isEmpty())
{
tooltip += QString("<br>");
tooltip += tr("Last received block was generated %1.").arg(text);
}
// Don't word-wrap this (fixed-width) tooltip
tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
labelBlocksIcon->setToolTip(tooltip);
progressBarLabel->setToolTip(tooltip);
progressBar->setToolTip(tooltip);
}
void BitcoinGUI::error(const QString &title, const QString &message, bool modal)
{
// Report errors from network/worker thread
if(modal)
{
QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok);
} else {
notificator->notify(Notificator::Critical, title, message);
}
}
void BitcoinGUI::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
#ifndef Q_WS_MAC // Ignored on Mac
if(e->type() == QEvent::WindowStateChange)
{
if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray())
{
QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e);
if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized())
{
QTimer::singleShot(0, this, SLOT(hide()));
e->ignore();
}
}
}
#endif
}
void BitcoinGUI::closeEvent(QCloseEvent *event)
{
if(clientModel)
{
#ifndef Q_WS_MAC // Ignored on Mac
if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
!clientModel->getOptionsModel()->getMinimizeOnClose())
{
qApp->quit();
}
#endif
}
QMainWindow::closeEvent(event);
}
void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
{
QString strMessage =
tr("This transaction is over the size limit. You can still send it for a fee of %1, "
"which goes to the nodes that process your transaction and helps to support the network. "
"Do you want to pay the fee?").arg(
BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
QMessageBox::StandardButton retval = QMessageBox::question(
this, tr("Confirm transaction fee"), strMessage,
QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
*payFee = (retval == QMessageBox::Yes);
}
void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end)
{
if(!walletModel || !clientModel)
return;
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
.data(Qt::EditRole).toULongLong();
if(!clientModel->inInitialBlockDownload())
{
// On new transaction, make an info balloon
// Unless the initial block download is in progress, to prevent balloon-spam
QString date = ttm->index(start, TransactionTableModel::Date, parent)
.data().toString();
QString type = ttm->index(start, TransactionTableModel::Type, parent)
.data().toString();
QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
.data().toString();
QIcon icon = qvariant_cast<QIcon>(ttm->index(start,
TransactionTableModel::ToAddress, parent)
.data(Qt::DecorationRole));
notificator->notify(Notificator::Information,
(amount)<0 ? tr("Sent transaction") :
tr("Incoming transaction"),
tr("Date: %1\n"
"Amount: %2\n"
"Type: %3\n"
"Address: %4\n")
.arg(date)
.arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true))
.arg(type)
.arg(address), icon);
}
}
void BitcoinGUI::gotoOverviewPage()
{
overviewAction->setChecked(true);
centralWidget->setCurrentWidget(overviewPage);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
}
void BitcoinGUI::gotoHistoryPage()
{
historyAction->setChecked(true);
centralWidget->setCurrentWidget(transactionsPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked()));
}
void BitcoinGUI::gotoAddressBookPage()
{
addressBookAction->setChecked(true);
centralWidget->setCurrentWidget(addressBookPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked()));
}
void BitcoinGUI::gotoReceiveCoinsPage()
{
receiveCoinsAction->setChecked(true);
centralWidget->setCurrentWidget(receiveCoinsPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked()));
}
void BitcoinGUI::gotoSendCoinsPage()
{
sendCoinsAction->setChecked(true);
centralWidget->setCurrentWidget(sendCoinsPage);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
}
void BitcoinGUI::gotoSignMessageTab(QString addr)
{
#ifdef FIRST_CLASS_MESSAGING
firstClassMessagingAction->setChecked(true);
centralWidget->setCurrentWidget(signVerifyMessageDialog);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
signVerifyMessageDialog->showTab_SM(false);
#else
// call show() in showTab_SM()
signVerifyMessageDialog->showTab_SM(true);
#endif
if(!addr.isEmpty())
signVerifyMessageDialog->setAddress_SM(addr);
}
void BitcoinGUI::gotoVerifyMessageTab(QString addr)
{
#ifdef FIRST_CLASS_MESSAGING
firstClassMessagingAction->setChecked(true);
centralWidget->setCurrentWidget(signVerifyMessageDialog);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
signVerifyMessageDialog->showTab_VM(false);
#else
// call show() in showTab_VM()
signVerifyMessageDialog->showTab_VM(true);
#endif
if(!addr.isEmpty())
signVerifyMessageDialog->setAddress_VM(addr);
}
void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
{
// Accept only URIs
if(event->mimeData()->hasUrls())
event->acceptProposedAction();
}
void BitcoinGUI::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasUrls())
{
int nValidUrisFound = 0;
QList<QUrl> uris = event->mimeData()->urls();
foreach(const QUrl &uri, uris)
{
if (sendCoinsPage->handleURI(uri.toString()))
nValidUrisFound++;
}
// if valid URIs were found
if (nValidUrisFound)
gotoSendCoinsPage();
else
notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters."));
}
event->acceptProposedAction();
}
void BitcoinGUI::handleURI(QString strURI)
{
// URI has to be valid
if (sendCoinsPage->handleURI(strURI))
{
showNormalIfMinimized();
gotoSendCoinsPage();
}
else
notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid CasinoCoin address or malformed URI parameters."));
}
void BitcoinGUI::setEncryptionStatus(int status)
{
switch(status)
{
case WalletModel::Unencrypted:
labelEncryptionIcon->hide();
encryptWalletAction->setChecked(false);
changePassphraseAction->setEnabled(false);
encryptWalletAction->setEnabled(true);
break;
case WalletModel::Unlocked:
labelEncryptionIcon->show();
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
break;
case WalletModel::Locked:
labelEncryptionIcon->show();
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
break;
}
}
void BitcoinGUI::encryptWallet(bool status)
{
if(!walletModel)
return;
AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
AskPassphraseDialog::Decrypt, this);
dlg.setModel(walletModel);
dlg.exec();
setEncryptionStatus(walletModel->getEncryptionStatus());
}
void BitcoinGUI::backupWallet()
{
QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
if(!filename.isEmpty()) {
if(!walletModel->backupWallet(filename)) {
QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."));
}
}
}
void BitcoinGUI::changePassphrase()
{
AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
dlg.setModel(walletModel);
dlg.exec();
}
void BitcoinGUI::unlockWallet()
{
if(!walletModel)
return;
// Unlock wallet when requested by wallet model
if(walletModel->getEncryptionStatus() == WalletModel::Locked)
{
AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
dlg.setModel(walletModel);
dlg.exec();
}
}
void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
{
// activateWindow() (sometimes) helps with keyboard focus on Windows
if (isHidden())
{
show();
activateWindow();
}
else if (isMinimized())
{
showNormal();
activateWindow();
}
else if (GUIUtil::isObscured(this))
{
raise();
activateWindow();
}
else if(fToggleHidden)
hide();
}
void BitcoinGUI::toggleHidden()
{
showNormalIfMinimized(true);
}

180
src/qt/bitcoingui.h Normal file
View File

@@ -0,0 +1,180 @@
#ifndef BITCOINGUI_H
#define BITCOINGUI_H
#include <QMainWindow>
#include <QSystemTrayIcon>
class TransactionTableModel;
class ClientModel;
class WalletModel;
class TransactionView;
class OverviewPage;
class AddressBookPage;
class SendCoinsDialog;
class SignVerifyMessageDialog;
class Notificator;
class RPCConsole;
QT_BEGIN_NAMESPACE
class QLabel;
class QLineEdit;
class QTableView;
class QAbstractItemModel;
class QModelIndex;
class QProgressBar;
class QStackedWidget;
class QUrl;
QT_END_NAMESPACE
/**
Bitcoin GUI main class. This class represents the main window of the Bitcoin UI. It communicates with both the client and
wallet models to give the user an up-to-date view of the current core state.
*/
class BitcoinGUI : public QMainWindow
{
Q_OBJECT
public:
explicit BitcoinGUI(QWidget *parent = 0);
~BitcoinGUI();
/** Set the client model.
The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic.
*/
void setClientModel(ClientModel *clientModel);
/** Set the wallet model.
The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending
functionality.
*/
void setWalletModel(WalletModel *walletModel);
protected:
void changeEvent(QEvent *e);
void closeEvent(QCloseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
private:
ClientModel *clientModel;
WalletModel *walletModel;
QStackedWidget *centralWidget;
OverviewPage *overviewPage;
QWidget *transactionsPage;
AddressBookPage *addressBookPage;
AddressBookPage *receiveCoinsPage;
SendCoinsDialog *sendCoinsPage;
SignVerifyMessageDialog *signVerifyMessageDialog;
QLabel *labelEncryptionIcon;
QLabel *labelConnectionsIcon;
QLabel *labelBlocksIcon;
QLabel *progressBarLabel;
QProgressBar *progressBar;
QMenuBar *appMenuBar;
QAction *overviewAction;
QAction *historyAction;
QAction *quitAction;
QAction *sendCoinsAction;
QAction *addressBookAction;
QAction *signMessageAction;
QAction *verifyMessageAction;
QAction *firstClassMessagingAction;
QAction *aboutAction;
QAction *receiveCoinsAction;
QAction *optionsAction;
QAction *toggleHideAction;
QAction *exportAction;
QAction *encryptWalletAction;
QAction *backupWalletAction;
QAction *changePassphraseAction;
QAction *aboutQtAction;
QAction *openRPCConsoleAction;
QSystemTrayIcon *trayIcon;
Notificator *notificator;
TransactionView *transactionView;
RPCConsole *rpcConsole;
QMovie *syncIconMovie;
/** Create the main UI actions. */
void createActions();
/** Create the menu bar and submenus. */
void createMenuBar();
/** Create the toolbars */
void createToolBars();
/** Create system tray (notification) icon */
void createTrayIcon();
public slots:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks shown in the UI */
void setNumBlocks(int count, int countOfPeers);
/** Set the encryption status as shown in the UI.
@param[in] status current encryption status
@see WalletModel::EncryptionStatus
*/
void setEncryptionStatus(int status);
/** Notify the user of an error in the network or transaction handling code. */
void error(const QString &title, const QString &message, bool modal);
/** Asks the user whether to pay the transaction fee or to cancel the transaction.
It is currently not possible to pass a return value to another thread through
BlockingQueuedConnection, so an indirected pointer is used.
http://bugreports.qt.nokia.com/browse/QTBUG-10440
@param[in] nFeeRequired the required fee
@param[out] payFee true to pay the fee, false to not pay the fee
*/
void askFee(qint64 nFeeRequired, bool *payFee);
void handleURI(QString strURI);
private slots:
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
void gotoHistoryPage();
/** Switch to address book page */
void gotoAddressBookPage();
/** Switch to receive coins page */
void gotoReceiveCoinsPage();
/** Switch to send coins page */
void gotoSendCoinsPage();
/** Show Sign/Verify Message dialog and switch to sign message tab */
void gotoSignMessageTab(QString addr = "");
/** Show Sign/Verify Message dialog and switch to verify message tab */
void gotoVerifyMessageTab(QString addr = "");
/** Show configuration dialog */
void optionsClicked();
/** Show about dialog */
void aboutClicked();
#ifndef Q_WS_MAC
/** Handle tray icon clicked */
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
#endif
/** Show incoming transaction notification for new transactions.
The new items are those between start and end inclusive, under the given parent item.
*/
void incomingTransaction(const QModelIndex & parent, int start, int end);
/** Encrypt the wallet */
void encryptWallet(bool status);
/** Backup the wallet */
void backupWallet();
/** Change encrypted wallet passphrase */
void changePassphrase();
/** Ask for pass phrase to unlock wallet temporarily */
void unlockWallet();
/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */
void showNormalIfMinimized(bool fToggleHidden = false);
/** simply calls showNormalIfMinimized(true) for use in SLOT() macro */
void toggleHidden();
};
#endif

148
src/qt/bitcoinstrings.cpp Normal file
View File

@@ -0,0 +1,148 @@
#include <QtGlobal>
// Automatically generated by extract_strings.py
#ifdef __GNUC__
#define UNUSED __attribute__((unused))
#else
#define UNUSED
#endif
static const char UNUSED *bitcoin_strings[] = {
QT_TRANSLATE_NOOP("bitcoin-core", ""
"%s, you must set a rpcpassword in the configuration file:\n"
" %s\n"
"It is recommended you use the following random password:\n"
"rpcuser=casinocoinrpc\n"
"rpcpassword=%s\n"
"(you do not need to remember this password)\n"
"If the file does not exist, create it with owner-readable-only file "
"permissions.\n"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:"
"@STRENGTH)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. CasinoCoin is probably already "
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Detach block and address databases. Increases shutdown time (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: The transaction was rejected. This might happen if some of the coins "
"in your wallet were already spent, such as if you used a copy of wallet.dat "
"and coins were spent in the copy but not marked as spent here."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: This transaction requires a transaction fee of at least %s because of "
"its amount, complexity, or use of recently received funds "),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when the best block changes (%s in cmd is replaced by block "
"hash)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Number of seconds to keep misbehaving peers from reconnecting (default: "
"86400)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to bind to %s on this computer. CasinoCoin is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: -paytxfee is set very high. This is the transaction fee you will "
"pay if you send a transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Please check that your computer's date and time are correct. If "
"your clock is wrong CasinoCoin will not work properly."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"You must set rpcpassword=<password> in the configuration file:\n"
"%s\n"
"If the file does not exist, create it with owner-readable-only file "
"permissions."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"\n"
"SSL options: (see the Bitcoin Wiki for SSL setup instructions)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"),
QT_TRANSLATE_NOOP("bitcoin-core", "An error occured while setting up the RPC port %i for listening: %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Bind to given address. Use [host]:port notation for IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", "CasinoCoin version"),
QT_TRANSLATE_NOOP("bitcoin-core", "CasinoCoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot initialize keypool"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -bind address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -externalip address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node(s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks proxy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading blkindex.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of CasinoCoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed "),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction "),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: could not start node"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"),
QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using DNS lookup (default: 1 unless -connect)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using internet relay chat (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"),
QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 2500, 0 = all)"),
QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-6, default: 1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000?.dat file"),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -tor address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"),
QT_TRANSLATE_NOOP("bitcoin-core", "List commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: 9332)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: 9333 or testnet: 19333)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Maintain at most <n> connections to peers (default: 125)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (IPv4, IPv6 or Tor)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Output extra debugging information. Implies all other -debug* options"),
QT_TRANSLATE_NOOP("bitcoin-core", "Output extra network debugging information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
QT_TRANSLATE_NOOP("bitcoin-core", "Select the version of socks proxy to use (4-5, default: 5)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send command to -server or casinocoind"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send commands to node running on <ip> (default: 127.0.0.1)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to console instead of debug.log file"),
QT_TRANSLATE_NOOP("bitcoin-core", "Send trace/debug info to debugger"),
QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (default: 25)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set database disk log size in megabytes (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: casinocoin.conf)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout (in milliseconds)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: casinocoind.pid)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %d, %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -socks proxy version requested: %i"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrade wallet to latest format"),
QT_TRANSLATE_NOOP("bitcoin-core", "Usage:"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use OpenSSL (https) for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: 1 when listening)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use proxy to reach tor hidden services (default: same as -proxy)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart CasinoCoin to complete"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: this version is obsolete, upgrade required"),
};

181
src/qt/bitcoinunits.cpp Normal file
View File

@@ -0,0 +1,181 @@
#include "bitcoinunits.h"
#include <QStringList>
BitcoinUnits::BitcoinUnits(QObject *parent):
QAbstractListModel(parent),
unitlist(availableUnits())
{
}
QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits()
{
QList<BitcoinUnits::Unit> unitlist;
unitlist.append(BTC);
unitlist.append(mBTC);
unitlist.append(uBTC);
return unitlist;
}
bool BitcoinUnits::valid(int unit)
{
switch(unit)
{
case BTC:
case mBTC:
case uBTC:
return true;
default:
return false;
}
}
QString BitcoinUnits::name(int unit)
{
switch(unit)
{
case BTC: return QString("CSC");
case mBTC: return QString("mCSC");
case uBTC: return QString::fromUtf8("μCSC");
default: return QString("???");
}
}
QString BitcoinUnits::description(int unit)
{
switch(unit)
{
case BTC: return QString("CasinoCoins");
case mBTC: return QString("Milli-CasinoCoins (1 / 1,000)");
case uBTC: return QString("Micro-CasinoCoins (1 / 1,000,000)");
default: return QString("???");
}
}
qint64 BitcoinUnits::factor(int unit)
{
switch(unit)
{
case BTC: return 100000000;
case mBTC: return 100000;
case uBTC: return 100;
default: return 100000000;
}
}
int BitcoinUnits::amountDigits(int unit)
{
switch(unit)
{
case BTC: return 8; // 21,000,000 (# digits, without commas)
case mBTC: return 11; // 21,000,000,000
case uBTC: return 14; // 21,000,000,000,000
default: return 0;
}
}
int BitcoinUnits::decimals(int unit)
{
switch(unit)
{
case BTC: return 8;
case mBTC: return 5;
case uBTC: return 2;
default: return 0;
}
}
QString BitcoinUnits::format(int unit, qint64 n, bool fPlus)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
if(!valid(unit))
return QString(); // Refuse to format invalid unit
qint64 coin = factor(unit);
int num_decimals = decimals(unit);
qint64 n_abs = (n > 0 ? n : -n);
qint64 quotient = n_abs / coin;
qint64 remainder = n_abs % coin;
QString quotient_str = QString::number(quotient);
QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0');
// Right-trim excess 0's after the decimal point
int nTrim = 0;
for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i)
++nTrim;
remainder_str.chop(nTrim);
if (n < 0)
quotient_str.insert(0, '-');
else if (fPlus && n > 0)
quotient_str.insert(0, '+');
return quotient_str + QString(".") + remainder_str;
}
QString BitcoinUnits::formatWithUnit(int unit, qint64 amount, bool plussign)
{
return format(unit, amount, plussign) + QString(" ") + name(unit);
}
bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out)
{
if(!valid(unit) || value.isEmpty())
return false; // Refuse to parse invalid unit or empty string
int num_decimals = decimals(unit);
QStringList parts = value.split(".");
if(parts.size() > 2)
{
return false; // More than one dot
}
QString whole = parts[0];
QString decimals;
if(parts.size() > 1)
{
decimals = parts[1];
}
if(decimals.size() > num_decimals)
{
return false; // Exceeds max precision
}
bool ok = false;
QString str = whole + decimals.leftJustified(num_decimals, '0');
if(str.size() > 18)
{
return false; // Longer numbers will exceed 63 bits
}
qint64 retvalue = str.toLongLong(&ok);
if(val_out)
{
*val_out = retvalue;
}
return ok;
}
int BitcoinUnits::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return unitlist.size();
}
QVariant BitcoinUnits::data(const QModelIndex &index, int role) const
{
int row = index.row();
if(row >= 0 && row < unitlist.size())
{
Unit unit = unitlist.at(row);
switch(role)
{
case Qt::EditRole:
case Qt::DisplayRole:
return QVariant(name(unit));
case Qt::ToolTipRole:
return QVariant(description(unit));
case UnitRole:
return QVariant(static_cast<int>(unit));
}
}
return QVariant();
}

66
src/qt/bitcoinunits.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef BITCOINUNITS_H
#define BITCOINUNITS_H
#include <QString>
#include <QAbstractListModel>
/** Bitcoin unit definitions. Encapsulates parsing and formatting
and serves as list model for dropdown selection boxes.
*/
class BitcoinUnits: public QAbstractListModel
{
public:
explicit BitcoinUnits(QObject *parent);
/** Bitcoin units.
@note Source: https://en.bitcoin.it/wiki/Units . Please add only sensible ones
*/
enum Unit
{
BTC,
mBTC,
uBTC
};
//! @name Static API
//! Unit conversion and formatting
///@{
//! Get list of units, for dropdown box
static QList<Unit> availableUnits();
//! Is unit ID valid?
static bool valid(int unit);
//! Short name
static QString name(int unit);
//! Longer description
static QString description(int unit);
//! Number of Satoshis (1e-8) per unit
static qint64 factor(int unit);
//! Number of amount digits (to represent max number of coins)
static int amountDigits(int unit);
//! Number of decimals left
static int decimals(int unit);
//! Format as string
static QString format(int unit, qint64 amount, bool plussign=false);
//! Format as string (with unit)
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false);
//! Parse string to coin amount
static bool parse(int unit, const QString &value, qint64 *val_out);
///@}
//! @name AbstractListModel implementation
//! List model for unit dropdown selection box.
///@{
enum RoleIndex {
/** Unit identifier */
UnitRole = Qt::UserRole
};
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
///@}
private:
QList<BitcoinUnits::Unit> unitlist;
};
typedef BitcoinUnits::Unit BitcoinUnit;
#endif // BITCOINUNITS_H

209
src/qt/clientmodel.cpp Normal file
View File

@@ -0,0 +1,209 @@
#include "clientmodel.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"
#include "main.h"
#include "init.h" // for pwalletMain
#include "ui_interface.h"
#include <QDateTime>
#include <QTimer>
static const int64 nClientStartupTime = GetTime();
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
QObject(parent), optionsModel(optionsModel),
cachedNumBlocks(0), cachedNumBlocksOfPeers(0), cachedHashrate(0), pollTimer(0)
{
numBlocksAtStartup = -1;
pollTimer = new QTimer(this);
pollTimer->setInterval(MODEL_UPDATE_DELAY);
pollTimer->start();
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
subscribeToCoreSignals();
}
ClientModel::~ClientModel()
{
unsubscribeFromCoreSignals();
}
int ClientModel::getNumConnections() const
{
return vNodes.size();
}
int ClientModel::getNumBlocks() const
{
return nBestHeight;
}
int ClientModel::getNumBlocksAtStartup()
{
if (numBlocksAtStartup == -1) numBlocksAtStartup = getNumBlocks();
return numBlocksAtStartup;
}
int ClientModel::getHashrate() const
{
if (GetTimeMillis() - nHPSTimerStart > 8000)
return (boost::int64_t)0;
return (boost::int64_t)dHashesPerSec;
}
// CasinoCoin: copied from bitcoinrpc.cpp.
double ClientModel::GetDifficulty() const
{
// Floating point number that is a multiple of the minimum difficulty,
// minimum difficulty = 1.0.
if (pindexBest == NULL)
return 1.0;
int nShift = (pindexBest->nBits >> 24) & 0xff;
double dDiff =
(double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
while (nShift < 29)
{
dDiff *= 256.0;
nShift++;
}
while (nShift > 29)
{
dDiff /= 256.0;
nShift--;
}
return dDiff;
}
QDateTime ClientModel::getLastBlockDate() const
{
return QDateTime::fromTime_t(pindexBest->GetBlockTime());
}
void ClientModel::updateTimer()
{
// Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
// Periodically check and update with a timer.
int newNumBlocks = getNumBlocks();
int newNumBlocksOfPeers = getNumBlocksOfPeers();
if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers)
emit numBlocksChanged(newNumBlocks, newNumBlocksOfPeers);
cachedNumBlocks = newNumBlocks;
cachedNumBlocksOfPeers = newNumBlocksOfPeers;
}
void ClientModel::updateNumConnections(int numConnections)
{
emit numConnectionsChanged(numConnections);
}
void ClientModel::updateAlert(const QString &hash, int status)
{
// Show error message notification for new alert
if(status == CT_NEW)
{
uint256 hash_256;
hash_256.SetHex(hash.toStdString());
CAlert alert = CAlert::getAlertByHash(hash_256);
if(!alert.IsNull())
{
emit error(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false);
}
}
// Emit a numBlocksChanged when the status message changes,
// so that the view recomputes and updates the status bar.
emit numBlocksChanged(getNumBlocks(), getNumBlocksOfPeers());
}
bool ClientModel::isTestNet() const
{
return fTestNet;
}
bool ClientModel::inInitialBlockDownload() const
{
return IsInitialBlockDownload();
}
int ClientModel::getNumBlocksOfPeers() const
{
return GetNumBlocksOfPeers();
}
QString ClientModel::getStatusBarWarnings() const
{
return QString::fromStdString(GetWarnings("statusbar"));
}
OptionsModel *ClientModel::getOptionsModel()
{
return optionsModel;
}
QString ClientModel::formatFullVersion() const
{
return QString::fromStdString(FormatFullVersion());
}
QString ClientModel::formatBuildDate() const
{
return QString::fromStdString(CLIENT_DATE);
}
QString ClientModel::clientName() const
{
return QString::fromStdString(CLIENT_NAME);
}
QString ClientModel::formatClientStartupTime() const
{
return QDateTime::fromTime_t(nClientStartupTime).toString();
}
// Handlers for core signals
static void NotifyBlocksChanged(ClientModel *clientmodel)
{
// This notification is too frequent. Don't trigger a signal.
// Don't remove it, though, as it might be useful later.
}
static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
{
// Too noisy: OutputDebugStringF("NotifyNumConnectionsChanged %i\n", newNumConnections);
QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
Q_ARG(int, newNumConnections));
}
static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status)
{
OutputDebugStringF("NotifyAlertChanged %s status=%i\n", hash.GetHex().c_str(), status);
QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(hash.GetHex())),
Q_ARG(int, status));
}
void ClientModel::subscribeToCoreSignals()
{
// Connect signals to client
uiInterface.NotifyBlocksChanged.connect(boost::bind(NotifyBlocksChanged, this));
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
}
void ClientModel::unsubscribeFromCoreSignals()
{
// Disconnect signals from client
uiInterface.NotifyBlocksChanged.disconnect(boost::bind(NotifyBlocksChanged, this));
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
}

75
src/qt/clientmodel.h Normal file
View File

@@ -0,0 +1,75 @@
#ifndef CLIENTMODEL_H
#define CLIENTMODEL_H
#include <QObject>
class OptionsModel;
class AddressTableModel;
class TransactionTableModel;
class CWallet;
QT_BEGIN_NAMESPACE
class QDateTime;
class QTimer;
QT_END_NAMESPACE
/** Model for Bitcoin network client. */
class ClientModel : public QObject
{
Q_OBJECT
public:
explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0);
~ClientModel();
OptionsModel *getOptionsModel();
int getNumConnections() const;
int getNumBlocks() const;
int getNumBlocksAtStartup();
int getHashrate() const;
double GetDifficulty() const;
QDateTime getLastBlockDate() const;
//! Return true if client connected to testnet
bool isTestNet() const;
//! Return true if core is doing initial block download
bool inInitialBlockDownload() const;
//! Return conservative estimate of total number of blocks, or 0 if unknown
int getNumBlocksOfPeers() const;
//! Return warnings to be displayed in status bar
QString getStatusBarWarnings() const;
QString formatFullVersion() const;
QString formatBuildDate() const;
QString clientName() const;
QString formatClientStartupTime() const;
private:
OptionsModel *optionsModel;
int cachedNumBlocks;
int cachedNumBlocksOfPeers;
int cachedHashrate;
int numBlocksAtStartup;
QTimer *pollTimer;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
signals:
void numConnectionsChanged(int count);
void numBlocksChanged(int count, int countOfPeers);
//! Asynchronous error notification
void error(const QString &title, const QString &message, bool modal);
public slots:
void updateTimer();
void updateNumConnections(int numConnections);
void updateAlert(const QString &hash, int status);
};
#endif // CLIENTMODEL_H

88
src/qt/csvmodelwriter.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "csvmodelwriter.h"
#include <QAbstractItemModel>
#include <QFile>
#include <QTextStream>
CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) :
QObject(parent),
filename(filename), model(0)
{
}
void CSVModelWriter::setModel(const QAbstractItemModel *model)
{
this->model = model;
}
void CSVModelWriter::addColumn(const QString &title, int column, int role)
{
Column col;
col.title = title;
col.column = column;
col.role = role;
columns.append(col);
}
static void writeValue(QTextStream &f, const QString &value)
{
QString escaped = value;
escaped.replace('"', "\"\"");
f << "\"" << escaped << "\"";
}
static void writeSep(QTextStream &f)
{
f << ",";
}
static void writeNewline(QTextStream &f)
{
f << "\n";
}
bool CSVModelWriter::write()
{
QFile file(filename);
if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
return false;
QTextStream out(&file);
int numRows = 0;
if(model)
{
numRows = model->rowCount();
}
// Header row
for(int i=0; i<columns.size(); ++i)
{
if(i!=0)
{
writeSep(out);
}
writeValue(out, columns[i].title);
}
writeNewline(out);
// Data rows
for(int j=0; j<numRows; ++j)
{
for(int i=0; i<columns.size(); ++i)
{
if(i!=0)
{
writeSep(out);
}
QVariant data = model->index(j, columns[i].column).data(columns[i].role);
writeValue(out, data.toString());
}
writeNewline(out);
}
file.close();
return file.error() == QFile::NoError;
}

46
src/qt/csvmodelwriter.h Normal file
View File

@@ -0,0 +1,46 @@
#ifndef CSVMODELWRITER_H
#define CSVMODELWRITER_H
#include <QObject>
#include <QList>
QT_BEGIN_NAMESPACE
class QAbstractItemModel;
QT_END_NAMESPACE
/** Export a Qt table model to a CSV file. This is useful for analyzing or post-processing the data in
a spreadsheet.
*/
class CSVModelWriter : public QObject
{
Q_OBJECT
public:
explicit CSVModelWriter(const QString &filename, QObject *parent = 0);
void setModel(const QAbstractItemModel *model);
void addColumn(const QString &title, int column, int role=Qt::EditRole);
/** Perform export of the model to CSV.
@returns true on success, false otherwise
*/
bool write();
private:
QString filename;
const QAbstractItemModel *model;
struct Column
{
QString title;
int column;
int role;
};
QList<Column> columns;
signals:
public slots:
};
#endif // CSVMODELWRITER_H

View File

@@ -0,0 +1,128 @@
#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->setDisabled(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);
}
bool EditAddressDialog::saveCurrentRow()
{
if(!model)
return false;
switch(mode)
{
case NewReceivingAddress:
case NewSendingAddress:
address = model->addRow(
mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive,
ui->labelEdit->text(),
ui->addressEdit->text());
break;
case EditReceivingAddress:
case EditSendingAddress:
if(mapper->submit())
{
address = ui->addressEdit->text();
}
break;
}
return !address.isEmpty();
}
void EditAddressDialog::accept()
{
if(!model)
return;
if(!saveCurrentRow())
{
switch(model->getEditStatus())
{
case AddressTableModel::DUPLICATE_ADDRESS:
QMessageBox::warning(this, windowTitle(),
tr("The entered address \"%1\" is already in the address book.").arg(ui->addressEdit->text()),
QMessageBox::Ok, QMessageBox::Ok);
break;
case AddressTableModel::INVALID_ADDRESS:
QMessageBox::warning(this, windowTitle(),
tr("The entered address \"%1\" is not a valid CasinoCoin address.").arg(ui->addressEdit->text()),
QMessageBox::Ok, QMessageBox::Ok);
return;
case AddressTableModel::WALLET_UNLOCK_FAILURE:
QMessageBox::critical(this, windowTitle(),
tr("Could not unlock wallet."),
QMessageBox::Ok, QMessageBox::Ok);
return;
case AddressTableModel::KEY_GENERATION_FAILURE:
QMessageBox::critical(this, windowTitle(),
tr("New key generation failed."),
QMessageBox::Ok, QMessageBox::Ok);
return;
case AddressTableModel::OK:
// Failed with unknown reason. Just reject.
break;
}
return;
}
QDialog::accept();
}
QString EditAddressDialog::getAddress() const
{
return address;
}
void EditAddressDialog::setAddress(const QString &address)
{
this->address = address;
ui->addressEdit->setText(address);
}

View File

@@ -0,0 +1,50 @@
#ifndef EDITADDRESSDIALOG_H
#define EDITADDRESSDIALOG_H
#include <QDialog>
QT_BEGIN_NAMESPACE
class QDataWidgetMapper;
QT_END_NAMESPACE
namespace Ui {
class EditAddressDialog;
}
class AddressTableModel;
/** Dialog for editing an address and associated information.
*/
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);
void accept();
QString getAddress() const;
void setAddress(const QString &address);
private:
bool saveCurrentRow();
Ui::EditAddressDialog *ui;
QDataWidgetMapper *mapper;
Mode mode;
AddressTableModel *model;
QString address;
};
#endif // EDITADDRESSDIALOG_H

183
src/qt/forms/aboutdialog.ui Normal file
View File

@@ -0,0 +1,183 @@
<?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>400</height>
</rect>
</property>
<property name="windowTitle">
<string>About CasinoCoin</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="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="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>&lt;b&gt;CasinoCoin&lt;/b&gt; version</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="versionLabel">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string notr="true">0.3.666-beta</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</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="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>
Copyright © 2009-2012 Bitcoin Developers
Copyright © 2011-2012 Litecoin Developers
Copyright © 2013 CasinoCoin Developers
This is experimental software.
Distributed under the MIT/X11 software license, see the accompanying file COPYING 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.
Official forum: http://forum.casinoco.in
</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</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>

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddressBookPage</class>
<widget class="QWidget" name="AddressBookPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>760</width>
<height>380</height>
</rect>
</property>
<property name="windowTitle">
<string>Address Book</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelExplanation">
<property name="text">
<string>These are your CasinoCoin 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.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="tableView">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="toolTip">
<string>Double-click to edit address or label</string>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<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>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="newAddressButton">
<property name="toolTip">
<string>Create a new address</string>
</property>
<property name="text">
<string>&amp;New Address</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/add</normaloff>:/icons/add</iconset>
</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>&amp;Copy Address</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/editcopy</normaloff>:/icons/editcopy</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="showQRCode">
<property name="text">
<string>Show &amp;QR Code</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/qrcode</normaloff>:/icons/qrcode</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="signMessage">
<property name="toolTip">
<string>Sign a message to prove you own a Bitcoin address</string>
</property>
<property name="text">
<string>&amp;Sign Message</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/edit</normaloff>:/icons/edit</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="verifyMessage">
<property name="toolTip">
<string>Verify a message to ensure it was signed with a specified Bitcoin address</string>
</property>
<property name="text">
<string>&amp;Verify Message</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/transaction_0</normaloff>:/icons/transaction_0</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="toolTip">
<string>Delete the currently selected address from the list. Only sending addresses can be deleted.</string>
</property>
<property name="text">
<string>&amp;Delete</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</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>
<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>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AskPassphraseDialog</class>
<widget class="QDialog" name="AskPassphraseDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>598</width>
<height>198</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>550</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Passphrase Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="warningLabel">
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="passLabel1">
<property name="text">
<string>Enter passphrase</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="passEdit1">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="passLabel2">
<property name="text">
<string>New passphrase</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="passEdit2">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="passLabel3">
<property name="text">
<string>Repeat new passphrase</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="passEdit3">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="capsLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</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>AskPassphraseDialog</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>AskPassphraseDialog</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>

View 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>457</width>
<height>126</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>&amp;Label</string>
</property>
<property name="buddy">
<cstring>labelEdit</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="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Address</string>
</property>
<property name="buddy">
<cstring>addressEdit</cstring>
</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>

View File

@@ -0,0 +1,466 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OptionsDialog</class>
<widget class="QDialog" name="OptionsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>540</width>
<height>380</height>
</rect>
</property>
<property name="windowTitle">
<string>Options</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="tabMain">
<attribute name="title">
<string>&amp;Main</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Main">
<item>
<widget class="QLabel" name="transactionFeeInfoLabel">
<property name="text">
<string>Optional transaction fee per kB that helps make sure your transactions are processed quickly. Most transactions are 1 kB. Fee 0.01 recommended.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Main">
<item>
<widget class="QLabel" name="transactionFeeLabel">
<property name="text">
<string>Pay transaction &amp;fee</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>transactionFee</cstring>
</property>
</widget>
</item>
<item>
<widget class="BitcoinAmountField" name="transactionFee"/>
</item>
<item>
<spacer name="horizontalSpacer_Main">
<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="QCheckBox" name="bitcoinAtStartup">
<property name="toolTip">
<string>Automatically start CasinoCoin after logging in to the system.</string>
</property>
<property name="text">
<string>&amp;Start CasinoCoin on system login</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="detachDatabases">
<property name="toolTip">
<string>Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached.</string>
</property>
<property name="text">
<string>&amp;Detach databases at shutdown</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_Main">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabNetwork">
<attribute name="title">
<string>&amp;Network</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Network">
<item>
<widget class="QCheckBox" name="mapPortUpnp">
<property name="toolTip">
<string>Automatically open the CasinoCoin client port on the router. This only works when your router supports UPnP and it is enabled.</string>
</property>
<property name="text">
<string>Map port using &amp;UPnP</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="connectSocks">
<property name="toolTip">
<string>Connect to the CasinoCoin network through a SOCKS proxy (e.g. when connecting through Tor).</string>
</property>
<property name="text">
<string>&amp;Connect through SOCKS proxy:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Network">
<item>
<widget class="QLabel" name="proxyIpLabel">
<property name="text">
<string>Proxy &amp;IP:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>proxyIp</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValidatedLineEdit" name="proxyIp">
<property name="maximumSize">
<size>
<width>140</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>IP address of the proxy (e.g. 127.0.0.1)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="proxyPortLabel">
<property name="text">
<string>&amp;Port:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>proxyPort</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="proxyPort">
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Port of the proxy (e.g. 9050)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="socksVersionLabel">
<property name="text">
<string>SOCKS &amp;Version:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>socksVersion</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValueComboBox" name="socksVersion">
<property name="toolTip">
<string>SOCKS version of the proxy (e.g. 5)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_Network">
<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>
<spacer name="verticalSpacer_Network">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabWindow">
<attribute name="title">
<string>&amp;Window</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Window">
<item>
<widget class="QCheckBox" name="minimizeToTray">
<property name="toolTip">
<string>Show only a tray icon after minimizing the window.</string>
</property>
<property name="text">
<string>&amp;Minimize to the tray instead of the taskbar</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="minimizeOnClose">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>M&amp;inimize on close</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_Window">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabDisplay">
<attribute name="title">
<string>&amp;Display</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_Display">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_1_Display">
<item>
<widget class="QLabel" name="langLabel">
<property name="text">
<string>User Interface &amp;language:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>lang</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValueComboBox" name="lang">
<property name="toolTip">
<string>The user interface language can be set here. This setting will take effect after restarting CasinoCoin.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2_Display">
<item>
<widget class="QLabel" name="unitLabel">
<property name="text">
<string>&amp;Unit to show amounts in:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>unit</cstring>
</property>
</widget>
</item>
<item>
<widget class="QValueComboBox" name="unit">
<property name="toolTip">
<string>Choose the default subdivision unit to show in the interface and when sending coins.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="displayAddresses">
<property name="toolTip">
<string>Whether to show CasinoCoin addresses in the transaction list or not.</string>
</property>
<property name="text">
<string>&amp;Display addresses in transaction list</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_Display">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Buttons">
<item>
<spacer name="horizontalSpacer_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>48</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="statusLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>48</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okButton">
<property name="text">
<string>&amp;OK</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelButton">
<property name="text">
<string>&amp;Cancel</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="applyButton">
<property name="text">
<string>&amp;Apply</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QSpinBox</extends>
<header>bitcoinamountfield.h</header>
</customwidget>
<customwidget>
<class>QValueComboBox</class>
<extends>QComboBox</extends>
<header>qvaluecombobox.h</header>
</customwidget>
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
<header>qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,320 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OverviewPage</class>
<widget class="QWidget" name="OverviewPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>573</width>
<height>342</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<pointsize>11</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Wallet</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelWalletStatus">
<property name="toolTip">
<string>The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet.</string>
</property>
<property name="styleSheet">
<string notr="true">QLabel { color: red; }</string>
</property>
<property name="text">
<string notr="true">(out of sync)</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<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>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="horizontalSpacing">
<number>12</number>
</property>
<property name="verticalSpacing">
<number>12</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Balance:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="labelBalance">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="toolTip">
<string>Your current balance</string>
</property>
<property name="text">
<string notr="true">0 CSC</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Unconfirmed:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="labelUnconfirmed">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="toolTip">
<string>Total of transactions that have yet to be confirmed, and do not yet count toward the current balance</string>
</property>
<property name="text">
<string notr="true">0 CSC</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Number of transactions:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="labelNumTransactions">
<property name="toolTip">
<string>Total number of transactions in wallet</string>
</property>
<property name="text">
<string notr="true">0</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelImmatureText">
<property name="text">
<string>Immature:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="labelImmature">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Mined balance that has not yet matured</string>
</property>
<property name="text">
<string notr="true">0 CSC</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</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="QLabel" name="label_6">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../bitcoin.qrc">:/images/backg</pixmap>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="margin">
<number>-2</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>&lt;b&gt;Recent transactions&lt;/b&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelTransactionsStatus">
<property name="toolTip">
<string>The displayed information may be out of date. Your wallet automatically synchronizes with the CasinoCoin network after a connection is established, but this process has not completed yet.</string>
</property>
<property name="styleSheet">
<string notr="true">QLabel { color: red; }</string>
</property>
<property name="text">
<string notr="true">(out of sync)</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</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="QListView" name="listTransactions">
<property name="styleSheet">
<string notr="true">QListView { background: transparent; }</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<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>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QRCodeDialog</class>
<widget class="QDialog" name="QRCodeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>340</width>
<height>530</height>
</rect>
</property>
<property name="windowTitle">
<string>QR Code Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="lblQRCode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>300</height>
</size>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="outUri">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>50</height>
</size>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="chkReqPayment">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Request Payment</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="1" column="0">
<widget class="QLabel" name="lblLabel">
<property name="text">
<string>Label:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnLabel</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lnLabel"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblMessage">
<property name="text">
<string>Message:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnMessage</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lnMessage"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblAmount">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Amount:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnReqAmount</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="BitcoinAmountField" name="lnReqAmount">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</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="btnSaveAs">
<property name="text">
<string>&amp;Save As...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QSpinBox</extends>
<header>bitcoinamountfield.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>chkReqPayment</sender>
<signal>clicked(bool)</signal>
<receiver>lnReqAmount</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>92</x>
<y>285</y>
</hint>
<hint type="destinationlabel">
<x>98</x>
<y>311</y>
</hint>
</hints>
</connection>
</connections>
</ui>

436
src/qt/forms/rpcconsole.ui Normal file
View File

@@ -0,0 +1,436 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RPCConsole</class>
<widget class="QDialog" name="RPCConsole">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>740</width>
<height>450</height>
</rect>
</property>
<property name="windowTitle">
<string>CasinoCoin - Debug window</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_info">
<attribute name="title">
<string>&amp;Information</string>
</attribute>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<property name="horizontalSpacing">
<number>12</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Bitcoin Core</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Client name</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="clientName">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Client version</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="clientVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Using OpenSSL version</string>
</property>
<property name="indent">
<number>10</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="openSSLVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Startup time</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="startupTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_11">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Network</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Number of connections</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="numberOfConnections">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>On testnet</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="isTestNet">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Block chain</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Current number of blocks</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="numberOfBlocks">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Estimated total blocks</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="totalBlocks">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Last block time</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="lastBlockTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>N/A</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="14" column="0">
<widget class="QLabel" name="labelDebugLogfile">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Debug logfile</string>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QPushButton" name="openDebugLogfileButton">
<property name="toolTip">
<string>Open the CasinoCoin debug logfile from the current data directory. This can take a few seconds for large logfiles.</string>
</property>
<property name="text">
<string>&amp;Open</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="labelCLOptions">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Command-line options</string>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QPushButton" name="showCLOptionsButton">
<property name="toolTip">
<string>Show the CasinoCoin-Qt help message to get a list with possible CasinoCoin command-line options.</string>
</property>
<property name="text">
<string>&amp;Show</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item row="18" column="0">
<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>
</layout>
</widget>
<widget class="QWidget" name="tab_console">
<attribute name="title">
<string>&amp;Console</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QTextEdit" name="messagesWidget">
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="tabKeyNavigation" stdset="0">
<bool>false</bool>
</property>
<property name="columnCount" stdset="0">
<number>2</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string notr="true">&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Clear console</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
<property name="shortcut">
<string notr="true">Ctrl+L</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,175 @@
<?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>686</width>
<height>217</height>
</rect>
</property>
<property name="windowTitle">
<string>Send Coins</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>666</width>
<height>165</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="entries">
<property name="spacing">
<number>6</number>
</property>
</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>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="addButton">
<property name="toolTip">
<string>Send to multiple recipients at once</string>
</property>
<property name="text">
<string>&amp;Add Recipient</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/add</normaloff>:/icons/add</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Remove all transaction fields</string>
</property>
<property name="text">
<string>Clear &amp;All</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
<property name="autoRepeatDelay">
<number>300</number>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>3</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Balance:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelBalance">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
<string>123.456 CSC</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</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>
<item>
<widget class="QPushButton" name="sendButton">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Confirm the send action</string>
</property>
<property name="text">
<string>&amp;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>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SendCoinsEntry</class>
<widget class="QFrame" name="SendCoinsEntry">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>729</width>
<height>136</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="spacing">
<number>12</number>
</property>
<item row="5" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>A&amp;mount:</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 &amp;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="5" column="1">
<widget class="BitcoinAmountField" name="payAmount"/>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QValidatedLineEdit" name="addAsLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Enter a label for this address to add it to your address book</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Label:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>addAsLabel</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="payToLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QValidatedLineEdit" 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>
<widget class="QToolButton" name="addressBookButton">
<property name="toolTip">
<string>Choose address from address book</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/address-book</normaloff>:/icons/address-book</iconset>
</property>
<property name="shortcut">
<string>Alt+A</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="pasteButton">
<property name="toolTip">
<string>Paste address from clipboard</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/editpaste</normaloff>:/icons/editpaste</iconset>
</property>
<property name="shortcut">
<string>Alt+P</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="deleteButton">
<property name="toolTip">
<string>Remove this recipient</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
<header>bitcoinamountfield.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
<header>qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,386 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SignVerifyMessageDialog</class>
<widget class="QDialog" name="SignVerifyMessageDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>700</width>
<height>380</height>
</rect>
</property>
<property name="windowTitle">
<string>Signatures - Sign / Verify a Message</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabSignMessage">
<attribute name="title">
<string>&amp;Sign Message</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_SM">
<item>
<widget class="QLabel" name="infoLabel_SM">
<property name="text">
<string>You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_1_SM">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QValidatedLineEdit" name="addressIn_SM">
<property name="toolTip">
<string>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
</property>
<property name="maxLength">
<number>34</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addressBookButton_SM">
<property name="toolTip">
<string>Choose an address from the address book</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/address-book</normaloff>:/icons/address-book</iconset>
</property>
<property name="shortcut">
<string>Alt+A</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pasteButton_SM">
<property name="toolTip">
<string>Paste address from clipboard</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/editpaste</normaloff>:/icons/editpaste</iconset>
</property>
<property name="shortcut">
<string>Alt+P</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPlainTextEdit" name="messageIn_SM">
<property name="toolTip">
<string>Enter the message you want to sign here</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2_SM">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="signatureOut_SM">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="copySignatureButton_SM">
<property name="toolTip">
<string>Copy the current signature to the system clipboard</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/editcopy</normaloff>:/icons/editcopy</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3_SM">
<item>
<widget class="QPushButton" name="signMessageButton_SM">
<property name="toolTip">
<string>Sign the message to prove you own this Bitcoin address</string>
</property>
<property name="text">
<string>&amp;Sign Message</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/edit</normaloff>:/icons/edit</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton_SM">
<property name="toolTip">
<string>Reset all sign message fields</string>
</property>
<property name="text">
<string>Clear &amp;All</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_1_SM">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>48</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="statusLabel_SM">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2_SM">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>48</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabVerifyMessage">
<attribute name="title">
<string>&amp;Verify Message</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_VM">
<item>
<widget class="QLabel" name="infoLabel_VM">
<property name="text">
<string>Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack.</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_1_VM">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QValidatedLineEdit" name="addressIn_VM">
<property name="toolTip">
<string>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
</property>
<property name="maxLength">
<number>34</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addressBookButton_VM">
<property name="toolTip">
<string>Choose an address from the address book</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/address-book</normaloff>:/icons/address-book</iconset>
</property>
<property name="shortcut">
<string>Alt+A</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPlainTextEdit" name="messageIn_VM"/>
</item>
<item>
<widget class="QValidatedLineEdit" name="signatureIn_VM"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2_VM">
<item>
<widget class="QPushButton" name="verifyMessageButton_VM">
<property name="toolTip">
<string>Verify the message to ensure it was signed with the specified Bitcoin address</string>
</property>
<property name="text">
<string>&amp;Verify Message</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/transaction_0</normaloff>:/icons/transaction_0</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton_VM">
<property name="toolTip">
<string>Reset all verify message fields</string>
</property>
<property name="text">
<string>Clear &amp;All</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_1_VM">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>48</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="statusLabel_VM">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2_VM">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>48</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
<header>qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../bitcoin.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,74 @@
<?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>620</width>
<height>250</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>
<property name="readOnly">
<bool>true</bool>
</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>

34
src/qt/guiconstants.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef GUICONSTANTS_H
#define GUICONSTANTS_H
/* Milliseconds between model updates */
static const int MODEL_UPDATE_DELAY = 500;
/* AskPassphraseDialog -- Maximum passphrase length */
static const int MAX_PASSPHRASE_SIZE = 1024;
/* BitcoinGUI -- Size of icons in status bar */
static const int STATUSBAR_ICONSIZE = 16;
/* Invalid field background style */
#define STYLE_INVALID "background:#FF8080"
/* Transaction list -- unconfirmed transaction */
#define COLOR_UNCONFIRMED QColor(128, 128, 128)
/* Transaction list -- negative amount */
#define COLOR_NEGATIVE QColor(255, 0, 0)
/* Transaction list -- bare address (without label) */
#define COLOR_BAREADDRESS QColor(140, 140, 140)
/* Tooltips longer than this (in characters) are converted into rich text,
so that they can be word-wrapped.
*/
static const int TOOLTIP_WRAP_THRESHOLD = 80;
/* Maximum allowed URI length */
static const int MAX_URI_LENGTH = 255;
/* QRCodeDialog -- size of exported QR Code image */
#define EXPORT_IMAGE_SIZE 256
#endif // GUICONSTANTS_H

463
src/qt/guiutil.cpp Normal file
View File

@@ -0,0 +1,463 @@
#include "guiutil.h"
#include "bitcoinaddressvalidator.h"
#include "walletmodel.h"
#include "bitcoinunits.h"
#include "util.h"
#include "init.h"
#include "base58.h"
#include <QString>
#include <QDateTime>
#include <QDoubleValidator>
#include <QFont>
#include <QLineEdit>
#include <QUrl>
#include <QTextDocument> // For Qt::escape
#include <QAbstractItemView>
#include <QApplication>
#include <QClipboard>
#include <QFileDialog>
#include <QDesktopServices>
#include <QThread>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#ifdef WIN32
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "shlwapi.h"
#include "shlobj.h"
#include "shellapi.h"
#endif
namespace GUIUtil {
QString dateTimeStr(const QDateTime &date)
{
return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
}
QString dateTimeStr(qint64 nTime)
{
return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
}
QFont bitcoinAddressFont()
{
QFont font("Monospace");
font.setStyleHint(QFont::TypeWriter);
return font;
}
void setupAddressWidget(QLineEdit *widget, QWidget *parent)
{
widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
widget->setValidator(new BitcoinAddressValidator(parent));
widget->setFont(bitcoinAddressFont());
}
void setupAmountWidget(QLineEdit *widget, QWidget *parent)
{
QDoubleValidator *amountValidator = new QDoubleValidator(parent);
amountValidator->setDecimals(8);
amountValidator->setBottom(0.0);
widget->setValidator(amountValidator);
widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
}
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
{
if(uri.scheme() != QString("casinocoin"))
return false;
// check if the address is valid
CBitcoinAddress addressFromUri(uri.path().toStdString());
if (!addressFromUri.IsValid())
return false;
SendCoinsRecipient rv;
rv.address = uri.path();
rv.amount = 0;
QList<QPair<QString, QString> > items = uri.queryItems();
for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
{
bool fShouldReturnFalse = false;
if (i->first.startsWith("req-"))
{
i->first.remove(0, 4);
fShouldReturnFalse = true;
}
if (i->first == "label")
{
rv.label = i->second;
fShouldReturnFalse = false;
}
else if (i->first == "amount")
{
if(!i->second.isEmpty())
{
if(!BitcoinUnits::parse(BitcoinUnits::BTC, i->second, &rv.amount))
{
return false;
}
}
fShouldReturnFalse = false;
}
if (fShouldReturnFalse)
return false;
}
if(out)
{
*out = rv;
}
return true;
}
bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
{
// Convert casinocoin:// to casinocoin:
//
// Cannot handle this later, because casinocoin:// will cause Qt to see the part after // as host,
// which will lowercase it (and thus invalidate the address).
if(uri.startsWith("casinocoin://"))
{
uri.replace(0, 11, "casinocoin:");
}
QUrl uriInstance(uri);
return parseBitcoinURI(uriInstance, out);
}
QString HtmlEscape(const QString& str, bool fMultiLine)
{
QString escaped = Qt::escape(str);
if(fMultiLine)
{
escaped = escaped.replace("\n", "<br>\n");
}
return escaped;
}
QString HtmlEscape(const std::string& str, bool fMultiLine)
{
return HtmlEscape(QString::fromStdString(str), fMultiLine);
}
void copyEntryData(QAbstractItemView *view, int column, int role)
{
if(!view || !view->selectionModel())
return;
QModelIndexList selection = view->selectionModel()->selectedRows(column);
if(!selection.isEmpty())
{
// Copy first item
QApplication::clipboard()->setText(selection.at(0).data(role).toString());
}
}
QString getSaveFileName(QWidget *parent, const QString &caption,
const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
{
QString selectedFilter;
QString myDir;
if(dir.isEmpty()) // Default to user documents location
{
myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
}
else
{
myDir = dir;
}
QString result = QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter);
/* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
QString selectedSuffix;
if(filter_re.exactMatch(selectedFilter))
{
selectedSuffix = filter_re.cap(1);
}
/* Add suffix if needed */
QFileInfo info(result);
if(!result.isEmpty())
{
if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
{
/* No suffix specified, add selected suffix */
if(!result.endsWith("."))
result.append(".");
result.append(selectedSuffix);
}
}
/* Return selected suffix if asked to */
if(selectedSuffixOut)
{
*selectedSuffixOut = selectedSuffix;
}
return result;
}
Qt::ConnectionType blockingGUIThreadConnection()
{
if(QThread::currentThread() != QCoreApplication::instance()->thread())
{
return Qt::BlockingQueuedConnection;
}
else
{
return Qt::DirectConnection;
}
}
bool checkPoint(const QPoint &p, const QWidget *w)
{
QWidget *atW = qApp->widgetAt(w->mapToGlobal(p));
if (!atW) return false;
return atW->topLevelWidget() == w;
}
bool isObscured(QWidget *w)
{
return !(checkPoint(QPoint(0, 0), w)
&& checkPoint(QPoint(w->width() - 1, 0), w)
&& checkPoint(QPoint(0, w->height() - 1), w)
&& checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
&& checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
}
void openDebugLogfile()
{
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
/* Open debug.log with the associated application */
if (boost::filesystem::exists(pathDebug))
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(pathDebug.string())));
}
ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
QObject(parent), size_threshold(size_threshold)
{
}
bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
{
if(evt->type() == QEvent::ToolTipChange)
{
QWidget *widget = static_cast<QWidget*>(obj);
QString tooltip = widget->toolTip();
if(tooltip.size() > size_threshold && !tooltip.startsWith("<qt/>") && !Qt::mightBeRichText(tooltip))
{
// Prefix <qt/> to make sure Qt detects this as rich text
// Escape the current message as HTML and replace \n by <br>
tooltip = "<qt/>" + HtmlEscape(tooltip, true);
widget->setToolTip(tooltip);
return true;
}
}
return QObject::eventFilter(obj, evt);
}
#ifdef WIN32
boost::filesystem::path static StartupShortcutPath()
{
return GetSpecialFolderPath(CSIDL_STARTUP) / "CasinoCoin.lnk";
}
bool GetStartOnSystemStartup()
{
// check for CasinoCoin.lnk
return boost::filesystem::exists(StartupShortcutPath());
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
// If the shortcut exists already, remove it for updating
boost::filesystem::remove(StartupShortcutPath());
if (fAutoStart)
{
CoInitialize(NULL);
// Get a pointer to the IShellLink interface.
IShellLink* psl = NULL;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER, IID_IShellLink,
reinterpret_cast<void**>(&psl));
if (SUCCEEDED(hres))
{
// Get the current executable path
TCHAR pszExePath[MAX_PATH];
GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
TCHAR pszArgs[5] = TEXT("-min");
// Set the path to the shortcut target
psl->SetPath(pszExePath);
PathRemoveFileSpec(pszExePath);
psl->SetWorkingDirectory(pszExePath);
psl->SetShowCmd(SW_SHOWMINNOACTIVE);
psl->SetArguments(pszArgs);
// Query IShellLink for the IPersistFile interface for
// saving the shortcut in persistent storage.
IPersistFile* ppf = NULL;
hres = psl->QueryInterface(IID_IPersistFile,
reinterpret_cast<void**>(&ppf));
if (SUCCEEDED(hres))
{
WCHAR pwsz[MAX_PATH];
// Ensure that the string is ANSI.
MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH);
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(pwsz, TRUE);
ppf->Release();
psl->Release();
CoUninitialize();
return true;
}
psl->Release();
}
CoUninitialize();
return false;
}
return true;
}
#elif defined(LINUX)
// Follow the Desktop Application Autostart Spec:
// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
boost::filesystem::path static GetAutostartDir()
{
namespace fs = boost::filesystem;
char* pszConfigHome = getenv("XDG_CONFIG_HOME");
if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
char* pszHome = getenv("HOME");
if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
return fs::path();
}
boost::filesystem::path static GetAutostartFilePath()
{
return GetAutostartDir() / "casinocoin.desktop";
}
bool GetStartOnSystemStartup()
{
boost::filesystem::ifstream optionFile(GetAutostartFilePath());
if (!optionFile.good())
return false;
// Scan through file for "Hidden=true":
std::string line;
while (!optionFile.eof())
{
getline(optionFile, line);
if (line.find("Hidden") != std::string::npos &&
line.find("true") != std::string::npos)
return false;
}
optionFile.close();
return true;
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
if (!fAutoStart)
boost::filesystem::remove(GetAutostartFilePath());
else
{
char pszExePath[MAX_PATH+1];
memset(pszExePath, 0, sizeof(pszExePath));
if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
return false;
boost::filesystem::create_directories(GetAutostartDir());
boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
if (!optionFile.good())
return false;
// Write a casinocoin.desktop file to the autostart directory:
optionFile << "[Desktop Entry]\n";
optionFile << "Type=Application\n";
optionFile << "Name=CasinoCoin\n";
optionFile << "Exec=" << pszExePath << " -min\n";
optionFile << "Terminal=false\n";
optionFile << "Hidden=false\n";
optionFile.close();
}
return true;
}
#else
// TODO: OSX startup stuff; see:
// https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
bool GetStartOnSystemStartup() { return false; }
bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
#endif
HelpMessageBox::HelpMessageBox(QWidget *parent) :
QMessageBox(parent)
{
header = tr("CasinoCoin-Qt") + " " + tr("version") + " " +
QString::fromStdString(FormatFullVersion()) + "\n\n" +
tr("Usage:") + "\n" +
" casinocoin-qt [" + tr("command-line options") + "] " + "\n";
coreOptions = QString::fromStdString(HelpMessage());
uiOptions = tr("UI options") + ":\n" +
" -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
" -min " + tr("Start minimized") + "\n" +
" -splash " + tr("Show splash screen on startup (default: 1)") + "\n";
setWindowTitle(tr("CasinoCoin-Qt"));
setTextFormat(Qt::PlainText);
// setMinimumWidth is ignored for QMessageBox so put in nonbreaking spaces to make it wider.
setText(header + QString(QChar(0x2003)).repeated(50));
setDetailedText(coreOptions + "\n" + uiOptions);
}
void HelpMessageBox::printToConsole()
{
// On other operating systems, the expected action is to print the message to the console.
QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
fprintf(stderr, "%s", strUsage.toStdString().c_str());
}
void HelpMessageBox::showOrPrint()
{
#if defined(WIN32)
// On windows, show a message box, as there is no stderr/stdout in windowed applications
exec();
#else
// On other operating systems, print help text to console
printToConsole();
#endif
}
} // namespace GUIUtil

120
src/qt/guiutil.h Normal file
View File

@@ -0,0 +1,120 @@
#ifndef GUIUTIL_H
#define GUIUTIL_H
#include <QString>
#include <QObject>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
class QFont;
class QLineEdit;
class QWidget;
class QDateTime;
class QUrl;
class QAbstractItemView;
QT_END_NAMESPACE
class SendCoinsRecipient;
/** Utility functions used by the CasinoCoin Qt UI.
*/
namespace GUIUtil
{
// Create human-readable string from date
QString dateTimeStr(const QDateTime &datetime);
QString dateTimeStr(qint64 nTime);
// Render CasinoCoin addresses in monospace font
QFont bitcoinAddressFont();
// Set up widgets for address and amounts
void setupAddressWidget(QLineEdit *widget, QWidget *parent);
void setupAmountWidget(QLineEdit *widget, QWidget *parent);
// Parse "casinocoin:" URI into recipient object, return true on succesful parsing
// See Bitcoin URI definition discussion here: https://bitcointalk.org/index.php?topic=33490.0
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out);
bool parseBitcoinURI(QString uri, SendCoinsRecipient *out);
// HTML escaping for rich text controls
QString HtmlEscape(const QString& str, bool fMultiLine=false);
QString HtmlEscape(const std::string& str, bool fMultiLine=false);
/** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing
is selected.
@param[in] column Data column to extract from the model
@param[in] role Data role to extract from the model
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
*/
void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
/** Get save file name, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
when no suffix is provided by the user.
@param[in] parent Parent window (or 0)
@param[in] caption Window caption (or empty, for default)
@param[in] dir Starting directory (or empty, to default to documents directory)
@param[in] filter Filter specification such as "Comma Separated Files (*.csv)"
@param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0).
Can be useful when choosing the save file format based on suffix.
*/
QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(),
const QString &dir=QString(), const QString &filter=QString(),
QString *selectedSuffixOut=0);
/** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking.
@returns If called from the GUI thread, return a Qt::DirectConnection.
If called from another thread, return a Qt::BlockingQueuedConnection.
*/
Qt::ConnectionType blockingGUIThreadConnection();
// Determine whether a widget is hidden behind other windows
bool isObscured(QWidget *w);
// Open debug.log
void openDebugLogfile();
/** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text
representation if needed. This assures that Qt can word-wrap long tooltip messages.
Tooltips longer than the provided size threshold (in characters) are wrapped.
*/
class ToolTipToRichTextFilter : public QObject
{
Q_OBJECT
public:
explicit ToolTipToRichTextFilter(int size_threshold, QObject *parent = 0);
protected:
bool eventFilter(QObject *obj, QEvent *evt);
private:
int size_threshold;
};
bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart);
/** Help message for CasinoCoin-Qt, shown with --help. */
class HelpMessageBox : public QMessageBox
{
Q_OBJECT
public:
HelpMessageBox(QWidget *parent = 0);
/** Show message box or print help message to standard output, based on operating system. */
void showOrPrint();
/** Print help message to console */
void printToConsole();
private:
QString header;
QString coreOptions;
QString uiOptions;
};
} // namespace GUIUtil
#endif // GUIUTIL_H

2500
src/qt/locale/bitcoin_bg.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2520
src/qt/locale/bitcoin_cs.ts Normal file

File diff suppressed because it is too large Load Diff

2532
src/qt/locale/bitcoin_da.ts Normal file

File diff suppressed because it is too large Load Diff

2518
src/qt/locale/bitcoin_de.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2086
src/qt/locale/bitcoin_en.ts Normal file

File diff suppressed because it is too large Load Diff

2540
src/qt/locale/bitcoin_es.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2499
src/qt/locale/bitcoin_et.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More