mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-20 18:45:55 +00:00
.
This commit is contained in:
@@ -5,6 +5,9 @@
|
|||||||
#include "TimingService.h"
|
#include "TimingService.h"
|
||||||
#include "ValidationCollection.h"
|
#include "ValidationCollection.h"
|
||||||
#include "Wallet.h"
|
#include "Wallet.h"
|
||||||
|
#include "Serializer.h"
|
||||||
|
#include "database/database.h"
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
class RPCDoor;
|
class RPCDoor;
|
||||||
@@ -18,12 +21,14 @@ class Application
|
|||||||
KnownNodeList mKnownNodes;
|
KnownNodeList mKnownNodes;
|
||||||
Wallet mWallet;
|
Wallet mWallet;
|
||||||
ValidationCollection mValidations;
|
ValidationCollection mValidations;
|
||||||
|
Database* mDatabase;
|
||||||
|
|
||||||
LedgerMaster mLedgerMaster;
|
LedgerMaster mLedgerMaster;
|
||||||
|
|
||||||
ConnectionPool mConnectionPool;
|
ConnectionPool mConnectionPool;
|
||||||
PeerDoor* mPeerDoor;
|
PeerDoor* mPeerDoor;
|
||||||
RPCDoor* mRPCDoor;
|
RPCDoor* mRPCDoor;
|
||||||
|
Serializer* mSerializer;
|
||||||
|
|
||||||
boost::asio::io_service mIOService;
|
boost::asio::io_service mIOService;
|
||||||
|
|
||||||
@@ -37,6 +42,12 @@ public:
|
|||||||
UniqueNodeList& getUNL(){ return(mUNL); }
|
UniqueNodeList& getUNL(){ return(mUNL); }
|
||||||
ValidationCollection& getValidationCollection(){ return(mValidations); }
|
ValidationCollection& getValidationCollection(){ return(mValidations); }
|
||||||
Wallet& getWallet(){ return(mWallet); }
|
Wallet& getWallet(){ return(mWallet); }
|
||||||
|
Database* getDB(){ return(mDatabase); }
|
||||||
|
|
||||||
|
void setDatabase(Database* db){ mDatabase=db; }
|
||||||
|
|
||||||
|
Serializer* getSerializer(){ return(mSerializer); }
|
||||||
|
void setSerializer(Serializer* ser){ mSerializer=ser; }
|
||||||
|
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|||||||
12
Config.cpp
12
Config.cpp
@@ -1,5 +1,8 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "util/pugixml.hpp"
|
#include "util/pugixml.hpp"
|
||||||
|
#include "Application.h"
|
||||||
|
#include "database/SqliteDatabase.h"
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
using namespace pugi;
|
using namespace pugi;
|
||||||
@@ -50,5 +53,14 @@ void Config::load()
|
|||||||
node= root.child("RPC_PORT");
|
node= root.child("RPC_PORT");
|
||||||
if(!node.empty()) RPC_PORT=boost::lexical_cast<int>(node.child_value());
|
if(!node.empty()) RPC_PORT=boost::lexical_cast<int>(node.child_value());
|
||||||
|
|
||||||
|
/*
|
||||||
|
node=root.child("DB_TYPE");
|
||||||
|
if(!node.empty())
|
||||||
|
{
|
||||||
|
if( stricmp(node.child_value(),"mysql")==0 ) theApp->setDB(Database::newMysqlDatabase("host","user","pass"));
|
||||||
|
else theApp->setSerializer(new DiskSerializer());
|
||||||
|
}else */
|
||||||
|
theApp->setDB(new SqliteDatabase());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
45
Ledger.cpp
45
Ledger.cpp
@@ -11,6 +11,13 @@
|
|||||||
using namespace boost;
|
using namespace boost;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
Ledger::Ledger()
|
||||||
|
{
|
||||||
|
mIndex=0;
|
||||||
|
mValidSig=false;
|
||||||
|
mValidHash=false;
|
||||||
|
mValidationSeqNum=0;
|
||||||
|
}
|
||||||
|
|
||||||
Ledger::Ledger(uint32 index)
|
Ledger::Ledger(uint32 index)
|
||||||
{
|
{
|
||||||
@@ -20,6 +27,15 @@ Ledger::Ledger(uint32 index)
|
|||||||
mValidationSeqNum=0;
|
mValidationSeqNum=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ledger::Ledger(Ledger::pointer other)
|
||||||
|
{
|
||||||
|
mValidSig=false;
|
||||||
|
mValidHash=false;
|
||||||
|
mValidationSeqNum=0;
|
||||||
|
mIndex=other->getIndex();
|
||||||
|
mergeIn(other);
|
||||||
|
}
|
||||||
|
|
||||||
Ledger::Ledger(newcoin::FullLedger& ledger)
|
Ledger::Ledger(newcoin::FullLedger& ledger)
|
||||||
{
|
{
|
||||||
setTo(ledger);
|
setTo(ledger);
|
||||||
@@ -28,10 +44,10 @@ Ledger::Ledger(newcoin::FullLedger& ledger)
|
|||||||
// TODO: we should probably make a shared pointer type for each of these PB types
|
// TODO: we should probably make a shared pointer type for each of these PB types
|
||||||
newcoin::FullLedger* Ledger::createFullLedger()
|
newcoin::FullLedger* Ledger::createFullLedger()
|
||||||
{
|
{
|
||||||
// TODO: do we need to hash and create accounts map first?
|
|
||||||
newcoin::FullLedger* ledger=new newcoin::FullLedger();
|
newcoin::FullLedger* ledger=new newcoin::FullLedger();
|
||||||
ledger->set_index(mIndex);
|
ledger->set_index(mIndex);
|
||||||
ledger->set_hash(mHash.begin(),mHash.GetSerializeSize());
|
ledger->set_hash(getHash().begin(),getHash().GetSerializeSize());
|
||||||
|
ledger->set_parenthash(mParentHash.begin(),mParentHash.GetSerializeSize());
|
||||||
|
|
||||||
pair<uint160, pair<uint64,uint32> >& account=pair<uint160, pair<uint64,uint32> >();
|
pair<uint160, pair<uint64,uint32> >& account=pair<uint160, pair<uint64,uint32> >();
|
||||||
BOOST_FOREACH(account,mAccounts)
|
BOOST_FOREACH(account,mAccounts)
|
||||||
@@ -41,7 +57,6 @@ newcoin::FullLedger* Ledger::createFullLedger()
|
|||||||
saveAccount->set_amount(account.second.first);
|
saveAccount->set_amount(account.second.first);
|
||||||
saveAccount->set_seqnum(account.second.second);
|
saveAccount->set_seqnum(account.second.second);
|
||||||
}
|
}
|
||||||
//mBundle.addTransactionsToPB(ledger);
|
|
||||||
|
|
||||||
return(ledger);
|
return(ledger);
|
||||||
}
|
}
|
||||||
@@ -81,8 +96,27 @@ Ledger::pointer Ledger::getParent()
|
|||||||
return(mParent);
|
return(mParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Ledger::load(uint256& hash)
|
||||||
|
{
|
||||||
|
Database* db=theApp->getDB();
|
||||||
|
|
||||||
|
string sql="SELECT * from Ledgers where hash=";
|
||||||
|
string hashStr;
|
||||||
|
db->escape(hash.begin(),hash.GetSerializeSize(),hashStr);
|
||||||
|
sql.append(hashStr);
|
||||||
|
|
||||||
|
if(db->executeSQL(sql.c_str()))
|
||||||
|
{
|
||||||
|
db->getNextRow();
|
||||||
|
sql="SELECT * from Transactions where "
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
bool Ledger::load(std::string dir)
|
bool Ledger::load(std::string dir)
|
||||||
{
|
{
|
||||||
|
|
||||||
string filename=strprintf("%s%u.ledger",dir,mIndex);
|
string filename=strprintf("%s%u.ledger",dir,mIndex);
|
||||||
|
|
||||||
ifstream loadfile(filename, ios::in | ios::binary);
|
ifstream loadfile(filename, ios::in | ios::binary);
|
||||||
@@ -112,6 +146,7 @@ void Ledger::save(string dir)
|
|||||||
}
|
}
|
||||||
delete(ledger);
|
delete(ledger);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
int64 Ledger::getAmountHeld(uint160& address)
|
int64 Ledger::getAmountHeld(uint160& address)
|
||||||
{
|
{
|
||||||
@@ -151,13 +186,13 @@ void Ledger::publishValidation()
|
|||||||
|
|
||||||
void Ledger::sign()
|
void Ledger::sign()
|
||||||
{
|
{
|
||||||
// TODO:
|
// TODO: Ledger::sign()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Ledger::hash()
|
void Ledger::hash()
|
||||||
{
|
{
|
||||||
// TODO:
|
// TODO: Ledger::hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
6
Ledger.h
6
Ledger.h
@@ -20,7 +20,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool mValidSig;
|
bool mValidSig;
|
||||||
bool mValidHash;
|
bool mValidHash;
|
||||||
bool mFaith; //TODO: if you will bother to validate this ledger or not. You have to accept the first ledger on Faith
|
|
||||||
|
|
||||||
uint32 mIndex;
|
uint32 mIndex;
|
||||||
uint256 mHash;
|
uint256 mHash;
|
||||||
@@ -49,6 +48,7 @@ private:
|
|||||||
void correctAccount(uint160& address);
|
void correctAccount(uint160& address);
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<Ledger> pointer;
|
typedef boost::shared_ptr<Ledger> pointer;
|
||||||
|
Ledger();
|
||||||
Ledger(uint32 index);
|
Ledger(uint32 index);
|
||||||
Ledger(newcoin::FullLedger& ledger);
|
Ledger(newcoin::FullLedger& ledger);
|
||||||
Ledger(Ledger::pointer other);
|
Ledger(Ledger::pointer other);
|
||||||
@@ -56,8 +56,8 @@ public:
|
|||||||
void setTo(newcoin::FullLedger& ledger);
|
void setTo(newcoin::FullLedger& ledger);
|
||||||
void mergeIn(Ledger::pointer other);
|
void mergeIn(Ledger::pointer other);
|
||||||
|
|
||||||
void save(std::string dir);
|
void save(uint256& hash);
|
||||||
bool load(std::string dir);
|
bool load(uint256& hash);
|
||||||
|
|
||||||
void recalculate(bool recursive=true);
|
void recalculate(bool recursive=true);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "LedgerHistory.h"
|
#include "LedgerHistory.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "Application.h"
|
||||||
|
#include <string>
|
||||||
/*
|
/*
|
||||||
Soon we should support saving the ledger in a real DB
|
Soon we should support saving the ledger in a real DB
|
||||||
For now save them all in
|
For now save them all in
|
||||||
@@ -14,16 +15,33 @@ void LedgerHistory::load()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LedgerHistory::loadLedger(uint32 index)
|
bool LedgerHistory::loadLedger(uint256& hash)
|
||||||
{
|
{
|
||||||
Ledger::pointer ledger(new Ledger(index));
|
Ledger::pointer ledger=Ledger::pointer(new Ledger());
|
||||||
if(ledger->load(theConfig.HISTORY_DIR))
|
if(ledger->load(hash))
|
||||||
{
|
{
|
||||||
mAcceptedLedgers[index]=ledger;
|
mAllLedgers[hash]=ledger;
|
||||||
|
return(true);
|
||||||
}
|
}
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LedgerHistory::loadAcceptedLedger(uint32 index)
|
||||||
|
{
|
||||||
|
Ledger::pointer ledger=theApp->getSerializer()->loadAcceptedLedger(index);
|
||||||
|
if(ledger)
|
||||||
|
{
|
||||||
|
mAcceptedLedgers[index]=ledger;
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger)
|
||||||
|
{
|
||||||
|
mAcceptedLedgers[ledger->getIndex()]=ledger;
|
||||||
|
}
|
||||||
|
|
||||||
// this will see if the ledger is in memory
|
// this will see if the ledger is in memory
|
||||||
// if not it will check disk and load it
|
// if not it will check disk and load it
|
||||||
// if not it will return NULL
|
// if not it will return NULL
|
||||||
@@ -31,7 +49,7 @@ Ledger::pointer LedgerHistory::getAcceptedLedger(uint32 index)
|
|||||||
{
|
{
|
||||||
if(mAcceptedLedgers.count(index))
|
if(mAcceptedLedgers.count(index))
|
||||||
return(mAcceptedLedgers[index]);
|
return(mAcceptedLedgers[index]);
|
||||||
if(loadLedger(index)) return(mAcceptedLedgers[index]);
|
if(loadAcceptedLedger(index)) return(mAcceptedLedgers[index]);
|
||||||
return(Ledger::pointer());
|
return(Ledger::pointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,3 +58,11 @@ void LedgerHistory::addLedger(Ledger::pointer ledger)
|
|||||||
mAcceptedLedgers[ledger->getIndex()]=ledger;
|
mAcceptedLedgers[ledger->getIndex()]=ledger;
|
||||||
ledger->save(theConfig.HISTORY_DIR);
|
ledger->save(theConfig.HISTORY_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ledger::pointer LedgerHistory::getLedger(uint256& hash)
|
||||||
|
{
|
||||||
|
if(mAllLedgers.count(hash))
|
||||||
|
return(mAllLedgers[hash]);
|
||||||
|
if(loadLedger(hash)) return(mAllLedgers[hash]);
|
||||||
|
return(Ledger::pointer());
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ class LedgerHistory
|
|||||||
std::map<uint32, Ledger::pointer> mAcceptedLedgers;
|
std::map<uint32, Ledger::pointer> mAcceptedLedgers;
|
||||||
std::map<uint256, Ledger::pointer> mAllLedgers;
|
std::map<uint256, Ledger::pointer> mAllLedgers;
|
||||||
|
|
||||||
bool loadLedger(uint32 index);
|
bool loadAcceptedLedger(uint32 index);
|
||||||
|
bool loadLedger(uint256& hash);
|
||||||
public:
|
public:
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
|
|||||||
@@ -225,14 +225,15 @@ void LedgerMaster::checkLedgerProposal(Peer::pointer peer, newcoin::ProposeLedge
|
|||||||
addFutureProposal(peer,otherLedger);
|
addFutureProposal(peer,otherLedger);
|
||||||
}else
|
}else
|
||||||
{ // you guys are on the same page
|
{ // you guys are on the same page
|
||||||
if(mFinalizingLedger->getHash()!= Transaction::protobufToInternalHash(otherLedger.hash()))
|
uint256 otherHash=Transaction::protobufToInternalHash(otherLedger.hash());
|
||||||
|
if(mFinalizingLedger->getHash()!= otherHash)
|
||||||
{
|
{
|
||||||
if( mFinalizingLedger->getNumTransactions()>=otherLedger.numtransactions())
|
if( mFinalizingLedger->getNumTransactions()>=otherLedger.numtransactions())
|
||||||
{
|
{
|
||||||
peer->sendLedgerProposal(mFinalizingLedger);
|
peer->sendLedgerProposal(mFinalizingLedger);
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
peer->sendGetFullLedger(otherLedger.ledgerindex());
|
peer->sendGetFullLedger(otherHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
#include "BitcoinUtil.h"
|
#include "BitcoinUtil.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint160 NewcoinAddress::protobufToInternal(const std::string& buf)
|
||||||
|
{
|
||||||
|
uint160 ret;
|
||||||
|
// TODO:
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint160 NewcoinAddress::humanToInternal(const std::string& buf)
|
||||||
|
{
|
||||||
|
uint160 ret;
|
||||||
|
// TODO:
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
bool NewcoinAddress::SetHash160(const uint160& hash160)
|
bool NewcoinAddress::SetHash160(const uint160& hash160)
|
||||||
{
|
{
|
||||||
SetData(theConfig.TEST_NET ? 112 : 1, &hash160, 20);
|
SetData(theConfig.TEST_NET ? 112 : 1, &hash160, 20);
|
||||||
|
|||||||
16
Peer.cpp
16
Peer.cpp
@@ -134,6 +134,15 @@ PackedMessage::pointer Peer::createValidation(Ledger::pointer ledger)
|
|||||||
return(packet);
|
return(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PackedMessage::pointer Peer::createGetFullLedger(uint256& hash)
|
||||||
|
{
|
||||||
|
newcoin::GetFullLedger* gfl=new newcoin::GetFullLedger();
|
||||||
|
gfl->set_hash(hash.begin(),hash.GetSerializeSize());
|
||||||
|
|
||||||
|
PackedMessage::pointer packet(new PackedMessage(PackedMessage::MessagePointer(gfl),newcoin::GET_FULL_LEDGER));
|
||||||
|
return(packet);
|
||||||
|
}
|
||||||
|
|
||||||
void Peer::sendLedgerProposal(Ledger::pointer ledger)
|
void Peer::sendLedgerProposal(Ledger::pointer ledger)
|
||||||
{
|
{
|
||||||
PackedMessage::pointer packet=Peer::createLedgerProposal(ledger);
|
PackedMessage::pointer packet=Peer::createLedgerProposal(ledger);
|
||||||
@@ -150,12 +159,9 @@ void Peer::sendFullLedger(Ledger::pointer ledger)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peer::sendGetFullLedger(uint32 index)
|
void Peer::sendGetFullLedger(uint256& hash)
|
||||||
{
|
{
|
||||||
newcoin::GetFullLedger* gfl=new newcoin::GetFullLedger();
|
PackedMessage::pointer packet=createGetFullLedger(hash);
|
||||||
gfl->set_ledgerindex(index);
|
|
||||||
|
|
||||||
PackedMessage::pointer packet(new PackedMessage(PackedMessage::MessagePointer(gfl),newcoin::GET_FULL_LEDGER));
|
|
||||||
sendPacket(packet);
|
sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
Peer.h
2
Peer.h
@@ -79,7 +79,7 @@ public:
|
|||||||
void sendPacket(PackedMessage::pointer packet);
|
void sendPacket(PackedMessage::pointer packet);
|
||||||
void sendLedgerProposal(Ledger::pointer ledger);
|
void sendLedgerProposal(Ledger::pointer ledger);
|
||||||
void sendFullLedger(Ledger::pointer ledger);
|
void sendFullLedger(Ledger::pointer ledger);
|
||||||
void sendGetFullLedger(uint32 index);
|
void sendGetFullLedger(uint256& hash);
|
||||||
|
|
||||||
//static PackedMessage::pointer createFullLedger(Ledger::pointer ledger);
|
//static PackedMessage::pointer createFullLedger(Ledger::pointer ledger);
|
||||||
static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger);
|
static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger);
|
||||||
|
|||||||
@@ -33,3 +33,16 @@ uint256 Transaction::calcHash(TransactionPtr trans)
|
|||||||
trans->SerializeToArray(&(buffer[0]),buffer.size());
|
trans->SerializeToArray(&(buffer[0]),buffer.size());
|
||||||
return Hash(buffer.begin(), buffer.end());
|
return Hash(buffer.begin(), buffer.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint256 Transaction::protobufToInternalHash(const std::string& hash)
|
||||||
|
{
|
||||||
|
uint256 ret;
|
||||||
|
// TODO:
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Transaction::isSigValid(TransactionPtr trans)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
@@ -1,7 +1,31 @@
|
|||||||
#include "UniqueNodeList.h"
|
#include "UniqueNodeList.h"
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
void UniqueNodeList::load()
|
|
||||||
|
void UniqueNodeList::addNode(uint160& hanko,uint1024& publicKey)
|
||||||
{
|
{
|
||||||
|
"INSERT INTO UNL values ("
|
||||||
|
theApp->getDB()->executeSQL(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UniqueNodeList::removeNode(uint160& hanko)
|
||||||
|
{
|
||||||
|
"DELETE FROM UNL where hanko="
|
||||||
|
theApp->getDB()->executeSQL(sql);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int UniqueNodeList::checkValid(newcoin::Validation& valid)
|
||||||
|
{
|
||||||
|
"SELECT pubkey from UNL where hanko="
|
||||||
|
if( theApp->getDB()->executeSQL(sql) )
|
||||||
|
{
|
||||||
|
if(theApp->getDB()->getNextRow())
|
||||||
|
{
|
||||||
|
theApp->getDB()->getBytes();
|
||||||
|
|
||||||
|
}else return(0); // not on our list
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,17 @@
|
|||||||
|
|
||||||
class UniqueNodeList
|
class UniqueNodeList
|
||||||
{
|
{
|
||||||
|
// hanko to public key
|
||||||
|
//std::map<uint160,uint512> mUNL;
|
||||||
public:
|
public:
|
||||||
void load();
|
//void load();
|
||||||
void save();
|
//void save();
|
||||||
|
|
||||||
bool findHanko(const std::string& hanko);
|
void addNode(uint160& hanko,uint1024& publicKey);
|
||||||
|
void removeNode(uint160& hanko);
|
||||||
|
|
||||||
|
// 0- we don't care, 1- we care and is valid, 2-invalid signature
|
||||||
|
int checkValid(newcoin::Validation& valid);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,19 @@ Then we just have to check this ledger to see if a new ledger is compatible
|
|||||||
This is also the ledger we hand back when we ask for the consensus ledger
|
This is also the ledger we hand back when we ask for the consensus ledger
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
ValidationCollection::ValidationCollection()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValidationCollection::save()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void ValidationCollection::load()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool ValidationCollection::hasValidation(uint256& ledgerHash,uint160& hanko,uint32 seqnum)
|
bool ValidationCollection::hasValidation(uint256& ledgerHash,uint160& hanko,uint32 seqnum)
|
||||||
{
|
{
|
||||||
@@ -51,16 +63,20 @@ void ValidationCollection::addValidation(newcoin::Validation& valid)
|
|||||||
if(hasValidation(hash,hanko,valid.seqnum())) return;
|
if(hasValidation(hash,hanko,valid.seqnum())) return;
|
||||||
|
|
||||||
// check if we care about this hanko
|
// check if we care about this hanko
|
||||||
if( theApp->getUNL().findHanko(valid.hanko()) )
|
int validity=theApp->getUNL().checkValid(valid);
|
||||||
|
if( validity==1 )
|
||||||
{
|
{
|
||||||
mValidations[hash].push_back(valid);
|
mValidations[hash].push_back(valid);
|
||||||
mIndexValidations[valid.ledgerindex()].push_back(valid);
|
mIndexValidations[valid.ledgerindex()].push_back(valid);
|
||||||
addToGroup(valid);
|
addToGroup(valid);
|
||||||
|
|
||||||
theApp->getLedgerMaster().checkConsensus(valid.ledgerindex());
|
theApp->getLedgerMaster().checkConsensus(valid.ledgerindex());
|
||||||
}else
|
}else if(validity==0)
|
||||||
{
|
{
|
||||||
mIgnoredValidations[hash].push_back(valid);
|
mIgnoredValidations[hash].push_back(valid);
|
||||||
|
}else
|
||||||
|
{ // the signature wasn't valid
|
||||||
|
cout << "Invalid Validation" << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
database/SqliteDatabase.cpp
Normal file
23
database/SqliteDatabase.cpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include "SqliteDatabase.h"
|
||||||
|
|
||||||
|
SqliteDatabase::SqliteDatabase()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* http://www.sqlite.org/lang_expr.html
|
||||||
|
BLOB literals are string literals containing hexadecimal data and preceded by a single "x" or "X" character. For example:
|
||||||
|
X'53514C697465'
|
||||||
|
*/
|
||||||
|
void SqliteDatabase::escape(unsigned char* start,int size,std::string& retStr)
|
||||||
|
{
|
||||||
|
retStr.clear();
|
||||||
|
|
||||||
|
char buf[3];
|
||||||
|
retStr.append("X'");
|
||||||
|
for(int n=0; n<size; n++)
|
||||||
|
{
|
||||||
|
retStr.append( itoa(*start,buf,16) );
|
||||||
|
}
|
||||||
|
retStr.push_back('\'');
|
||||||
|
}
|
||||||
11
database/SqliteDatabase.h
Normal file
11
database/SqliteDatabase.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
class SqliteDatabase : public Database
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SqliteDatabase();
|
||||||
|
|
||||||
|
|
||||||
|
void escape(unsigned char* start,int size,std::string& retStr);
|
||||||
|
|
||||||
|
};
|
||||||
118
database/database.cpp
Normal file
118
database/database.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#include "database.h"
|
||||||
|
#include "../utillib/reportingmechanism.h"
|
||||||
|
#include "string/i4string.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
Database::Database(const char* host,const char* user,const char* pass) : mDBPass(pass), mHost(host) ,mUser(user), mNumCol(0)
|
||||||
|
{
|
||||||
|
mColNameTable=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::~Database()
|
||||||
|
{
|
||||||
|
delete[] mColNameTable;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char* Database::getStr(const char* colName,std::string& retStr)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
if(getColNumber(colName,&index))
|
||||||
|
{
|
||||||
|
return(getStr(index,retStr));
|
||||||
|
}
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
w32 Database::getInt(const char* colName)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
if(getColNumber(colName,&index))
|
||||||
|
{
|
||||||
|
return(getInt(index));
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Database::getFloat(const char* colName)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
if(getColNumber(colName,&index))
|
||||||
|
{
|
||||||
|
return(getFloat(index));
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::getBool(const char* colName)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
if(getColNumber(colName,&index))
|
||||||
|
{
|
||||||
|
return(getBool(index));
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// returns false if can't find col
|
||||||
|
bool Database::getColNumber(const char* colName,int* retIndex)
|
||||||
|
{
|
||||||
|
for(int n=0; n<mNumCol; n++)
|
||||||
|
{
|
||||||
|
if(i4_stricmp(colName,mColNameTable[n])==0)
|
||||||
|
{
|
||||||
|
*retIndex=n;
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Database::getSingleDBValueInt(const char* sql)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if( executeSQL(sql) && startIterRows() && getNextRow())
|
||||||
|
{
|
||||||
|
ret=getInt(0);
|
||||||
|
endIterRows();
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
//theUI->statusMsg("ERROR with database: %s",sql);
|
||||||
|
ret=0;
|
||||||
|
}
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Database::getSingleDBValueFloat(const char* sql)
|
||||||
|
{
|
||||||
|
float ret;
|
||||||
|
if( executeSQL(sql) && startIterRows() && getNextRow())
|
||||||
|
{
|
||||||
|
ret=getFloat(0);
|
||||||
|
endIterRows();
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
//theUI->statusMsg("ERROR with database: %s",sql);
|
||||||
|
ret=0;
|
||||||
|
}
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Database::getSingleDBValueStr(const char* sql,std::string& retStr)
|
||||||
|
{
|
||||||
|
char* ret;
|
||||||
|
if( executeSQL(sql) && startIterRows() && getNextRow())
|
||||||
|
{
|
||||||
|
ret=getStr(0,retStr);
|
||||||
|
endIterRows();
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
//theUI->statusMsg("ERROR with database: %s",sql);
|
||||||
|
ret=0;
|
||||||
|
}
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
73
database/database.h
Normal file
73
database/database.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#ifndef __DATABASE__
|
||||||
|
#define __DATABASE__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/*
|
||||||
|
this maintains the connection to the database
|
||||||
|
*/
|
||||||
|
class Database
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int mNumCol;
|
||||||
|
std:string mUser;
|
||||||
|
std:string mHost;
|
||||||
|
std:string mDBPass;
|
||||||
|
std:string* mColNameTable;
|
||||||
|
|
||||||
|
bool getColNumber(const char* colName, int* retIndex);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Database(const char* host,const char* user,const char* pass);
|
||||||
|
static Database* newMysqlDatabase(const char* host,const char* user,const char* pass);
|
||||||
|
virtual ~Database();
|
||||||
|
|
||||||
|
virtual void connect()=0;
|
||||||
|
virtual void disconnect()=0;
|
||||||
|
|
||||||
|
std::string& getPass(){ return(mDBPass); }
|
||||||
|
|
||||||
|
virtual void escape(unsigned char* start,int size,std::string& retStr)=0;
|
||||||
|
|
||||||
|
// returns true if the query went ok
|
||||||
|
virtual bool executeSQL(const char* sql)=0;
|
||||||
|
|
||||||
|
// tells you how many rows were changed by an update or insert
|
||||||
|
virtual int getNumRowsAffected()=0;
|
||||||
|
|
||||||
|
// returns false if there are no results
|
||||||
|
virtual bool startIterRows()=0;
|
||||||
|
virtual void endIterRows()=0;
|
||||||
|
|
||||||
|
// call this after you executeSQL
|
||||||
|
// will return false if there are no more rows
|
||||||
|
virtual bool getNextRow()=0;
|
||||||
|
|
||||||
|
// get Data from the current row
|
||||||
|
char* getStr(const char* colName,std::string& retStr);
|
||||||
|
int32 getInt(const char* colName);
|
||||||
|
float getFloat(const char* colName);
|
||||||
|
bool getBool(const char* colName);
|
||||||
|
bool getBinary(const char* colName,char* buf,int maxSize);
|
||||||
|
|
||||||
|
virtual char* getStr(int colIndex,std::string& retStr)=0;
|
||||||
|
virtual int32 getInt(int colIndex)=0;
|
||||||
|
virtual float getFloat(int colIndex)=0;
|
||||||
|
virtual bool getBool(int colIndex)=0;
|
||||||
|
virtual bool getBinary(int colIndex,char* buf,int maxSize)=0;
|
||||||
|
|
||||||
|
int getSingleDBValueInt(const char* sql);
|
||||||
|
float getSingleDBValueFloat(const char* sql);
|
||||||
|
char* getSingleDBValueStr(const char* sql, std::string& retStr);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class MsqlDatabase
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
136
database/linux/mysqldatabase.cpp
Normal file
136
database/linux/mysqldatabase.cpp
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#include "mysqldatabase.h"
|
||||||
|
#include "reportingmechanism.h"
|
||||||
|
#include "string/i4string.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
Database* Database::newDatabase(const char* host,const char* user,const char* pass)
|
||||||
|
{
|
||||||
|
return(new MySqlDatabase(host,user,pass));
|
||||||
|
}
|
||||||
|
|
||||||
|
MySqlDatabase::MySqlDatabase(const char* host,const char* user,const char* pass) : Database(host,user,pass)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MySqlDatabase::~MySqlDatabase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySqlDatabase::connect()
|
||||||
|
{
|
||||||
|
mysql_init(&mMysql);
|
||||||
|
mysql_options(&mMysql,MYSQL_READ_DEFAULT_GROUP,"i4min");
|
||||||
|
if(!mysql_real_connect(&mMysql,mHost,mUser,mDBPass,NULL,0,NULL,0))
|
||||||
|
{
|
||||||
|
theUI->statusMsg("Failed to connect to database: Error: %s\n", mysql_error(&mMysql));
|
||||||
|
}else theUI->statusMsg("Connection Established to DB");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySqlDatabase::disconnect()
|
||||||
|
{
|
||||||
|
mysql_close(&mMysql);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MySqlDatabase::getNumRowsAffected()
|
||||||
|
{
|
||||||
|
return( mysql_affected_rows(&mMysql));
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the query went ok
|
||||||
|
bool MySqlDatabase::executeSQL(const char* sql)
|
||||||
|
{
|
||||||
|
int ret=mysql_query(&mMysql, sql);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
connect();
|
||||||
|
int ret=mysql_query(&mMysql, sql);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
theUI->statusMsg("ERROR with executeSQL: %d %s",ret,sql);
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MySqlDatabase::startIterRows()
|
||||||
|
{
|
||||||
|
mResult=mysql_store_result(&mMysql);
|
||||||
|
// get total number of columns from the resultset
|
||||||
|
mNumCol = mysql_num_fields(mResult);
|
||||||
|
if(mNumCol)
|
||||||
|
{
|
||||||
|
delete[](mColNameTable);
|
||||||
|
mColNameTable=new i4_str[mNumCol];
|
||||||
|
|
||||||
|
// fill out the column name table
|
||||||
|
for(int n = 0; n < mNumCol; n++)
|
||||||
|
{
|
||||||
|
MYSQL_FIELD* field=mysql_fetch_field(mResult);
|
||||||
|
mColNameTable[n]= field->name;
|
||||||
|
}
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call this after you executeSQL
|
||||||
|
// will return false if there are no more rows
|
||||||
|
bool MySqlDatabase::getNextRow()
|
||||||
|
{
|
||||||
|
mCurRow=mysql_fetch_row(mResult);
|
||||||
|
|
||||||
|
return(mCurRow!=NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* MySqlDatabase::getStr(int colIndex,i4_str* retStr)
|
||||||
|
{
|
||||||
|
if(mCurRow[colIndex])
|
||||||
|
{
|
||||||
|
(*retStr)=mCurRow[colIndex];
|
||||||
|
}else (*retStr)="";
|
||||||
|
|
||||||
|
return(*retStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
w32 MySqlDatabase::getInt(int colIndex)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(mCurRow[colIndex])
|
||||||
|
{
|
||||||
|
w32 ret=atoll(mCurRow[colIndex]);
|
||||||
|
//theUI->statusMsg("getInt: %s,%c,%u",mCurRow[colIndex],mCurRow[colIndex][0],ret);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float MySqlDatabase::getFloat(int colIndex)
|
||||||
|
{
|
||||||
|
if(mCurRow[colIndex])
|
||||||
|
{
|
||||||
|
float ret=atof(mCurRow[colIndex]);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
return(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MySqlDatabase::getBool(int colIndex)
|
||||||
|
{
|
||||||
|
if(mCurRow[colIndex])
|
||||||
|
{
|
||||||
|
int ret=atoi(mCurRow[colIndex]);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MySqlDatabase::endIterRows()
|
||||||
|
{
|
||||||
|
mysql_free_result(mResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
47
database/linux/mysqldatabase.h
Normal file
47
database/linux/mysqldatabase.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef __MYSQLDATABASE__
|
||||||
|
#define __MYSQLDATABASE__
|
||||||
|
|
||||||
|
#include "../database.h"
|
||||||
|
#include "string/i4string.h"
|
||||||
|
#include "mysql.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
this maintains the connection to the database
|
||||||
|
*/
|
||||||
|
class MySqlDatabase : public Database
|
||||||
|
{
|
||||||
|
MYSQL mMysql;
|
||||||
|
MYSQL_RES* mResult;
|
||||||
|
MYSQL_ROW mCurRow;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MySqlDatabase(const char* host,const char* user,const char* pass);
|
||||||
|
~MySqlDatabase();
|
||||||
|
|
||||||
|
void connect();
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
// returns true if the query went ok
|
||||||
|
bool executeSQL(const char* sql);
|
||||||
|
|
||||||
|
int getNumRowsAffected();
|
||||||
|
|
||||||
|
// returns false if there are no results
|
||||||
|
bool startIterRows();
|
||||||
|
void endIterRows();
|
||||||
|
|
||||||
|
// call this after you executeSQL
|
||||||
|
// will return false if there are no more rows
|
||||||
|
bool getNextRow();
|
||||||
|
|
||||||
|
// get Data from the current row
|
||||||
|
|
||||||
|
char* getStr(int colIndex,i4_str* retStr);
|
||||||
|
w32 getInt(int colIndex);
|
||||||
|
float getFloat(int colIndex);
|
||||||
|
bool getBool(int colIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
82
database/win/dbutility.h
Normal file
82
database/win/dbutility.h
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#ifndef __TMYODBC_UTILITY_H__
|
||||||
|
#define __TMYODBC_UTILITY_H__
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <myconf.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* STANDARD C HEADERS */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/* ODBC HEADERS */
|
||||||
|
#include <sqlext.h>
|
||||||
|
|
||||||
|
#define MAX_NAME_LEN 95
|
||||||
|
#define MAX_COLUMNS 255
|
||||||
|
#define MAX_ROW_DATA_LEN 255
|
||||||
|
|
||||||
|
|
||||||
|
/* PROTOTYPE */
|
||||||
|
void myerror(SQLRETURN rc,SQLSMALLINT htype, SQLHANDLE handle);
|
||||||
|
|
||||||
|
/* UTILITY MACROS */
|
||||||
|
#define myenv(henv,r) \
|
||||||
|
if ( ((r) != SQL_SUCCESS) ) \
|
||||||
|
myerror(r, 1,henv); \
|
||||||
|
assert( ((r) == SQL_SUCCESS) || ((r) == SQL_SUCCESS_WITH_INFO) )
|
||||||
|
|
||||||
|
#define myenv_err(henv,r,rc) \
|
||||||
|
if ( rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO ) \
|
||||||
|
myerror(rc, 1, henv); \
|
||||||
|
assert( r )
|
||||||
|
|
||||||
|
#define mycon(hdbc,r) \
|
||||||
|
if ( ((r) != SQL_SUCCESS) ) \
|
||||||
|
myerror(r, 2, hdbc); \
|
||||||
|
assert( ((r) == SQL_SUCCESS) || ((r) == SQL_SUCCESS_WITH_INFO) )
|
||||||
|
|
||||||
|
#define mycon_err(hdbc,r,rc) \
|
||||||
|
if ( rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO ) \
|
||||||
|
myerror(rc, 2, hdbc); \
|
||||||
|
assert( r )
|
||||||
|
|
||||||
|
#define mystmt(hstmt,r) \
|
||||||
|
if ( ((r) != SQL_SUCCESS) ) \
|
||||||
|
myerror(r, 3, hstmt); \
|
||||||
|
assert( ((r) == SQL_SUCCESS) || ((r) == SQL_SUCCESS_WITH_INFO) )
|
||||||
|
|
||||||
|
#define mystmt_err(hstmt,r,rc) \
|
||||||
|
if ( rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO ) \
|
||||||
|
myerror(rc, 3, hstmt); \
|
||||||
|
assert( r )
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* MyODBC 3.51 error handler *
|
||||||
|
*********************************************************/
|
||||||
|
void myerror(SQLRETURN rc, SQLSMALLINT htype, SQLHANDLE handle)
|
||||||
|
{
|
||||||
|
SQLRETURN lrc;
|
||||||
|
|
||||||
|
if( rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO )
|
||||||
|
{
|
||||||
|
SQLCHAR szSqlState[6],szErrorMsg[SQL_MAX_MESSAGE_LENGTH];
|
||||||
|
SQLINTEGER pfNativeError;
|
||||||
|
SQLSMALLINT pcbErrorMsg;
|
||||||
|
|
||||||
|
lrc = SQLGetDiagRec(htype, handle,1,
|
||||||
|
(SQLCHAR *)&szSqlState,
|
||||||
|
(SQLINTEGER *)&pfNativeError,
|
||||||
|
(SQLCHAR *)&szErrorMsg,
|
||||||
|
SQL_MAX_MESSAGE_LENGTH-1,
|
||||||
|
(SQLSMALLINT *)&pcbErrorMsg);
|
||||||
|
if(lrc == SQL_SUCCESS || lrc == SQL_SUCCESS_WITH_INFO)
|
||||||
|
printf("\n [%s][%d:%s]\n",szSqlState,pfNativeError,szErrorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __TMYODBC_UTILITY_H__ */
|
||||||
|
|
||||||
212
database/win/windatabase.cpp
Normal file
212
database/win/windatabase.cpp
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
#include "windatabase.h"
|
||||||
|
#include "dbutility.h"
|
||||||
|
|
||||||
|
Database* Database::newMysqlDatabase(const char* host,const char* user,const char* pass)
|
||||||
|
{
|
||||||
|
return(new WinDatabase(host,user,pass));
|
||||||
|
}
|
||||||
|
|
||||||
|
WinDatabase::WinDatabase(const char* host,const char* user,const char* pass) : Database(host,user,pass)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
WinDatabase::~WinDatabase()
|
||||||
|
{
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WinDatabase::connect()
|
||||||
|
{
|
||||||
|
SQLRETURN rc;
|
||||||
|
|
||||||
|
rc = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv);
|
||||||
|
myenv(henv, rc);
|
||||||
|
|
||||||
|
rc = SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3,0);
|
||||||
|
myenv(henv, rc);
|
||||||
|
|
||||||
|
rc = SQLAllocHandle(SQL_HANDLE_DBC,henv, &hdbc);
|
||||||
|
myenv(henv, rc);
|
||||||
|
|
||||||
|
rc = SQLConnect(hdbc, (unsigned char*)(char*) mHost, SQL_NTS, (unsigned char*)(char*) mUser, SQL_NTS, (unsigned char*)(char*) mDBPass, SQL_NTS);
|
||||||
|
mycon(hdbc, rc);
|
||||||
|
|
||||||
|
rc = SQLSetConnectAttr(hdbc,SQL_ATTR_AUTOCOMMIT,(SQLPOINTER)SQL_AUTOCOMMIT_ON,0);
|
||||||
|
mycon(hdbc,rc);
|
||||||
|
|
||||||
|
rc = SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt);
|
||||||
|
mycon(hdbc,rc);
|
||||||
|
|
||||||
|
//rc = SQLGetInfo(hdbc,SQL_DBMS_NAME,&server_name,40,NULL);
|
||||||
|
//mycon(hdbc, rc);
|
||||||
|
|
||||||
|
theUI->statusMsg("Connection Established to DB");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinDatabase::disconnect()
|
||||||
|
{
|
||||||
|
SQLRETURN rc;
|
||||||
|
|
||||||
|
rc = SQLFreeStmt(hstmt, SQL_DROP);
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
|
||||||
|
rc = SQLDisconnect(hdbc);
|
||||||
|
mycon(hdbc, rc);
|
||||||
|
|
||||||
|
rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
|
||||||
|
mycon(hdbc, rc);
|
||||||
|
|
||||||
|
rc = SQLFreeHandle(SQL_HANDLE_ENV, henv);
|
||||||
|
myenv(henv, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WinDatabase::getNumRowsAffected()
|
||||||
|
{
|
||||||
|
// theUI->statusMsg("getNumRowsAffected()");
|
||||||
|
SQLINTEGER ret;
|
||||||
|
SQLRowCount(hstmt,&ret);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the query went ok
|
||||||
|
bool WinDatabase::executeSQL(const char* sql)
|
||||||
|
{
|
||||||
|
SQLRETURN rc = SQLExecDirect(hstmt,(unsigned char*) sql,SQL_NTS);
|
||||||
|
if(rc==SQL_ERROR)
|
||||||
|
{
|
||||||
|
theUI->errorMsg("Trying to recover from DB error");
|
||||||
|
rc = SQLExecDirect(hstmt,(unsigned char*) sql,SQL_NTS);
|
||||||
|
if(rc==SQL_ERROR)
|
||||||
|
{
|
||||||
|
SQLCHAR SqlState[6], /*SQLStmt[100],*/ Msg[SQL_MAX_MESSAGE_LENGTH];
|
||||||
|
SQLINTEGER NativeError;
|
||||||
|
SQLSMALLINT i, MsgLen;
|
||||||
|
SQLRETURN /*rc1,*/ rc2;
|
||||||
|
|
||||||
|
i = 1;
|
||||||
|
while ((rc2 = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
|
||||||
|
{
|
||||||
|
theUI->errorMsg("DB ERROR: %s,%d,%s",SqlState,NativeError,Msg);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
|
||||||
|
// commit the transaction
|
||||||
|
rc = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
|
||||||
|
mycon(hdbc,rc);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WinDatabase::startIterRows()
|
||||||
|
{
|
||||||
|
SQLUINTEGER pcColDef;
|
||||||
|
SQLCHAR szColName[MAX_NAME_LEN];
|
||||||
|
SQLSMALLINT pfSqlType, pcbScale, pfNullable;
|
||||||
|
SQLSMALLINT numCol;
|
||||||
|
|
||||||
|
/* get total number of columns from the resultset */
|
||||||
|
SQLRETURN rc = SQLNumResultCols(hstmt,&numCol);
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
mNumCol=(int)numCol;
|
||||||
|
|
||||||
|
if(mNumCol)
|
||||||
|
{
|
||||||
|
delete[](mColNameTable);
|
||||||
|
mColNameTable=new i4_str[mNumCol];
|
||||||
|
|
||||||
|
// fill out the column name table
|
||||||
|
for(int n = 1; n <= mNumCol; n++)
|
||||||
|
{
|
||||||
|
rc = SQLDescribeCol(hstmt,n,szColName, MAX_NAME_LEN, NULL, &pfSqlType,&pcColDef,&pcbScale,&pfNullable);
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
|
||||||
|
mColNameTable[n-1]= (char*)szColName;
|
||||||
|
}
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call this after you executeSQL
|
||||||
|
// will return false if there are no more rows
|
||||||
|
bool WinDatabase::getNextRow()
|
||||||
|
{
|
||||||
|
SQLRETURN rc = SQLFetch(hstmt);
|
||||||
|
return((rc==SQL_SUCCESS) || (rc==SQL_SUCCESS_WITH_INFO));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char* WinDatabase::getStr(int colIndex,i4_str* retStr)
|
||||||
|
{
|
||||||
|
colIndex++;
|
||||||
|
(*retStr)="";
|
||||||
|
char buf[1000];
|
||||||
|
// SQLINTEGER len;
|
||||||
|
buf[0]=0;
|
||||||
|
|
||||||
|
while(SQLGetData(hstmt, colIndex, SQL_C_CHAR, &buf, 1000,NULL)!= SQL_NO_DATA)
|
||||||
|
{
|
||||||
|
(*retStr) += buf;
|
||||||
|
// theUI->statusMsg("Win: %s",buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
//SQLRETURN rc = SQLGetData(hstmt,colIndex,SQL_C_CHAR,&buf,30000,&len);
|
||||||
|
//mystmt(hstmt,rc);
|
||||||
|
//*retStr=buf;
|
||||||
|
|
||||||
|
//theUI->statusMsg("Win: %s",buf);
|
||||||
|
|
||||||
|
return(*retStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
w32 WinDatabase::getInt(int colIndex)
|
||||||
|
{
|
||||||
|
colIndex++;
|
||||||
|
int ret=0;
|
||||||
|
SQLRETURN rc = SQLGetData(hstmt,colIndex,SQL_INTEGER,&ret,sizeof(int),NULL);
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
float WinDatabase::getFloat(int colIndex)
|
||||||
|
{
|
||||||
|
colIndex++;
|
||||||
|
float ret=0;
|
||||||
|
SQLRETURN rc = SQLGetData(hstmt,colIndex,SQL_C_FLOAT,&ret,sizeof(float),NULL);
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WinDatabase::getBool(int colIndex)
|
||||||
|
{
|
||||||
|
colIndex++;
|
||||||
|
char buf[1];
|
||||||
|
buf[0]=0;
|
||||||
|
SQLRETURN rc = SQLGetData(hstmt,colIndex,SQL_C_CHAR,&buf,1,NULL);
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
|
||||||
|
return(buf[0] != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WinDatabase::endIterRows()
|
||||||
|
{
|
||||||
|
// free the statement row bind resources
|
||||||
|
SQLRETURN rc = SQLFreeStmt(hstmt, SQL_UNBIND);
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
|
||||||
|
// free the statement cursor
|
||||||
|
rc = SQLFreeStmt(hstmt, SQL_CLOSE);
|
||||||
|
mystmt(hstmt,rc);
|
||||||
|
}
|
||||||
55
database/win/windatabase.h
Normal file
55
database/win/windatabase.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef __WINDATABASE__
|
||||||
|
#define __WINDATABASE__
|
||||||
|
|
||||||
|
#include "../database.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define _WINSOCKAPI_ // prevent inclusion of winsock.h in windows.h
|
||||||
|
#include <windows.h>
|
||||||
|
#include "sql.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "string/i4string.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
this maintains the connection to the database
|
||||||
|
*/
|
||||||
|
class WinDatabase : public Database
|
||||||
|
{
|
||||||
|
SQLHENV henv;
|
||||||
|
SQLHDBC hdbc;
|
||||||
|
SQLHSTMT hstmt;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WinDatabase(const char* host,const char* user,const char* pass);
|
||||||
|
virtual ~WinDatabase();
|
||||||
|
|
||||||
|
void connect();
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
char* getPass(){ return(mDBPass); }
|
||||||
|
|
||||||
|
// returns true if the query went ok
|
||||||
|
bool executeSQL(const char* sql);
|
||||||
|
|
||||||
|
int getNumRowsAffected();
|
||||||
|
|
||||||
|
// returns false if there are no results
|
||||||
|
bool startIterRows();
|
||||||
|
void endIterRows();
|
||||||
|
|
||||||
|
// call this after you executeSQL
|
||||||
|
// will return false if there are no more rows
|
||||||
|
bool getNextRow();
|
||||||
|
|
||||||
|
// get Data from the current row
|
||||||
|
char* getStr(int colIndex,i4_str* retStr);
|
||||||
|
w32 getInt(int colIndex);
|
||||||
|
float getFloat(int colIndex);
|
||||||
|
bool getBool(int colIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
13
db layout.txt
Normal file
13
db layout.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// need to make this compatible with at least SQLite and Mysql
|
||||||
|
|
||||||
|
drop database if exists newcoin;
|
||||||
|
CREATE DATABASE newcoin;
|
||||||
|
use newcoin;
|
||||||
|
CREATE TABLE UNL (Hanko BINARY(20) PRIMARY KEY, PubKey BINARY(128));
|
||||||
|
CREATE TABLE Transactions (TransactionID INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, From BINARY(20), Dest BINARY(20), Amount BIGINT UNSIGNED, LedgerIndex INT UNSIGNED, SeqNum INT, PubKey BINARY(128), Sig BINARY(32));
|
||||||
|
CREATE TABLE Ledgers (LedgerID INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, LedgerIndex INT UNSIGNED, Hash BINARY(32), ParentHash BINARY(32),FeeHeld BIGINT UNSIGNED); //, Accepted TINYINT
|
||||||
|
CREATE TABLE Validations(LedgerIndex INT UNSIGNED, Hash BINARY(32), Hanko BINARY(20), SeqNum INT UNSIGNED, Sig BINARY(32), WeCare TINYINT);
|
||||||
|
CREATE TABLE LedgerTransactionMap (LedgerID INT UNSIGNED, TransactionID INT UNSIGNED, Include TINYINT);
|
||||||
|
CREATE TABLE LedgerAccountMap(LedgerID INT UNSIGNED,AccountID INT UNSIGNED);
|
||||||
|
CREATE TABLE Accounts (AccountID INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, Address BINARY(20), Amount BIGINT UNSIGNED, SeqNum INT);
|
||||||
|
CREATE TABLE AcceptedLedgers (LedgerIndex INT UNSIGNED PRIMARY KEY, LedgerID INT UNSIGNED);
|
||||||
@@ -70,8 +70,7 @@ message FullLedger {
|
|||||||
|
|
||||||
|
|
||||||
message GetFullLedger {
|
message GetFullLedger {
|
||||||
required uint32 ledgerIndex = 1;
|
required bytes hash = 1;
|
||||||
optional bytes hash = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetValidations {
|
message GetValidations {
|
||||||
|
|||||||
@@ -91,6 +91,10 @@
|
|||||||
<ClCompile Include="ConnectionPool.cpp" />
|
<ClCompile Include="ConnectionPool.cpp" />
|
||||||
<ClCompile Include="cryptopp\cpu.cpp" />
|
<ClCompile Include="cryptopp\cpu.cpp" />
|
||||||
<ClCompile Include="cryptopp\sha.cpp" />
|
<ClCompile Include="cryptopp\sha.cpp" />
|
||||||
|
<ClCompile Include="database\database.cpp" />
|
||||||
|
<ClCompile Include="database\SqliteDatabase.cpp" />
|
||||||
|
<ClCompile Include="database\win\windatabase.cpp" />
|
||||||
|
<ClCompile Include="DiskSerializer.cpp" />
|
||||||
<ClCompile Include="HttpReply.cpp" />
|
<ClCompile Include="HttpReply.cpp" />
|
||||||
<ClCompile Include="json\json_spirit_reader.cpp" />
|
<ClCompile Include="json\json_spirit_reader.cpp" />
|
||||||
<ClCompile Include="json\json_spirit_value.cpp" />
|
<ClCompile Include="json\json_spirit_value.cpp" />
|
||||||
@@ -100,6 +104,7 @@
|
|||||||
<ClCompile Include="Ledger.cpp" />
|
<ClCompile Include="Ledger.cpp" />
|
||||||
<ClCompile Include="LedgerHistory.cpp" />
|
<ClCompile Include="LedgerHistory.cpp" />
|
||||||
<ClCompile Include="LedgerMaster.cpp" />
|
<ClCompile Include="LedgerMaster.cpp" />
|
||||||
|
<ClCompile Include="MySqlSerializer.cpp" />
|
||||||
<ClCompile Include="newcoin.pb.cc" />
|
<ClCompile Include="newcoin.pb.cc" />
|
||||||
<ClCompile Include="NewcoinAddress.cpp" />
|
<ClCompile Include="NewcoinAddress.cpp" />
|
||||||
<ClCompile Include="PackedMessage.cpp" />
|
<ClCompile Include="PackedMessage.cpp" />
|
||||||
@@ -139,6 +144,8 @@
|
|||||||
<ClInclude Include="cryptopp\simple.h" />
|
<ClInclude Include="cryptopp\simple.h" />
|
||||||
<ClInclude Include="cryptopp\smartptr.h" />
|
<ClInclude Include="cryptopp\smartptr.h" />
|
||||||
<ClInclude Include="cryptopp\stdcpp.h" />
|
<ClInclude Include="cryptopp\stdcpp.h" />
|
||||||
|
<ClInclude Include="database\database.h" />
|
||||||
|
<ClInclude Include="database\SqliteDatabase.h" />
|
||||||
<ClInclude Include="HttpReply.h" />
|
<ClInclude Include="HttpReply.h" />
|
||||||
<ClInclude Include="HttpRequest.h" />
|
<ClInclude Include="HttpRequest.h" />
|
||||||
<ClInclude Include="json\json_spirit.h" />
|
<ClInclude Include="json\json_spirit.h" />
|
||||||
@@ -168,11 +175,13 @@
|
|||||||
<ClInclude Include="RPCDoor.h" />
|
<ClInclude Include="RPCDoor.h" />
|
||||||
<ClInclude Include="script.h" />
|
<ClInclude Include="script.h" />
|
||||||
<ClInclude Include="SecureAllocator.h" />
|
<ClInclude Include="SecureAllocator.h" />
|
||||||
|
<ClInclude Include="Serializer.h" />
|
||||||
<ClInclude Include="TimingService.h" />
|
<ClInclude Include="TimingService.h" />
|
||||||
<ClInclude Include="ExtendedTransaction.h" />
|
<ClInclude Include="ExtendedTransaction.h" />
|
||||||
<ClInclude Include="Transaction.h" />
|
<ClInclude Include="Transaction.h" />
|
||||||
<ClInclude Include="TransactionBundle.h" />
|
<ClInclude Include="TransactionBundle.h" />
|
||||||
<ClInclude Include="types.h" />
|
<ClInclude Include="types.h" />
|
||||||
|
<ClInclude Include="uint256.h" />
|
||||||
<ClInclude Include="UniqueNodeList.h" />
|
<ClInclude Include="UniqueNodeList.h" />
|
||||||
<ClInclude Include="util\pugiconfig.hpp" />
|
<ClInclude Include="util\pugiconfig.hpp" />
|
||||||
<ClInclude Include="util\pugixml.hpp" />
|
<ClInclude Include="util\pugixml.hpp" />
|
||||||
@@ -186,6 +195,7 @@
|
|||||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\protoc-2.4.1-win32\protoc -I=..\newcoin --cpp_out=..\newcoin ..\newcoin\newcoin.proto</Command>
|
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\protoc-2.4.1-win32\protoc -I=..\newcoin --cpp_out=..\newcoin ..\newcoin\newcoin.proto</Command>
|
||||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">newcoin.pb.h</Outputs>
|
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">newcoin.pb.h</Outputs>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
|
<None Include="db layout.txt" />
|
||||||
<None Include="html\newcoin.html">
|
<None Include="html\newcoin.html">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</None>
|
</None>
|
||||||
|
|||||||
@@ -132,6 +132,21 @@
|
|||||||
<ClCompile Include="Transaction.cpp">
|
<ClCompile Include="Transaction.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="MySqlSerializer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="DiskSerializer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="database\database.cpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="database\win\windatabase.cpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="database\SqliteDatabase.cpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Application.h">
|
<ClInclude Include="Application.h">
|
||||||
@@ -308,6 +323,18 @@
|
|||||||
<ClInclude Include="Account.h">
|
<ClInclude Include="Account.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Serializer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="database\database.h">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="database\SqliteDatabase.h">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="uint256.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="nodes.xml" />
|
<None Include="nodes.xml" />
|
||||||
@@ -318,6 +345,7 @@
|
|||||||
<None Include="html\newcoin.html">
|
<None Include="html\newcoin.html">
|
||||||
<Filter>html</Filter>
|
<Filter>html</Filter>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="db layout.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="newcoin.proto" />
|
<CustomBuild Include="newcoin.proto" />
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
Boost 1_47
|
Boost 1_47
|
||||||
boost log http://boost-log.sourceforge.net/libs/log/doc/html/log/installation.html
|
boost log http://boost-log.sourceforge.net/libs/log/doc/html/log/installation.html // this didn't work immediatly so I stopped messing with it but we should probably use it
|
||||||
protocol buffers: expects ..\protobuf-2.4.1 and ..\protoc-2.4.1-win32
|
protocol buffers: expects ..\protobuf-2.4.1 and ..\protoc-2.4.1-win32
|
||||||
openssl
|
openssl
|
||||||
|
sqlite
|
||||||
|
|
||||||
Using:
|
Using:
|
||||||
pugixml version 1.0 download new versions at http://pugixml.org/
|
pugixml version 1.0 download new versions at http://pugixml.org/
|
||||||
@@ -49,3 +50,4 @@ Peers are causing:
|
|||||||
Actualy I think this can all be in one thread. Commands to the app must be done by RPC.
|
Actualy I think this can all be in one thread. Commands to the app must be done by RPC.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user