mirror of
https://github.com/AskDavis/Casinotest.git
synced 2026-01-02 20:09:47 -08:00
Initial commit.
This commit is contained in:
527
src/addrman.cpp
Normal file
527
src/addrman.cpp
Normal 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
503
src/addrman.h
Normal 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
124
src/allocators.h
Normal 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
468
src/base58.h
Normal 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
550
src/bignum.h
Normal 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
3399
src/bitcoinrpc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
75
src/bitcoinrpc.h
Normal file
75
src/bitcoinrpc.h
Normal 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 ¶ms) const;
|
||||
};
|
||||
|
||||
extern const CRPCTable tableRPC;
|
||||
|
||||
#endif
|
||||
60
src/checkpoints.cpp
Normal file
60
src/checkpoints.cpp
Normal 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
29
src/checkpoints.h
Normal 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
65
src/compat.h
Normal 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
135
src/crypter.cpp
Normal 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
102
src/crypter.h
Normal 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
842
src/db.cpp
Normal 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
340
src/db.h
Normal 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
774
src/init.cpp
Normal 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
19
src/init.h
Normal 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
396
src/irc.cpp
Normal 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
14
src/irc.h
Normal 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
24
src/json/LICENSE.txt
Normal 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
18
src/json/json_spirit.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef JSON_SPIRIT
|
||||
#define JSON_SPIRIT
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
#include "json_spirit_reader.h"
|
||||
#include "json_spirit_writer.h"
|
||||
#include "json_spirit_utils.h"
|
||||
|
||||
#endif
|
||||
54
src/json/json_spirit_error_position.h
Normal file
54
src/json/json_spirit_error_position.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef JSON_SPIRIT_ERROR_POSITION
|
||||
#define JSON_SPIRIT_ERROR_POSITION
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
// An Error_position exception is thrown by the "read_or_throw" functions below on finding an error.
|
||||
// Note the "read_or_throw" functions are around 3 times slower than the standard functions "read"
|
||||
// functions that return a bool.
|
||||
//
|
||||
struct Error_position
|
||||
{
|
||||
Error_position();
|
||||
Error_position( unsigned int line, unsigned int column, const std::string& reason );
|
||||
bool operator==( const Error_position& lhs ) const;
|
||||
unsigned int line_;
|
||||
unsigned int column_;
|
||||
std::string reason_;
|
||||
};
|
||||
|
||||
inline Error_position::Error_position()
|
||||
: line_( 0 )
|
||||
, column_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason )
|
||||
: line_( line )
|
||||
, column_( column )
|
||||
, reason_( reason )
|
||||
{
|
||||
}
|
||||
|
||||
inline bool Error_position::operator==( const Error_position& lhs ) const
|
||||
{
|
||||
if( this == &lhs ) return true;
|
||||
|
||||
return ( reason_ == lhs.reason_ ) &&
|
||||
( line_ == lhs.line_ ) &&
|
||||
( column_ == lhs.column_ );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
137
src/json/json_spirit_reader.cpp
Normal file
137
src/json/json_spirit_reader.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#include "json_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
|
||||
62
src/json/json_spirit_reader.h
Normal file
62
src/json/json_spirit_reader.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef JSON_SPIRIT_READER
|
||||
#define JSON_SPIRIT_READER
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
#include "json_spirit_error_position.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
// functions to reads a JSON values
|
||||
|
||||
bool read( const std::string& s, Value& value );
|
||||
bool read( std::istream& is, Value& value );
|
||||
bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value );
|
||||
|
||||
void read_or_throw( const std::string& s, Value& value );
|
||||
void read_or_throw( std::istream& is, Value& value );
|
||||
void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value );
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
|
||||
bool read( const std::wstring& s, wValue& value );
|
||||
bool read( std::wistream& is, wValue& value );
|
||||
bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value );
|
||||
|
||||
void read_or_throw( const std::wstring& s, wValue& value );
|
||||
void read_or_throw( std::wistream& is, wValue& value );
|
||||
void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value );
|
||||
|
||||
#endif
|
||||
|
||||
bool read( const std::string& s, mValue& value );
|
||||
bool read( std::istream& is, mValue& value );
|
||||
bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value );
|
||||
|
||||
void read_or_throw( const std::string& s, mValue& value );
|
||||
void read_or_throw( std::istream& is, mValue& value );
|
||||
void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value );
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
|
||||
bool read( const std::wstring& s, wmValue& value );
|
||||
bool read( std::wistream& is, wmValue& value );
|
||||
bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value );
|
||||
|
||||
void read_or_throw( const std::wstring& s, wmValue& value );
|
||||
void read_or_throw( std::wistream& is, wmValue& value );
|
||||
void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
612
src/json/json_spirit_reader_template.h
Normal file
612
src/json/json_spirit_reader_template.h
Normal file
@@ -0,0 +1,612 @@
|
||||
#ifndef JSON_SPIRIT_READER_TEMPLATE
|
||||
#define JSON_SPIRIT_READER_TEMPLATE
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
#include "json_spirit_error_position.h"
|
||||
|
||||
//#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 103800
|
||||
#include <boost/spirit/include/classic_core.hpp>
|
||||
#include <boost/spirit/include/classic_confix.hpp>
|
||||
#include <boost/spirit/include/classic_escape_char.hpp>
|
||||
#include <boost/spirit/include/classic_multi_pass.hpp>
|
||||
#include <boost/spirit/include/classic_position_iterator.hpp>
|
||||
#define spirit_namespace boost::spirit::classic
|
||||
#else
|
||||
#include <boost/spirit/core.hpp>
|
||||
#include <boost/spirit/utility/confix.hpp>
|
||||
#include <boost/spirit/utility/escape_char.hpp>
|
||||
#include <boost/spirit/iterator/multi_pass.hpp>
|
||||
#include <boost/spirit/iterator/position_iterator.hpp>
|
||||
#define spirit_namespace boost::spirit
|
||||
#endif
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
const spirit_namespace::int_parser < boost::int64_t > int64_p = spirit_namespace::int_parser < boost::int64_t >();
|
||||
const spirit_namespace::uint_parser< boost::uint64_t > uint64_p = spirit_namespace::uint_parser< boost::uint64_t >();
|
||||
|
||||
template< class Iter_type >
|
||||
bool is_eq( Iter_type first, Iter_type last, const char* c_str )
|
||||
{
|
||||
for( Iter_type i = first; i != last; ++i, ++c_str )
|
||||
{
|
||||
if( *c_str == 0 ) return false;
|
||||
|
||||
if( *i != *c_str ) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Char_type >
|
||||
Char_type hex_to_num( const Char_type c )
|
||||
{
|
||||
if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0';
|
||||
if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10;
|
||||
if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template< class Char_type, class Iter_type >
|
||||
Char_type hex_str_to_char( Iter_type& begin )
|
||||
{
|
||||
const Char_type c1( *( ++begin ) );
|
||||
const Char_type c2( *( ++begin ) );
|
||||
|
||||
return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 );
|
||||
}
|
||||
|
||||
template< class Char_type, class Iter_type >
|
||||
Char_type unicode_str_to_char( Iter_type& begin )
|
||||
{
|
||||
const Char_type c1( *( ++begin ) );
|
||||
const Char_type c2( *( ++begin ) );
|
||||
const Char_type c3( *( ++begin ) );
|
||||
const Char_type c4( *( ++begin ) );
|
||||
|
||||
return ( hex_to_num( c1 ) << 12 ) +
|
||||
( hex_to_num( c2 ) << 8 ) +
|
||||
( hex_to_num( c3 ) << 4 ) +
|
||||
hex_to_num( c4 );
|
||||
}
|
||||
|
||||
template< class String_type >
|
||||
void append_esc_char_and_incr_iter( String_type& s,
|
||||
typename String_type::const_iterator& begin,
|
||||
typename String_type::const_iterator end )
|
||||
{
|
||||
typedef typename String_type::value_type Char_type;
|
||||
|
||||
const Char_type c2( *begin );
|
||||
|
||||
switch( c2 )
|
||||
{
|
||||
case 't': s += '\t'; break;
|
||||
case 'b': s += '\b'; break;
|
||||
case 'f': s += '\f'; break;
|
||||
case 'n': s += '\n'; break;
|
||||
case 'r': s += '\r'; break;
|
||||
case '\\': s += '\\'; break;
|
||||
case '/': s += '/'; break;
|
||||
case '"': s += '"'; break;
|
||||
case 'x':
|
||||
{
|
||||
if( end - begin >= 3 ) // expecting "xHH..."
|
||||
{
|
||||
s += hex_str_to_char< Char_type >( begin );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
{
|
||||
if( end - begin >= 5 ) // expecting "uHHHH..."
|
||||
{
|
||||
s += unicode_str_to_char< Char_type >( begin );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< class String_type >
|
||||
String_type substitute_esc_chars( typename String_type::const_iterator begin,
|
||||
typename String_type::const_iterator end )
|
||||
{
|
||||
typedef typename String_type::const_iterator Iter_type;
|
||||
|
||||
if( end - begin < 2 ) return String_type( begin, end );
|
||||
|
||||
String_type result;
|
||||
|
||||
result.reserve( end - begin );
|
||||
|
||||
const Iter_type end_minus_1( end - 1 );
|
||||
|
||||
Iter_type substr_start = begin;
|
||||
Iter_type i = begin;
|
||||
|
||||
for( ; i < end_minus_1; ++i )
|
||||
{
|
||||
if( *i == '\\' )
|
||||
{
|
||||
result.append( substr_start, i );
|
||||
|
||||
++i; // skip the '\'
|
||||
|
||||
append_esc_char_and_incr_iter( result, i, end );
|
||||
|
||||
substr_start = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
result.append( substr_start, end );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template< class String_type >
|
||||
String_type get_str_( typename String_type::const_iterator begin,
|
||||
typename String_type::const_iterator end )
|
||||
{
|
||||
assert( end - begin >= 2 );
|
||||
|
||||
typedef typename String_type::const_iterator Iter_type;
|
||||
|
||||
Iter_type str_without_quotes( ++begin );
|
||||
Iter_type end_without_quotes( --end );
|
||||
|
||||
return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes );
|
||||
}
|
||||
|
||||
inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end )
|
||||
{
|
||||
return get_str_< std::string >( begin, end );
|
||||
}
|
||||
|
||||
inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end )
|
||||
{
|
||||
return get_str_< std::wstring >( begin, end );
|
||||
}
|
||||
|
||||
template< class String_type, class Iter_type >
|
||||
String_type get_str( Iter_type begin, Iter_type end )
|
||||
{
|
||||
const String_type tmp( begin, end ); // convert multipass iterators to string iterators
|
||||
|
||||
return get_str( tmp.begin(), tmp.end() );
|
||||
}
|
||||
|
||||
// this class's methods get called by the spirit parse resulting
|
||||
// in the creation of a JSON object or array
|
||||
//
|
||||
// NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator
|
||||
//
|
||||
template< class Value_type, class Iter_type >
|
||||
class Semantic_actions
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename Value_type::Config_type Config_type;
|
||||
typedef typename Config_type::String_type String_type;
|
||||
typedef typename Config_type::Object_type Object_type;
|
||||
typedef typename Config_type::Array_type Array_type;
|
||||
typedef typename String_type::value_type Char_type;
|
||||
|
||||
Semantic_actions( Value_type& value )
|
||||
: value_( value )
|
||||
, current_p_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void begin_obj( Char_type c )
|
||||
{
|
||||
assert( c == '{' );
|
||||
|
||||
begin_compound< Object_type >();
|
||||
}
|
||||
|
||||
void end_obj( Char_type c )
|
||||
{
|
||||
assert( c == '}' );
|
||||
|
||||
end_compound();
|
||||
}
|
||||
|
||||
void begin_array( Char_type c )
|
||||
{
|
||||
assert( c == '[' );
|
||||
|
||||
begin_compound< Array_type >();
|
||||
}
|
||||
|
||||
void end_array( Char_type c )
|
||||
{
|
||||
assert( c == ']' );
|
||||
|
||||
end_compound();
|
||||
}
|
||||
|
||||
void new_name( Iter_type begin, Iter_type end )
|
||||
{
|
||||
assert( current_p_->type() == obj_type );
|
||||
|
||||
name_ = get_str< String_type >( begin, end );
|
||||
}
|
||||
|
||||
void new_str( Iter_type begin, Iter_type end )
|
||||
{
|
||||
add_to_current( get_str< String_type >( begin, end ) );
|
||||
}
|
||||
|
||||
void new_true( Iter_type begin, Iter_type end )
|
||||
{
|
||||
assert( is_eq( begin, end, "true" ) );
|
||||
|
||||
add_to_current( true );
|
||||
}
|
||||
|
||||
void new_false( Iter_type begin, Iter_type end )
|
||||
{
|
||||
assert( is_eq( begin, end, "false" ) );
|
||||
|
||||
add_to_current( false );
|
||||
}
|
||||
|
||||
void new_null( Iter_type begin, Iter_type end )
|
||||
{
|
||||
assert( is_eq( begin, end, "null" ) );
|
||||
|
||||
add_to_current( Value_type() );
|
||||
}
|
||||
|
||||
void new_int( boost::int64_t i )
|
||||
{
|
||||
add_to_current( i );
|
||||
}
|
||||
|
||||
void new_uint64( boost::uint64_t ui )
|
||||
{
|
||||
add_to_current( ui );
|
||||
}
|
||||
|
||||
void new_real( double d )
|
||||
{
|
||||
add_to_current( d );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Semantic_actions& operator=( const Semantic_actions& );
|
||||
// to prevent "assignment operator could not be generated" warning
|
||||
|
||||
Value_type* add_first( const Value_type& value )
|
||||
{
|
||||
assert( current_p_ == 0 );
|
||||
|
||||
value_ = value;
|
||||
current_p_ = &value_;
|
||||
return current_p_;
|
||||
}
|
||||
|
||||
template< class Array_or_obj >
|
||||
void begin_compound()
|
||||
{
|
||||
if( current_p_ == 0 )
|
||||
{
|
||||
add_first( Array_or_obj() );
|
||||
}
|
||||
else
|
||||
{
|
||||
stack_.push_back( current_p_ );
|
||||
|
||||
Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place
|
||||
|
||||
current_p_ = add_to_current( new_array_or_obj );
|
||||
}
|
||||
}
|
||||
|
||||
void end_compound()
|
||||
{
|
||||
if( current_p_ != &value_ )
|
||||
{
|
||||
current_p_ = stack_.back();
|
||||
|
||||
stack_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
Value_type* add_to_current( const Value_type& value )
|
||||
{
|
||||
if( current_p_ == 0 )
|
||||
{
|
||||
return add_first( value );
|
||||
}
|
||||
else if( current_p_->type() == array_type )
|
||||
{
|
||||
current_p_->get_array().push_back( value );
|
||||
|
||||
return ¤t_p_->get_array().back();
|
||||
}
|
||||
|
||||
assert( current_p_->type() == obj_type );
|
||||
|
||||
return &Config_type::add( current_p_->get_obj(), name_, value );
|
||||
}
|
||||
|
||||
Value_type& value_; // this is the object or array that is being created
|
||||
Value_type* current_p_; // the child object or array that is currently being constructed
|
||||
|
||||
std::vector< Value_type* > stack_; // previous child objects and arrays
|
||||
|
||||
String_type name_; // of current name/value pair
|
||||
};
|
||||
|
||||
template< typename Iter_type >
|
||||
void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason )
|
||||
{
|
||||
throw Error_position( i.get_position().line, i.get_position().column, reason );
|
||||
}
|
||||
|
||||
template< typename Iter_type >
|
||||
void throw_error( Iter_type i, const std::string& reason )
|
||||
{
|
||||
throw reason;
|
||||
}
|
||||
|
||||
// the spirit grammer
|
||||
//
|
||||
template< class Value_type, class Iter_type >
|
||||
class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t;
|
||||
|
||||
Json_grammer( Semantic_actions_t& semantic_actions )
|
||||
: actions_( semantic_actions )
|
||||
{
|
||||
}
|
||||
|
||||
static void throw_not_value( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not a value" );
|
||||
}
|
||||
|
||||
static void throw_not_array( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not an array" );
|
||||
}
|
||||
|
||||
static void throw_not_object( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not an object" );
|
||||
}
|
||||
|
||||
static void throw_not_pair( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not a pair" );
|
||||
}
|
||||
|
||||
static void throw_not_colon( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "no colon in pair" );
|
||||
}
|
||||
|
||||
static void throw_not_string( Iter_type begin, Iter_type end )
|
||||
{
|
||||
throw_error( begin, "not a string" );
|
||||
}
|
||||
|
||||
template< typename ScannerT >
|
||||
class definition
|
||||
{
|
||||
public:
|
||||
|
||||
definition( const Json_grammer& self )
|
||||
{
|
||||
using namespace spirit_namespace;
|
||||
|
||||
typedef typename Value_type::String_type::value_type Char_type;
|
||||
|
||||
// first we convert the semantic action class methods to functors with the
|
||||
// parameter signature expected by spirit
|
||||
|
||||
typedef boost::function< void( Char_type ) > Char_action;
|
||||
typedef boost::function< void( Iter_type, Iter_type ) > Str_action;
|
||||
typedef boost::function< void( double ) > Real_action;
|
||||
typedef boost::function< void( boost::int64_t ) > Int_action;
|
||||
typedef boost::function< void( boost::uint64_t ) > Uint64_action;
|
||||
|
||||
Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) );
|
||||
Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) );
|
||||
Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) );
|
||||
Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) );
|
||||
Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) );
|
||||
Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) );
|
||||
Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) );
|
||||
Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) );
|
||||
Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) );
|
||||
Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) );
|
||||
Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) );
|
||||
Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) );
|
||||
|
||||
// actual grammer
|
||||
|
||||
json_
|
||||
= value_ | eps_p[ &throw_not_value ]
|
||||
;
|
||||
|
||||
value_
|
||||
= string_[ new_str ]
|
||||
| number_
|
||||
| object_
|
||||
| array_
|
||||
| str_p( "true" ) [ new_true ]
|
||||
| str_p( "false" )[ new_false ]
|
||||
| str_p( "null" ) [ new_null ]
|
||||
;
|
||||
|
||||
object_
|
||||
= ch_p('{')[ begin_obj ]
|
||||
>> !members_
|
||||
>> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] )
|
||||
;
|
||||
|
||||
members_
|
||||
= pair_ >> *( ',' >> pair_ )
|
||||
;
|
||||
|
||||
pair_
|
||||
= string_[ new_name ]
|
||||
>> ( ':' | eps_p[ &throw_not_colon ] )
|
||||
>> ( value_ | eps_p[ &throw_not_value ] )
|
||||
;
|
||||
|
||||
array_
|
||||
= ch_p('[')[ begin_array ]
|
||||
>> !elements_
|
||||
>> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] )
|
||||
;
|
||||
|
||||
elements_
|
||||
= value_ >> *( ',' >> value_ )
|
||||
;
|
||||
|
||||
string_
|
||||
= lexeme_d // this causes white space inside a string to be retained
|
||||
[
|
||||
confix_p
|
||||
(
|
||||
'"',
|
||||
*lex_escape_ch_p,
|
||||
'"'
|
||||
)
|
||||
]
|
||||
;
|
||||
|
||||
number_
|
||||
= strict_real_p[ new_real ]
|
||||
| int64_p [ new_int ]
|
||||
| uint64_p [ new_uint64 ]
|
||||
;
|
||||
}
|
||||
|
||||
spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_;
|
||||
|
||||
const spirit_namespace::rule< ScannerT >& start() const { return json_; }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning
|
||||
|
||||
Semantic_actions_t& actions_;
|
||||
};
|
||||
|
||||
template< class Iter_type, class Value_type >
|
||||
Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
|
||||
{
|
||||
Semantic_actions< Value_type, Iter_type > semantic_actions( value );
|
||||
|
||||
const spirit_namespace::parse_info< Iter_type > info =
|
||||
spirit_namespace::parse( begin, end,
|
||||
Json_grammer< Value_type, Iter_type >( semantic_actions ),
|
||||
spirit_namespace::space_p );
|
||||
|
||||
if( !info.hit )
|
||||
{
|
||||
assert( false ); // in theory exception should already have been thrown
|
||||
throw_error( info.stop, "error" );
|
||||
}
|
||||
|
||||
return info.stop;
|
||||
}
|
||||
|
||||
template< class Iter_type, class Value_type >
|
||||
void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
|
||||
{
|
||||
typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t;
|
||||
|
||||
const Posn_iter_t posn_begin( begin, end );
|
||||
const Posn_iter_t posn_end( end, end );
|
||||
|
||||
read_range_or_throw( posn_begin, posn_end, value );
|
||||
}
|
||||
|
||||
template< class Iter_type, class Value_type >
|
||||
bool read_range( Iter_type& begin, Iter_type end, Value_type& value )
|
||||
{
|
||||
try
|
||||
{
|
||||
begin = read_range_or_throw( begin, end, value );
|
||||
|
||||
return true;
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template< class String_type, class Value_type >
|
||||
void read_string_or_throw( const String_type& s, Value_type& value )
|
||||
{
|
||||
add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value );
|
||||
}
|
||||
|
||||
template< class String_type, class Value_type >
|
||||
bool read_string( const String_type& s, Value_type& value )
|
||||
{
|
||||
typename String_type::const_iterator begin = s.begin();
|
||||
|
||||
return read_range( begin, s.end(), value );
|
||||
}
|
||||
|
||||
template< class Istream_type >
|
||||
struct Multi_pass_iters
|
||||
{
|
||||
typedef typename Istream_type::char_type Char_type;
|
||||
typedef std::istream_iterator< Char_type, Char_type > istream_iter;
|
||||
typedef spirit_namespace::multi_pass< istream_iter > Mp_iter;
|
||||
|
||||
Multi_pass_iters( Istream_type& is )
|
||||
{
|
||||
is.unsetf( std::ios::skipws );
|
||||
|
||||
begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) );
|
||||
end_ = spirit_namespace::make_multi_pass( istream_iter() );
|
||||
}
|
||||
|
||||
Mp_iter begin_;
|
||||
Mp_iter end_;
|
||||
};
|
||||
|
||||
template< class Istream_type, class Value_type >
|
||||
bool read_stream( Istream_type& is, Value_type& value )
|
||||
{
|
||||
Multi_pass_iters< Istream_type > mp_iters( is );
|
||||
|
||||
return read_range( mp_iters.begin_, mp_iters.end_, value );
|
||||
}
|
||||
|
||||
template< class Istream_type, class Value_type >
|
||||
void read_stream_or_throw( Istream_type& is, Value_type& value )
|
||||
{
|
||||
const Multi_pass_iters< Istream_type > mp_iters( is );
|
||||
|
||||
add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
70
src/json/json_spirit_stream_reader.h
Normal file
70
src/json/json_spirit_stream_reader.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef JSON_SPIRIT_READ_STREAM
|
||||
#define JSON_SPIRIT_READ_STREAM
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "json_spirit_reader_template.h"
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
// these classes allows you to read multiple top level contiguous values from a stream,
|
||||
// the normal stream read functions have a bug that prevent multiple top level values
|
||||
// from being read unless they are separated by spaces
|
||||
|
||||
template< class Istream_type, class Value_type >
|
||||
class Stream_reader
|
||||
{
|
||||
public:
|
||||
|
||||
Stream_reader( Istream_type& is )
|
||||
: iters_( is )
|
||||
{
|
||||
}
|
||||
|
||||
bool read_next( Value_type& value )
|
||||
{
|
||||
return read_range( iters_.begin_, iters_.end_, value );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typedef Multi_pass_iters< Istream_type > Mp_iters;
|
||||
|
||||
Mp_iters iters_;
|
||||
};
|
||||
|
||||
template< class Istream_type, class Value_type >
|
||||
class Stream_reader_thrower
|
||||
{
|
||||
public:
|
||||
|
||||
Stream_reader_thrower( Istream_type& is )
|
||||
: iters_( is )
|
||||
, posn_begin_( iters_.begin_, iters_.end_ )
|
||||
, posn_end_( iters_.end_, iters_.end_ )
|
||||
{
|
||||
}
|
||||
|
||||
void read_next( Value_type& value )
|
||||
{
|
||||
posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typedef Multi_pass_iters< Istream_type > Mp_iters;
|
||||
typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t;
|
||||
|
||||
Mp_iters iters_;
|
||||
Posn_iter_t posn_begin_, posn_end_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
61
src/json/json_spirit_utils.h
Normal file
61
src/json/json_spirit_utils.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef JSON_SPIRIT_UTILS
|
||||
#define JSON_SPIRIT_UTILS
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
#include <map>
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
template< class Obj_t, class Map_t >
|
||||
void obj_to_map( const Obj_t& obj, Map_t& mp_obj )
|
||||
{
|
||||
mp_obj.clear();
|
||||
|
||||
for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i )
|
||||
{
|
||||
mp_obj[ i->name_ ] = i->value_;
|
||||
}
|
||||
}
|
||||
|
||||
template< class Obj_t, class Map_t >
|
||||
void map_to_obj( const Map_t& mp_obj, Obj_t& obj )
|
||||
{
|
||||
obj.clear();
|
||||
|
||||
for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i )
|
||||
{
|
||||
obj.push_back( typename Obj_t::value_type( i->first, i->second ) );
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::map< std::string, Value > Mapped_obj;
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
typedef std::map< std::wstring, wValue > wMapped_obj;
|
||||
#endif
|
||||
|
||||
template< class Object_type, class String_type >
|
||||
const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name )
|
||||
{
|
||||
for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i )
|
||||
{
|
||||
if( i->name_ == name )
|
||||
{
|
||||
return i->value_;
|
||||
}
|
||||
}
|
||||
|
||||
return Object_type::value_type::Value_type::null;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
8
src/json/json_spirit_value.cpp
Normal file
8
src/json/json_spirit_value.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
/* Copyright (c) 2007 John W Wilkinson
|
||||
|
||||
This source code can be used for any purpose as long as
|
||||
this comment is retained. */
|
||||
|
||||
// json spirit version 2.00
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
534
src/json/json_spirit_value.h
Normal file
534
src/json/json_spirit_value.h
Normal file
@@ -0,0 +1,534 @@
|
||||
#ifndef JSON_SPIRIT_VALUE
|
||||
#define JSON_SPIRIT_VALUE
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type };
|
||||
static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"};
|
||||
|
||||
template< class Config > // Config determines whether the value uses std::string or std::wstring and
|
||||
// whether JSON Objects are represented as vectors or maps
|
||||
class Value_impl
|
||||
{
|
||||
public:
|
||||
|
||||
typedef Config Config_type;
|
||||
typedef typename Config::String_type String_type;
|
||||
typedef typename Config::Object_type Object;
|
||||
typedef typename Config::Array_type Array;
|
||||
typedef typename String_type::const_pointer Const_str_ptr; // eg const char*
|
||||
|
||||
Value_impl(); // creates null value
|
||||
Value_impl( Const_str_ptr value );
|
||||
Value_impl( const String_type& value );
|
||||
Value_impl( const Object& value );
|
||||
Value_impl( const Array& value );
|
||||
Value_impl( bool value );
|
||||
Value_impl( int value );
|
||||
Value_impl( boost::int64_t value );
|
||||
Value_impl( boost::uint64_t value );
|
||||
Value_impl( double value );
|
||||
|
||||
Value_impl( const Value_impl& other );
|
||||
|
||||
bool operator==( const Value_impl& lhs ) const;
|
||||
|
||||
Value_impl& operator=( const Value_impl& lhs );
|
||||
|
||||
Value_type type() const;
|
||||
|
||||
bool is_uint64() const;
|
||||
bool is_null() const;
|
||||
|
||||
const String_type& get_str() const;
|
||||
const Object& get_obj() const;
|
||||
const Array& get_array() const;
|
||||
bool get_bool() const;
|
||||
int get_int() const;
|
||||
boost::int64_t get_int64() const;
|
||||
boost::uint64_t get_uint64() const;
|
||||
double get_real() const;
|
||||
|
||||
Object& get_obj();
|
||||
Array& get_array();
|
||||
|
||||
template< typename T > T get_value() const; // example usage: int i = value.get_value< int >();
|
||||
// or double d = value.get_value< double >();
|
||||
|
||||
static const Value_impl null;
|
||||
|
||||
private:
|
||||
|
||||
void check_type( const Value_type vtype ) const;
|
||||
|
||||
typedef boost::variant< String_type,
|
||||
boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >,
|
||||
bool, boost::int64_t, double > Variant;
|
||||
|
||||
Value_type type_;
|
||||
Variant v_;
|
||||
bool is_uint64_;
|
||||
};
|
||||
|
||||
// vector objects
|
||||
|
||||
template< class Config >
|
||||
struct Pair_impl
|
||||
{
|
||||
typedef typename Config::String_type String_type;
|
||||
typedef typename Config::Value_type Value_type;
|
||||
|
||||
Pair_impl( const String_type& name, const Value_type& value );
|
||||
|
||||
bool operator==( const Pair_impl& lhs ) const;
|
||||
|
||||
String_type name_;
|
||||
Value_type value_;
|
||||
};
|
||||
|
||||
template< class String >
|
||||
struct Config_vector
|
||||
{
|
||||
typedef String String_type;
|
||||
typedef Value_impl< Config_vector > Value_type;
|
||||
typedef Pair_impl < Config_vector > Pair_type;
|
||||
typedef std::vector< Value_type > Array_type;
|
||||
typedef std::vector< Pair_type > Object_type;
|
||||
|
||||
static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value )
|
||||
{
|
||||
obj.push_back( Pair_type( name , value ) );
|
||||
|
||||
return obj.back().value_;
|
||||
}
|
||||
|
||||
static String_type get_name( const Pair_type& pair )
|
||||
{
|
||||
return pair.name_;
|
||||
}
|
||||
|
||||
static Value_type get_value( const Pair_type& pair )
|
||||
{
|
||||
return pair.value_;
|
||||
}
|
||||
};
|
||||
|
||||
// typedefs for ASCII
|
||||
|
||||
typedef Config_vector< std::string > Config;
|
||||
|
||||
typedef Config::Value_type Value;
|
||||
typedef Config::Pair_type Pair;
|
||||
typedef Config::Object_type Object;
|
||||
typedef Config::Array_type Array;
|
||||
|
||||
// typedefs for Unicode
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
|
||||
typedef Config_vector< std::wstring > wConfig;
|
||||
|
||||
typedef wConfig::Value_type wValue;
|
||||
typedef wConfig::Pair_type wPair;
|
||||
typedef wConfig::Object_type wObject;
|
||||
typedef wConfig::Array_type wArray;
|
||||
#endif
|
||||
|
||||
// map objects
|
||||
|
||||
template< class String >
|
||||
struct Config_map
|
||||
{
|
||||
typedef String String_type;
|
||||
typedef Value_impl< Config_map > Value_type;
|
||||
typedef std::vector< Value_type > Array_type;
|
||||
typedef std::map< String_type, Value_type > Object_type;
|
||||
typedef typename Object_type::value_type Pair_type;
|
||||
|
||||
static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value )
|
||||
{
|
||||
return obj[ name ] = value;
|
||||
}
|
||||
|
||||
static String_type get_name( const Pair_type& pair )
|
||||
{
|
||||
return pair.first;
|
||||
}
|
||||
|
||||
static Value_type get_value( const Pair_type& pair )
|
||||
{
|
||||
return pair.second;
|
||||
}
|
||||
};
|
||||
|
||||
// typedefs for ASCII
|
||||
|
||||
typedef Config_map< std::string > mConfig;
|
||||
|
||||
typedef mConfig::Value_type mValue;
|
||||
typedef mConfig::Object_type mObject;
|
||||
typedef mConfig::Array_type mArray;
|
||||
|
||||
// typedefs for Unicode
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
|
||||
typedef Config_map< std::wstring > wmConfig;
|
||||
|
||||
typedef wmConfig::Value_type wmValue;
|
||||
typedef wmConfig::Object_type wmObject;
|
||||
typedef wmConfig::Array_type wmArray;
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// implementation
|
||||
|
||||
template< class Config >
|
||||
const Value_impl< Config > Value_impl< Config >::null;
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl()
|
||||
: type_( null_type )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( const Const_str_ptr value )
|
||||
: type_( str_type )
|
||||
, v_( String_type( value ) )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( const String_type& value )
|
||||
: type_( str_type )
|
||||
, v_( value )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( const Object& value )
|
||||
: type_( obj_type )
|
||||
, v_( value )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( const Array& value )
|
||||
: type_( array_type )
|
||||
, v_( value )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( bool value )
|
||||
: type_( bool_type )
|
||||
, v_( value )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( int value )
|
||||
: type_( int_type )
|
||||
, v_( static_cast< boost::int64_t >( value ) )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( boost::int64_t value )
|
||||
: type_( int_type )
|
||||
, v_( value )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( boost::uint64_t value )
|
||||
: type_( int_type )
|
||||
, v_( static_cast< boost::int64_t >( value ) )
|
||||
, is_uint64_( true )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( double value )
|
||||
: type_( real_type )
|
||||
, v_( value )
|
||||
, is_uint64_( false )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >::Value_impl( const Value_impl< Config >& other )
|
||||
: type_( other.type() )
|
||||
, v_( other.v_ )
|
||||
, is_uint64_( other.is_uint64_ )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs )
|
||||
{
|
||||
Value_impl tmp( lhs );
|
||||
|
||||
std::swap( type_, tmp.type_ );
|
||||
std::swap( v_, tmp.v_ );
|
||||
std::swap( is_uint64_, tmp.is_uint64_ );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
bool Value_impl< Config >::operator==( const Value_impl& lhs ) const
|
||||
{
|
||||
if( this == &lhs ) return true;
|
||||
|
||||
if( type() != lhs.type() ) return false;
|
||||
|
||||
return v_ == lhs.v_;
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Value_type Value_impl< Config >::type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
bool Value_impl< Config >::is_uint64() const
|
||||
{
|
||||
return is_uint64_;
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
bool Value_impl< Config >::is_null() const
|
||||
{
|
||||
return type() == null_type;
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
void Value_impl< Config >::check_type( const Value_type vtype ) const
|
||||
{
|
||||
if( type() != vtype )
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
///// Bitcoin: Tell the types by name instead of by number
|
||||
os << "value is type " << Value_type_name[type()] << ", expected " << Value_type_name[vtype];
|
||||
|
||||
throw std::runtime_error( os.str() );
|
||||
}
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
const typename Config::String_type& Value_impl< Config >::get_str() const
|
||||
{
|
||||
check_type( str_type );
|
||||
|
||||
return *boost::get< String_type >( &v_ );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const
|
||||
{
|
||||
check_type( obj_type );
|
||||
|
||||
return *boost::get< Object >( &v_ );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const
|
||||
{
|
||||
check_type( array_type );
|
||||
|
||||
return *boost::get< Array >( &v_ );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
bool Value_impl< Config >::get_bool() const
|
||||
{
|
||||
check_type( bool_type );
|
||||
|
||||
return boost::get< bool >( v_ );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
int Value_impl< Config >::get_int() const
|
||||
{
|
||||
check_type( int_type );
|
||||
|
||||
return static_cast< int >( get_int64() );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
boost::int64_t Value_impl< Config >::get_int64() const
|
||||
{
|
||||
check_type( int_type );
|
||||
|
||||
return boost::get< boost::int64_t >( v_ );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
boost::uint64_t Value_impl< Config >::get_uint64() const
|
||||
{
|
||||
check_type( int_type );
|
||||
|
||||
return static_cast< boost::uint64_t >( get_int64() );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
double Value_impl< Config >::get_real() const
|
||||
{
|
||||
if( type() == int_type )
|
||||
{
|
||||
return is_uint64() ? static_cast< double >( get_uint64() )
|
||||
: static_cast< double >( get_int64() );
|
||||
}
|
||||
|
||||
check_type( real_type );
|
||||
|
||||
return boost::get< double >( v_ );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
typename Value_impl< Config >::Object& Value_impl< Config >::get_obj()
|
||||
{
|
||||
check_type( obj_type );
|
||||
|
||||
return *boost::get< Object >( &v_ );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
typename Value_impl< Config >::Array& Value_impl< Config >::get_array()
|
||||
{
|
||||
check_type( array_type );
|
||||
|
||||
return *boost::get< Array >( &v_ );
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value )
|
||||
: name_( name )
|
||||
, value_( value )
|
||||
{
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const
|
||||
{
|
||||
if( this == &lhs ) return true;
|
||||
|
||||
return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ );
|
||||
}
|
||||
|
||||
// converts a C string, ie. 8 bit char array, to a string object
|
||||
//
|
||||
template < class String_type >
|
||||
String_type to_str( const char* c_str )
|
||||
{
|
||||
String_type result;
|
||||
|
||||
for( const char* p = c_str; *p != 0; ++p )
|
||||
{
|
||||
result += *p;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
namespace internal_
|
||||
{
|
||||
template< typename T >
|
||||
struct Type_to_type
|
||||
{
|
||||
};
|
||||
|
||||
template< class Value >
|
||||
int get_value( const Value& value, Type_to_type< int > )
|
||||
{
|
||||
return value.get_int();
|
||||
}
|
||||
|
||||
template< class Value >
|
||||
boost::int64_t get_value( const Value& value, Type_to_type< boost::int64_t > )
|
||||
{
|
||||
return value.get_int64();
|
||||
}
|
||||
|
||||
template< class Value >
|
||||
boost::uint64_t get_value( const Value& value, Type_to_type< boost::uint64_t > )
|
||||
{
|
||||
return value.get_uint64();
|
||||
}
|
||||
|
||||
template< class Value >
|
||||
double get_value( const Value& value, Type_to_type< double > )
|
||||
{
|
||||
return value.get_real();
|
||||
}
|
||||
|
||||
template< class Value >
|
||||
typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > )
|
||||
{
|
||||
return value.get_str();
|
||||
}
|
||||
|
||||
template< class Value >
|
||||
typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > )
|
||||
{
|
||||
return value.get_array();
|
||||
}
|
||||
|
||||
template< class Value >
|
||||
typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > )
|
||||
{
|
||||
return value.get_obj();
|
||||
}
|
||||
|
||||
template< class Value >
|
||||
bool get_value( const Value& value, Type_to_type< bool > )
|
||||
{
|
||||
return value.get_bool();
|
||||
}
|
||||
}
|
||||
|
||||
template< class Config >
|
||||
template< typename T >
|
||||
T Value_impl< Config >::get_value() const
|
||||
{
|
||||
return internal_::get_value( *this, internal_::Type_to_type< T >() );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
95
src/json/json_spirit_writer.cpp
Normal file
95
src/json/json_spirit_writer.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#include "json_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
|
||||
50
src/json/json_spirit_writer.h
Normal file
50
src/json/json_spirit_writer.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef JSON_SPIRIT_WRITER
|
||||
#define JSON_SPIRIT_WRITER
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
// functions to convert JSON Values to text,
|
||||
// the "formatted" versions add whitespace to format the output nicely
|
||||
|
||||
void write ( const Value& value, std::ostream& os );
|
||||
void write_formatted( const Value& value, std::ostream& os );
|
||||
std::string write ( const Value& value );
|
||||
std::string write_formatted( const Value& value );
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
|
||||
void write ( const wValue& value, std::wostream& os );
|
||||
void write_formatted( const wValue& value, std::wostream& os );
|
||||
std::wstring write ( const wValue& value );
|
||||
std::wstring write_formatted( const wValue& value );
|
||||
|
||||
#endif
|
||||
|
||||
void write ( const mValue& value, std::ostream& os );
|
||||
void write_formatted( const mValue& value, std::ostream& os );
|
||||
std::string write ( const mValue& value );
|
||||
std::string write_formatted( const mValue& value );
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
|
||||
void write ( const wmValue& value, std::wostream& os );
|
||||
void write_formatted( const wmValue& value, std::wostream& os );
|
||||
std::wstring write ( const wmValue& value );
|
||||
std::wstring write_formatted( const wmValue& value );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
248
src/json/json_spirit_writer_template.h
Normal file
248
src/json/json_spirit_writer_template.h
Normal file
@@ -0,0 +1,248 @@
|
||||
#ifndef JSON_SPIRIT_WRITER_TEMPLATE
|
||||
#define JSON_SPIRIT_WRITER_TEMPLATE
|
||||
|
||||
// Copyright John W. Wilkinson 2007 - 2009.
|
||||
// Distributed under the MIT License, see accompanying file LICENSE.txt
|
||||
|
||||
// json spirit version 4.03
|
||||
|
||||
#include "json_spirit_value.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace json_spirit
|
||||
{
|
||||
inline char to_hex_char( unsigned int c )
|
||||
{
|
||||
assert( c <= 0xF );
|
||||
|
||||
const char ch = static_cast< char >( c );
|
||||
|
||||
if( ch < 10 ) return '0' + ch;
|
||||
|
||||
return 'A' - 10 + ch;
|
||||
}
|
||||
|
||||
template< class String_type >
|
||||
String_type non_printable_to_string( unsigned int c )
|
||||
{
|
||||
typedef typename String_type::value_type Char_type;
|
||||
|
||||
String_type result( 6, '\\' );
|
||||
|
||||
result[1] = 'u';
|
||||
|
||||
result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4;
|
||||
result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4;
|
||||
result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4;
|
||||
result[ 2 ] = to_hex_char( c & 0x000F );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template< typename Char_type, class String_type >
|
||||
bool add_esc_char( Char_type c, String_type& s )
|
||||
{
|
||||
switch( c )
|
||||
{
|
||||
case '"': s += to_str< String_type >( "\\\"" ); return true;
|
||||
case '\\': s += to_str< String_type >( "\\\\" ); return true;
|
||||
case '\b': s += to_str< String_type >( "\\b" ); return true;
|
||||
case '\f': s += to_str< String_type >( "\\f" ); return true;
|
||||
case '\n': s += to_str< String_type >( "\\n" ); return true;
|
||||
case '\r': s += to_str< String_type >( "\\r" ); return true;
|
||||
case '\t': s += to_str< String_type >( "\\t" ); return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template< class String_type >
|
||||
String_type add_esc_chars( const String_type& s )
|
||||
{
|
||||
typedef typename String_type::const_iterator Iter_type;
|
||||
typedef typename String_type::value_type Char_type;
|
||||
|
||||
String_type result;
|
||||
|
||||
const Iter_type end( s.end() );
|
||||
|
||||
for( Iter_type i = s.begin(); i != end; ++i )
|
||||
{
|
||||
const Char_type c( *i );
|
||||
|
||||
if( add_esc_char( c, result ) ) continue;
|
||||
|
||||
const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );
|
||||
|
||||
if( iswprint( unsigned_c ) )
|
||||
{
|
||||
result += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += non_printable_to_string< String_type >( unsigned_c );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// this class generates the JSON text,
|
||||
// it keeps track of the indentation level etc.
|
||||
//
|
||||
template< class Value_type, class Ostream_type >
|
||||
class Generator
|
||||
{
|
||||
typedef typename Value_type::Config_type Config_type;
|
||||
typedef typename Config_type::String_type String_type;
|
||||
typedef typename Config_type::Object_type Object_type;
|
||||
typedef typename Config_type::Array_type Array_type;
|
||||
typedef typename String_type::value_type Char_type;
|
||||
typedef typename Object_type::value_type Obj_member_type;
|
||||
|
||||
public:
|
||||
|
||||
Generator( const Value_type& value, Ostream_type& os, bool pretty )
|
||||
: os_( os )
|
||||
, indentation_level_( 0 )
|
||||
, pretty_( pretty )
|
||||
{
|
||||
output( value );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void output( const Value_type& value )
|
||||
{
|
||||
switch( value.type() )
|
||||
{
|
||||
case obj_type: output( value.get_obj() ); break;
|
||||
case array_type: output( value.get_array() ); break;
|
||||
case str_type: output( value.get_str() ); break;
|
||||
case bool_type: output( value.get_bool() ); break;
|
||||
case int_type: output_int( value ); break;
|
||||
|
||||
/// Bitcoin: Added std::fixed and changed precision from 16 to 8
|
||||
case real_type: os_ << std::showpoint << std::fixed << std::setprecision(8)
|
||||
<< value.get_real(); break;
|
||||
|
||||
case null_type: os_ << "null"; break;
|
||||
default: assert( false );
|
||||
}
|
||||
}
|
||||
|
||||
void output( const Object_type& obj )
|
||||
{
|
||||
output_array_or_obj( obj, '{', '}' );
|
||||
}
|
||||
|
||||
void output( const Array_type& arr )
|
||||
{
|
||||
output_array_or_obj( arr, '[', ']' );
|
||||
}
|
||||
|
||||
void output( const Obj_member_type& member )
|
||||
{
|
||||
output( Config_type::get_name( member ) ); space();
|
||||
os_ << ':'; space();
|
||||
output( Config_type::get_value( member ) );
|
||||
}
|
||||
|
||||
void output_int( const Value_type& value )
|
||||
{
|
||||
if( value.is_uint64() )
|
||||
{
|
||||
os_ << value.get_uint64();
|
||||
}
|
||||
else
|
||||
{
|
||||
os_ << value.get_int64();
|
||||
}
|
||||
}
|
||||
|
||||
void output( const String_type& s )
|
||||
{
|
||||
os_ << '"' << add_esc_chars( s ) << '"';
|
||||
}
|
||||
|
||||
void output( bool b )
|
||||
{
|
||||
os_ << to_str< String_type >( b ? "true" : "false" );
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char )
|
||||
{
|
||||
os_ << start_char; new_line();
|
||||
|
||||
++indentation_level_;
|
||||
|
||||
for( typename T::const_iterator i = t.begin(); i != t.end(); ++i )
|
||||
{
|
||||
indent(); output( *i );
|
||||
|
||||
typename T::const_iterator next = i;
|
||||
|
||||
if( ++next != t.end())
|
||||
{
|
||||
os_ << ',';
|
||||
}
|
||||
|
||||
new_line();
|
||||
}
|
||||
|
||||
--indentation_level_;
|
||||
|
||||
indent(); os_ << end_char;
|
||||
}
|
||||
|
||||
void indent()
|
||||
{
|
||||
if( !pretty_ ) return;
|
||||
|
||||
for( int i = 0; i < indentation_level_; ++i )
|
||||
{
|
||||
os_ << " ";
|
||||
}
|
||||
}
|
||||
|
||||
void space()
|
||||
{
|
||||
if( pretty_ ) os_ << ' ';
|
||||
}
|
||||
|
||||
void new_line()
|
||||
{
|
||||
if( pretty_ ) os_ << '\n';
|
||||
}
|
||||
|
||||
Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning
|
||||
|
||||
Ostream_type& os_;
|
||||
int indentation_level_;
|
||||
bool pretty_;
|
||||
};
|
||||
|
||||
template< class Value_type, class Ostream_type >
|
||||
void write_stream( const Value_type& value, Ostream_type& os, bool pretty )
|
||||
{
|
||||
Generator< Value_type, Ostream_type >( value, os, pretty );
|
||||
}
|
||||
|
||||
template< class Value_type >
|
||||
typename Value_type::String_type write_string( const Value_type& value, bool pretty )
|
||||
{
|
||||
typedef typename Value_type::String_type::value_type Char_type;
|
||||
|
||||
std::basic_ostringstream< Char_type > os;
|
||||
|
||||
write_stream( value, os, pretty );
|
||||
|
||||
return os.str();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
387
src/key.cpp
Normal file
387
src/key.cpp
Normal 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
164
src/key.h
Normal 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
223
src/keystore.cpp
Normal 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
186
src/keystore.h
Normal 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
3883
src/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1640
src/main.h
Normal file
1640
src/main.h
Normal file
File diff suppressed because it is too large
Load Diff
105
src/makefile.linux-mingw
Normal file
105
src/makefile.linux-mingw
Normal 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
95
src/makefile.mingw
Normal 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
154
src/makefile.osx
Normal 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
167
src/makefile.unix
Normal 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
65
src/mruset.h
Normal 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
1983
src/net.cpp
Normal file
File diff suppressed because it is too large
Load Diff
692
src/net.h
Normal file
692
src/net.h
Normal 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
1165
src/netbase.cpp
Normal file
File diff suppressed because it is too large
Load Diff
153
src/netbase.h
Normal file
153
src/netbase.h
Normal 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
30
src/noui.cpp
Normal 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
152
src/protocol.cpp
Normal 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
139
src/protocol.h
Normal 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
30
src/qt/aboutdialog.cpp
Normal 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
28
src/qt/aboutdialog.h
Normal 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
374
src/qt/addressbookpage.cpp
Normal 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
85
src/qt/addressbookpage.h
Normal 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
|
||||
406
src/qt/addresstablemodel.cpp
Normal file
406
src/qt/addresstablemodel.cpp
Normal 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()));
|
||||
}
|
||||
91
src/qt/addresstablemodel.h
Normal file
91
src/qt/addresstablemodel.h
Normal 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
|
||||
239
src/qt/askpassphrasedialog.cpp
Normal file
239
src/qt/askpassphrasedialog.cpp
Normal 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;
|
||||
}
|
||||
45
src/qt/askpassphrasedialog.h
Normal file
45
src/qt/askpassphrasedialog.h
Normal 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
316
src/qt/bitcoin.cpp
Normal 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
89
src/qt/bitcoin.qrc
Normal 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>
|
||||
77
src/qt/bitcoinaddressvalidator.cpp
Normal file
77
src/qt/bitcoinaddressvalidator.cpp
Normal 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;
|
||||
}
|
||||
24
src/qt/bitcoinaddressvalidator.h
Normal file
24
src/qt/bitcoinaddressvalidator.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef BITCOINADDRESSVALIDATOR_H
|
||||
#define BITCOINADDRESSVALIDATOR_H
|
||||
|
||||
#include <QRegExpValidator>
|
||||
|
||||
/** Base48 entry widget validator.
|
||||
Corrects near-miss characters and refuses characters that are no part of base48.
|
||||
*/
|
||||
class BitcoinAddressValidator : public QValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BitcoinAddressValidator(QObject *parent = 0);
|
||||
|
||||
State validate(QString &input, int &pos) const;
|
||||
|
||||
static const int MaxAddressLength = 35;
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
#endif // BITCOINADDRESSVALIDATOR_H
|
||||
168
src/qt/bitcoinamountfield.cpp
Normal file
168
src/qt/bitcoinamountfield.cpp
Normal 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);
|
||||
}
|
||||
60
src/qt/bitcoinamountfield.h
Normal file
60
src/qt/bitcoinamountfield.h
Normal 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
919
src/qt/bitcoingui.cpp
Normal 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
180
src/qt/bitcoingui.h
Normal 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
148
src/qt/bitcoinstrings.cpp
Normal 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
181
src/qt/bitcoinunits.cpp
Normal 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
66
src/qt/bitcoinunits.h
Normal 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
209
src/qt/clientmodel.cpp
Normal 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
75
src/qt/clientmodel.h
Normal 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
88
src/qt/csvmodelwriter.cpp
Normal 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
46
src/qt/csvmodelwriter.h
Normal 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
|
||||
128
src/qt/editaddressdialog.cpp
Normal file
128
src/qt/editaddressdialog.cpp
Normal 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);
|
||||
}
|
||||
50
src/qt/editaddressdialog.h
Normal file
50
src/qt/editaddressdialog.h
Normal 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
183
src/qt/forms/aboutdialog.ui
Normal 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><b>CasinoCoin</b> 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>
|
||||
175
src/qt/forms/addressbookpage.ui
Normal file
175
src/qt/forms/addressbookpage.ui
Normal 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>&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>&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 &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>&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>&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>&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>
|
||||
151
src/qt/forms/askpassphrasedialog.ui
Normal file
151
src/qt/forms/askpassphrasedialog.ui
Normal 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>
|
||||
105
src/qt/forms/editaddressdialog.ui
Normal file
105
src/qt/forms/editaddressdialog.ui
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditAddressDialog</class>
|
||||
<widget class="QDialog" name="EditAddressDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>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>&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>&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>
|
||||
466
src/qt/forms/optionsdialog.ui
Normal file
466
src/qt/forms/optionsdialog.ui
Normal 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>&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 &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>&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>&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>&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 &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>&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 &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>&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 &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>&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>&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&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>&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 &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>&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>&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>&OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>&Cancel</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="applyButton">
|
||||
<property name="text">
|
||||
<string>&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>
|
||||
320
src/qt/forms/overviewpage.ui
Normal file
320
src/qt/forms/overviewpage.ui
Normal 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><b>Recent transactions</b></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>
|
||||
212
src/qt/forms/qrcodedialog.ui
Normal file
212
src/qt/forms/qrcodedialog.ui
Normal 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>&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
436
src/qt/forms/rpcconsole.ui
Normal 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>&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>&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>&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>&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">></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>
|
||||
175
src/qt/forms/sendcoinsdialog.ui
Normal file
175
src/qt/forms/sendcoinsdialog.ui
Normal 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>&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 &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>&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>
|
||||
169
src/qt/forms/sendcoinsentry.ui
Normal file
169
src/qt/forms/sendcoinsentry.ui
Normal 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&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 &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>&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>
|
||||
386
src/qt/forms/signverifymessagedialog.ui
Normal file
386
src/qt/forms/signverifymessagedialog.ui
Normal 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>&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>&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 &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>&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>&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 &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>
|
||||
74
src/qt/forms/transactiondescdialog.ui
Normal file
74
src/qt/forms/transactiondescdialog.ui
Normal 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
34
src/qt/guiconstants.h
Normal 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
463
src/qt/guiutil.cpp
Normal 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
120
src/qt/guiutil.h
Normal 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
2500
src/qt/locale/bitcoin_bg.ts
Normal file
File diff suppressed because it is too large
Load Diff
2499
src/qt/locale/bitcoin_ca_ES.ts
Normal file
2499
src/qt/locale/bitcoin_ca_ES.ts
Normal file
File diff suppressed because it is too large
Load Diff
2520
src/qt/locale/bitcoin_cs.ts
Normal file
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
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
2518
src/qt/locale/bitcoin_de.ts
Normal file
File diff suppressed because it is too large
Load Diff
2521
src/qt/locale/bitcoin_el_GR.ts
Normal file
2521
src/qt/locale/bitcoin_el_GR.ts
Normal file
File diff suppressed because it is too large
Load Diff
2086
src/qt/locale/bitcoin_en.ts
Normal file
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
2540
src/qt/locale/bitcoin_es.ts
Normal file
File diff suppressed because it is too large
Load Diff
2538
src/qt/locale/bitcoin_es_CL.ts
Normal file
2538
src/qt/locale/bitcoin_es_CL.ts
Normal file
File diff suppressed because it is too large
Load Diff
2499
src/qt/locale/bitcoin_et.ts
Normal file
2499
src/qt/locale/bitcoin_et.ts
Normal file
File diff suppressed because it is too large
Load Diff
2499
src/qt/locale/bitcoin_eu_ES.ts
Normal file
2499
src/qt/locale/bitcoin_eu_ES.ts
Normal file
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
Reference in New Issue
Block a user