Merge NewcoinAddress.

This commit is contained in:
Arthur Britto
2012-05-12 16:51:01 -07:00
66 changed files with 1750 additions and 906 deletions

View File

@@ -100,50 +100,59 @@ bool Database::getColNumber(const char* colName,int* retIndex)
return(false); return(false);
} }
#if 0
int Database::getSingleDBValueInt(const char* sql) int Database::getSingleDBValueInt(const char* sql)
{ {
int ret; int ret;
if( executeSQL(sql) && startIterRows() && getNextRow()) if( executeSQL(sql) && startIterRows()
{ {
ret=getInt(0); ret=getInt(0);
endIterRows(); endIterRows();
}else }
else
{ {
//theUI->statusMsg("ERROR with database: %s",sql); //theUI->statusMsg("ERROR with database: %s",sql);
ret=0; ret=0;
} }
return(ret); return(ret);
} }
#endif
#if 0
float Database::getSingleDBValueFloat(const char* sql) float Database::getSingleDBValueFloat(const char* sql)
{ {
float ret; float ret;
if( executeSQL(sql) && startIterRows() && getNextRow()) if(executeSQL(sql) && startIterRows() && getNextRow())
{ {
ret=getFloat(0); ret=getFloat(0);
endIterRows(); endIterRows();
}else }
else
{ {
//theUI->statusMsg("ERROR with database: %s",sql); //theUI->statusMsg("ERROR with database: %s",sql);
ret=0; ret=0;
} }
return(ret); return(ret);
} }
#endif
#if 0
char* Database::getSingleDBValueStr(const char* sql,std::string& retStr) char* Database::getSingleDBValueStr(const char* sql,std::string& retStr)
{ {
char* ret; char* ret;
if( executeSQL(sql) && startIterRows() && getNextRow()) if(executeSQL(sql) && startIterRows())
{ {
ret=getStr(0,retStr); ret=getStr(0,retStr);
endIterRows(); endIterRows();
}else }
else
{ {
//theUI->statusMsg("ERROR with database: %s",sql); //theUI->statusMsg("ERROR with database: %s",sql);
ret=0; ret=0;
} }
return(ret); return(ret);
} }
#endif
std::string Database::escape(const std::string strValue) std::string Database::escape(const std::string strValue)
{ {

View File

@@ -69,10 +69,9 @@ public:
virtual int getBinary(int colIndex,unsigned char* buf,int maxSize)=0; virtual int getBinary(int colIndex,unsigned char* buf,int maxSize)=0;
virtual uint64 getBigInt(int colIndex)=0; virtual uint64 getBigInt(int colIndex)=0;
int getSingleDBValueInt(const char* sql); // int getSingleDBValueInt(const char* sql);
float getSingleDBValueFloat(const char* sql); // float getSingleDBValueFloat(const char* sql);
char* getSingleDBValueStr(const char* sql, std::string& retStr); // char* getSingleDBValueStr(const char* sql, std::string& retStr);
}; };

View File

@@ -20,9 +20,11 @@ public:
typedef boost::shared_ptr<AccountState> pointer; typedef boost::shared_ptr<AccountState> pointer;
private: private:
NewcoinAddress mAccountID; NewcoinAddress mAccountID;
SerializedLedgerEntry::pointer mLedgerEntry; NewcoinAddress mAuthorizedKey;
bool mValid; SerializedLedgerEntry::pointer mLedgerEntry;
bool mValid;
public: public:
AccountState(const NewcoinAddress& AccountID); // For new accounts AccountState(const NewcoinAddress& AccountID); // For new accounts

View File

@@ -31,7 +31,7 @@ DatabaseCon::DatabaseCon(const std::string& name, const char *initStrings[], int
std::string path=strprintf("%s%s", theConfig.DATA_DIR.c_str(), name.c_str()); std::string path=strprintf("%s%s", theConfig.DATA_DIR.c_str(), name.c_str());
mDatabase=new SqliteDatabase(path.c_str()); mDatabase=new SqliteDatabase(path.c_str());
mDatabase->connect(); mDatabase->connect();
for(int i=0; i<initCount; i++) for(int i = 0; i < initCount; ++i)
mDatabase->executeSQL(initStrings[i], true); mDatabase->executeSQL(initStrings[i], true);
} }
@@ -41,11 +41,9 @@ DatabaseCon::~DatabaseCon()
delete mDatabase; delete mDatabase;
} }
Application::Application() : Application::Application() : mNetOps(mIOService), mUNL(mIOService),
mUNL(mIOService),
mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL),
mConnectionPool(mIOService), mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL)
mPeerDoor(NULL), mRPCDoor(NULL)
{ {
nothing(); nothing();
} }
@@ -57,7 +55,7 @@ void Application::stop()
{ {
mIOService.stop(); mIOService.stop();
std::cerr << "Stopped: " << mIOService.stopped() << std::endl; std::cerr << "Stopped: " << mIOService.stopped() << std::endl;
} }
void Application::run() void Application::run()
@@ -82,43 +80,96 @@ void Application::run()
// //
// Allow peer connections. // Allow peer connections.
// //
if(theConfig.PEER_PORT) if(!theConfig.PEER_IP.empty() && theConfig.PEER_PORT)
{ {
mPeerDoor=new PeerDoor(mIOService); mPeerDoor=new PeerDoor(mIOService);
}//else BOOST_LOG_TRIVIAL(info) << "No Peer Port set. Not listening for connections."; }
else
{
std::cerr << "Peer interface: disabled" << std::endl;
}
// //
// Allow RPC connections. // Allow RPC connections.
// //
if(theConfig.RPC_PORT) if(!theConfig.RPC_IP.empty() && theConfig.RPC_PORT)
{ {
mRPCDoor=new RPCDoor(mIOService); mRPCDoor=new RPCDoor(mIOService);
}//else BOOST_LOG_TRIVIAL(info) << "No RPC Port set. Not listening for commands."; }
else
{
std::cerr << "RPC interface: disabled" << std::endl;
}
// //
// Begin connectting to network. // Begin connecting to network.
// //
mConnectionPool.start(); mConnectionPool.start();
mTimingService.start(mIOService); // New stuff.
NewcoinAddress rootSeedMaster;
NewcoinAddress rootGeneratorMaster;
NewcoinAddress rootAddress;
rootSeedMaster.setFamilySeed(CKey::PassPhraseToKey("Master passphrase."));
rootGeneratorMaster.setFamilyGenerator(rootSeedMaster);
rootAddress.setAccountPublic(rootGeneratorMaster, 0);
std::cerr << "Master seed: " << rootSeedMaster.humanFamilySeed() << std::endl;
std::cerr << "Master generator: " << rootGeneratorMaster.humanFamilyGenerator() << std::endl;
std::cerr << "Root address: " << rootAddress.humanAccountPublic() << std::endl;
#if 0
NewcoinAddress rootSeedRegular;
NewcoinAddress rootGeneratorRegular;
NewcoinAddress reservedPublicRegular;
NewcoinAddress reservedPrivateRegular;
rootSeedRegular.setFamilySeed(CKey::PassPhraseToKey("Regular passphrase."));
rootGeneratorRegular.setFamilyGenerator(rootSeedRegular);
reservedPublicRegular.setAccountPublic(rootGeneratorRegular, -1);
reservedPrivateRegular.setAccountPrivate(rootGeneratorRegular, rootSeedRegular, -1);
// hash of regular account #reserved public key.
uint160 uiGeneratorID = reservedPublicRegular.getAccountID();
// std::cerr << "uiGeneratorID: " << uiGeneratorID << std::endl;
// Encrypt with regular account #reserved private key.
std::vector<unsigned char> vucGeneratorCipher = reservedPrivateRegular.accountPrivateEncrypt(reservedPublicRegular, rootGeneratorMaster.getFamilyGenerator());
std::cerr << "Plain: " << strHex(rootGeneratorMaster.getFamilyGenerator()) << std::endl;
std::cerr << "Cipher: " << strHex(vucGeneratorCipher) << std::endl;
std::vector<unsigned char> vucGeneratorText = reservedPrivateRegular.accountPrivateDecrypt(reservedPublicRegular, vucGeneratorCipher);
std::cerr << "Plain: " << strHex(vucGeneratorText) << std::endl;
std::cerr << "Regular seed: " << rootSeedRegular.humanFamilySeed() << std::endl;
std::cerr << "Regular generator: " << rootGeneratorRegular.humanFamilyGenerator() << std::endl;
std::cerr << "Reserved public regular: " << reservedPublicRegular.humanAccountPublic() << std::endl;
std::cerr << "Reserved private regular: " << reservedPrivateRegular.humanAccountPrivate() << std::endl;
#endif
// Temporary root account will be ["This is my payphrase."]:0 // Temporary root account will be ["This is my payphrase."]:0
NewcoinAddress rootFamilySeed; // Hold the 128 password. NewcoinAddress rootFamilySeed; // Hold the 128 password.
NewcoinAddress rootFamilyGenerator; // Hold the generator. NewcoinAddress rootFamilyGenerator; // Hold the generator.
NewcoinAddress rootAddress; // NewcoinAddress rootAddress;
rootFamilySeed.setFamilySeed(CKey::PassPhraseToKey("This is my payphrase.")); rootFamilySeed.setFamilySeed(CKey::PassPhraseToKey("This is my payphrase."));
rootFamilyGenerator.setFamilyGenerator(rootFamilySeed); rootFamilyGenerator.setFamilyGenerator(rootFamilySeed);
rootAddress.setAccountPublic(rootFamilyGenerator, 0); rootAddress.setAccountPublic(rootFamilyGenerator, 0);
std::cerr << "Root account: " << rootAddress.humanAccountID() << std::endl; std::cerr << "Root account: " << rootAddress.humanAccountID() << std::endl;
Ledger::pointer firstLedger(new Ledger(rootAddress, 100000000)); Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, 100000000);
assert(!!firstLedger->getAccountState(rootAddress)); assert(!!firstLedger->getAccountState(rootAddress));
firstLedger->updateHash();
firstLedger->setClosed(); firstLedger->setClosed();
firstLedger->setAccepted(); firstLedger->setAccepted();
mMasterLedger.pushLedger(firstLedger); mMasterLedger.pushLedger(firstLedger);
Ledger::pointer secondLedger = firstLedger->closeLedger(time(NULL)); Ledger::pointer secondLedger = boost::make_shared<Ledger>(firstLedger);
mMasterLedger.pushLedger(secondLedger); mMasterLedger.pushLedger(secondLedger);
assert(!!secondLedger->getAccountState(rootAddress)); assert(!!secondLedger->getAccountState(rootAddress));
mMasterLedger.setSynced(); mMasterLedger.setSynced();
@@ -126,6 +177,7 @@ void Application::run()
mWallet.load(); mWallet.load();
// mWallet.syncToLedger(true, &(*secondLedger)); // mWallet.syncToLedger(true, &(*secondLedger));
mNetOps.setStateTimer(5);
// temporary // temporary
mIOService.run(); // This blocks mIOService.run(); // This blocks

View File

@@ -3,7 +3,6 @@
#include "UniqueNodeList.h" #include "UniqueNodeList.h"
#include "ConnectionPool.h" #include "ConnectionPool.h"
#include "TimingService.h"
#include "PubKeyCache.h" #include "PubKeyCache.h"
#include "ScopedLock.h" #include "ScopedLock.h"
#include "LedgerMaster.h" #include "LedgerMaster.h"
@@ -34,12 +33,10 @@ public:
class Application class Application
{ {
NetworkOPs mNetOps;
Wallet mWallet;
boost::asio::io_service mIOService; boost::asio::io_service mIOService;
TimingService mTimingService; NetworkOPs mNetOps;
Wallet mWallet;
UniqueNodeList mUNL; UniqueNodeList mUNL;
PubKeyCache mPKCache; PubKeyCache mPKCache;
LedgerMaster mMasterLedger; LedgerMaster mMasterLedger;

View File

@@ -1,31 +1,15 @@
#ifndef __BINARYFORMATS__ #ifndef __BINARYFORMATS__
#define __BINARYFORMATS__ #define __BINARYFORMATS__
// binary transaction
const int BTxSize=145;
const int BTxPDestAcct=0, BTxLDestAact=20; // destination account pubkey Hash160
const int BTxPAmount=20, BTxLAmount=8; // amount
const int BTxPSASeq=28, BTxLASeq=4; // source account sequence number
const int BTxPSLIdx=32, BTxLSLIdx=4; // source ledger index
const int BTxPSTag=36, BTxLSTag=4; // source tag
const int BTxPSPubK=40, BTxLSPubK=33; // source public key
const int BTxPSig=73, BTxLSig=72; // signature
// ledger (note: fields after the timestamp are not part of the hash) // ledger (note: fields after the timestamp are not part of the hash)
const int BLgSize=192; const int BLgSize=190;
const int BLgPIndex=0, BLgLIndex=4; // ledger index const int BLgPIndex=0, BLgLIndex=4; // ledger index
const int BLgPTotCoins=4, BLgLTotCoins=8; // total native coins const int BLgPTotCoins=4, BLgLTotCoins=8; // total native coins
const int BLgPPrevLg=12, BLgLPrevLg=32; // previous ledger hash const int BLgPPrevLg=12, BLgLPrevLg=32; // previous ledger hash
const int BLgPTxT=44, BLgLTxT=32; // transaction tree hash const int BLgPTxT=44, BLgLTxT=32; // transaction tree hash
const int BLgPAcT=76, BLgLPAct=32; // account state hash const int BLgPAcT=76, BLgLPAct=32; // account state hash
const int BLgPClTs=108, BLgLClTs=8; // closing timestamp const int BLgPClTs=108, BLgLClTs=8; // closing timestamp
const int BLgPConf=116, BLgLPConf=4; // confidence const int BLgPNlIn=116, BLgLNlIn=2;
const int BLgPSig=120, BLgLSig=72; // signature const int BLgPSig=118, BLgLSig=72; // signature
// account status
const int BAsSize=32;
const int BAsPID=0, BAsLID=20; // account pubkey Hash160
const int BAsPBalance=20, BAsLBalance=8; // account balance
const int BAsPSequence=28, BASLSequence=4; // account sequence
#endif #endif

View File

@@ -52,7 +52,7 @@ int commandLineRPC(const std::vector<std::string>& vCmd)
int nRet = 0; int nRet = 0;
try try
{ {
if (vCmd.size() < 2) return 1; if (!vCmd.size()) return 1;
std::string strMethod = vCmd[0]; std::string strMethod = vCmd[0];

View File

@@ -19,7 +19,7 @@
#define SECTION_PEER_START_MAX "peer_start_max" #define SECTION_PEER_START_MAX "peer_start_max"
#define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water" #define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water"
#define SECTION_NETWORK_QUORUM "network_quorum" #define SECTION_NETWORK_QUORUM "network_quorum"
#define SECTION_BELIEF_QUORUM "belief_quorum" #define SECTION_VALIDATION_QUORUM "validation_quorum"
Config theConfig; Config theConfig;
@@ -33,8 +33,8 @@ Config::Config()
RPC_PORT = 5001; RPC_PORT = 5001;
NUMBER_CONNECTIONS = 30; NUMBER_CONNECTIONS = 30;
// a new ledger every 30 min // a new ledger every minute
LEDGER_SECONDS = (60*30); LEDGER_SECONDS = 60;
RPC_USER = "admin"; RPC_USER = "admin";
RPC_PASSWORD = "pass"; RPC_PASSWORD = "pass";
@@ -49,8 +49,8 @@ Config::Config()
TRANSACTION_FEE_BASE = 1000; TRANSACTION_FEE_BASE = 1000;
NETWORK_QUORUM = 0; NETWORK_QUORUM = 0; // Don't need to see other nodes
BELIEF_QUORUM = 1; VALIDATION_QUORUM = 1; // Only need one node to vouch
} }
void Config::load() void Config::load()
@@ -101,10 +101,10 @@ void Config::load()
PEER_CONNECT_LOW_WATER = MAX(1, boost::lexical_cast<int>(strTemp)); PEER_CONNECT_LOW_WATER = MAX(1, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_NETWORK_QUORUM, strTemp)) if (sectionSingleB(secConfig, SECTION_NETWORK_QUORUM, strTemp))
NETWORK_QUORUM = MIN(0, boost::lexical_cast<int>(strTemp)); NETWORK_QUORUM = MAX(0, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_BELIEF_QUORUM, strTemp)) if (sectionSingleB(secConfig, SECTION_VALIDATION_QUORUM, strTemp))
BELIEF_QUORUM = MIN(0, boost::lexical_cast<int>(strTemp)); VALIDATION_QUORUM = MAX(0, boost::lexical_cast<int>(strTemp));
} }
} }

View File

@@ -7,7 +7,7 @@
#define VALIDATORS_SITE "redstem.com" #define VALIDATORS_SITE "redstem.com"
#define VALIDATORS_FILE_NAME "validators.txt" #define VALIDATORS_FILE_NAME "validators.txt"
const int SYSTEM_PEER_PORT=6561; const int SYSTEM_PEER_PORT = 6561;
// Allow anonymous DH. // Allow anonymous DH.
#define DEFAULT_PEER_SSL_CIPHER_LIST "ALL:!LOW:!EXP:!MD5:@STRENGTH" #define DEFAULT_PEER_SSL_CIPHER_LIST "ALL:!LOW:!EXP:!MD5:@STRENGTH"
@@ -35,8 +35,9 @@ public:
int LEDGER_PROPOSAL_DELAY_SECONDS; int LEDGER_PROPOSAL_DELAY_SECONDS;
int LEDGER_AVALANCHE_SECONDS; int LEDGER_AVALANCHE_SECONDS;
// Note: The following parameters do not relate to the UNL or trust at all
int NETWORK_QUORUM; // Minimum number of nodes to consider the network present int NETWORK_QUORUM; // Minimum number of nodes to consider the network present
int BELIEF_QUORUM; // Percent agreement needed to sync ledger w/o validations int VALIDATION_QUORUM; // Minimum validations to consider ledger authoritative
// node networking parameters // node networking parameters
std::string PEER_IP; std::string PEER_IP;

View File

@@ -123,8 +123,9 @@ void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg)
BOOST_FOREACH(naPeer pair, mConnectedMap) BOOST_FOREACH(naPeer pair, mConnectedMap)
{ {
Peer::pointer peer = pair.second; Peer::pointer peer = pair.second;
if (!peer)
if(!fromPeer || !(peer.get() == fromPeer)) std::cerr << "CP::RM null peer in list" << std::endl;
else if (!fromPeer || !(peer.get() == fromPeer))
peer->sendPacket(msg); peer->sendPacket(msg);
} }
} }
@@ -176,7 +177,7 @@ bool ConnectionPool::connectTo(const std::string& strIp, int iPort)
if (it == mIpMap.end()) if (it == mIpMap.end())
{ {
// Did not find it. Not already connecting or connected. // Did not find it. Not already connecting or connected.
std::cerr << "ConnectionPool::connectTo: Connectting: " std::cerr << "ConnectionPool::connectTo: Connecting: "
<< strIp << " " << iPort << std::endl; << strIp << " " << iPort << std::endl;
Peer::pointer peer(Peer::create(theApp->getIOService(), mCtx)); Peer::pointer peer(Peer::create(theApp->getIOService(), mCtx));
@@ -208,8 +209,23 @@ Json::Value ConnectionPool::getPeersJson()
BOOST_FOREACH(naPeer pair, mConnectedMap) BOOST_FOREACH(naPeer pair, mConnectedMap)
{ {
Peer::pointer peer = pair.second; Peer::pointer peer = pair.second;
if (!peer)
std::cerr << "CP::GPH null peer" << std::endl;
else ret.append(peer->getJson());
}
ret.append(peer->getJson()); return ret;
}
std::vector<Peer::pointer> ConnectionPool::getPeerVector()
{
std::vector<Peer::pointer> ret;
ret.reserve(mConnectedMap.size());
BOOST_FOREACH(naPeer pair, mConnectedMap)
{
assert(!!pair.second);
ret.push_back(pair.second);
} }
return ret; return ret;
@@ -221,7 +237,7 @@ bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& na)
bool bSuccess; bool bSuccess;
std::cerr << "ConnectionPool::peerConnected: " << na.humanNodePublic() << std::endl; std::cerr << "ConnectionPool::peerConnected: " << na.humanNodePublic() << std::endl;
assert(!!peer);
if (na == theApp->getWallet().getNodePublic()) if (na == theApp->getWallet().getNodePublic())
{ {
std::cerr << "ConnectionPool::peerConnected: To self." << std::endl; std::cerr << "ConnectionPool::peerConnected: To self." << std::endl;
@@ -281,9 +297,12 @@ void ConnectionPool::peerDisconnected(Peer::pointer peer, const ipPort& ipPeer,
void ConnectionPool::peerFailed(const std::string& strIp, int iPort) void ConnectionPool::peerFailed(const std::string& strIp, int iPort)
{ {
if (bScanning && !mScanIp.compare(strIp), mScanPort == iPort) // If the fail was our scan, we are no longer scanning.
if (bScanning && !mScanIp.compare(strIp) && mScanPort == iPort)
{ {
bScanning = false; bScanning = false;
// Look for more to scan.
scanRefresh(); scanRefresh();
} }
} }

View File

@@ -72,6 +72,7 @@ public:
void peerFailed(const std::string& strIp, int iPort); void peerFailed(const std::string& strIp, int iPort);
Json::Value getPeersJson(); Json::Value getPeersJson();
std::vector<Peer::pointer> getPeerVector();
// //
// Scanning // Scanning

View File

@@ -9,21 +9,21 @@
bool HashedObject::checkHash() const bool HashedObject::checkHash() const
{ {
uint256 hash=Serializer::getSHA512Half(mData); uint256 hash = Serializer::getSHA512Half(mData);
return hash==mHash; return hash == mHash;
} }
bool HashedObject::checkFixHash() bool HashedObject::checkFixHash()
{ {
uint256 hash=Serializer::getSHA512Half(mData); uint256 hash = Serializer::getSHA512Half(mData);
if(hash==mHash) return true; if (hash == mHash) return true;
mHash=hash; mHash = hash;
return false; return false;
} }
void HashedObject::setHash() void HashedObject::setHash()
{ {
mHash=Serializer::getSHA512Half(mData); mHash = Serializer::getSHA512Half(mData);
} }
/* /*
@@ -39,12 +39,12 @@ CREATE INDEX ObjectLocate ON CommittedObjects(LedgerIndex, ObjType);
bool HashedObject::store(HashedObjectType type, uint32 index, const std::vector<unsigned char>& data, bool HashedObject::store(HashedObjectType type, uint32 index, const std::vector<unsigned char>& data,
const uint256& hash) const uint256& hash)
{ {
if(!theApp->getHashNodeDB()) return true; if (!theApp->getHashNodeDB()) return true;
#ifdef DEBUG #ifdef DEBUG
Serializer s(data); Serializer s(data);
assert(hash==s.getSHA512Half()); assert(hash == s.getSHA512Half());
#endif #endif
std::string sql="INSERT INTO CommitedObjects (Hash,ObjType,LedgerIndex,Object) VALUES ('"; std::string sql = "INSERT INTO CommitedObjects (Hash,ObjType,LedgerIndex,Object) VALUES ('";
sql.append(hash.GetHex()); sql.append(hash.GetHex());
switch(type) switch(type)
{ {
@@ -63,8 +63,8 @@ bool HashedObject::store(HashedObjectType type, uint32 index, const std::vector<
sql.append(");"); sql.append(");");
ScopedLock sl(theApp->getHashNodeDB()->getDBLock()); ScopedLock sl(theApp->getHashNodeDB()->getDBLock());
Database* db=theApp->getHashNodeDB()->getDB(); Database* db = theApp->getHashNodeDB()->getDB();
return db->executeSQL(sql.c_str()); return db->executeSQL(sql);
} }
bool HashedObject::store() const bool HashedObject::store() const
@@ -77,8 +77,8 @@ bool HashedObject::store() const
HashedObject::pointer HashedObject::retrieve(const uint256& hash) HashedObject::pointer HashedObject::retrieve(const uint256& hash)
{ {
if(!theApp->getHashNodeDB()) return HashedObject::pointer(); if (!theApp->getHashNodeDB()) return HashedObject::pointer();
std::string sql="SELECT * from CommitedObjects WHERE Hash='"; std::string sql = "SELECT * from CommitedObjects WHERE Hash='";
sql.append(hash.GetHex()); sql.append(hash.GetHex());
sql.append("';"); sql.append("';");
@@ -86,39 +86,41 @@ HashedObject::pointer HashedObject::retrieve(const uint256& hash)
uint32 index; uint32 index;
std::vector<unsigned char> data; std::vector<unsigned char> data;
data.reserve(8192); data.reserve(8192);
if(1)
{ {
ScopedLock sl(theApp->getHashNodeDB()->getDBLock()); ScopedLock sl(theApp->getHashNodeDB()->getDBLock());
Database* db=theApp->getHashNodeDB()->getDB(); Database* db = theApp->getHashNodeDB()->getDB();
if(!db->executeSQL(sql.c_str()) || !db->startIterRows() || !db->getNextRow()) if (!db->executeSQL(sql) || !db->startIterRows())
return HashedObject::pointer(); return HashedObject::pointer();
std::string type; std::string type;
db->getStr("ObjType", type); db->getStr("ObjType", type);
if(type.size()==0) return HashedObject::pointer(); if (type.size() == 0) return HashedObject::pointer();
index=db->getBigInt("LedgerIndex");
int size=db->getBinary("Object", NULL, 0); index = db->getBigInt("LedgerIndex");
int size = db->getBinary("Object", NULL, 0);
data.resize(size); data.resize(size);
db->getBinary("Object", &(data.front()), size); db->getBinary("Object", &(data.front()), size);
db->endIterRows(); db->endIterRows();
} }
HashedObjectType htype=UNKNOWN; HashedObjectType htype = UNKNOWN;
switch(type[0]) switch(type[0])
{ {
case 'L': htype=LEDGER; break; case 'L': htype = LEDGER; break;
case 'T': htype=TRANSACTION; break; case 'T': htype = TRANSACTION; break;
case 'A': htype=ACCOUNT_NODE; break; case 'A': htype = ACCOUNT_NODE; break;
case 'N': htype=TRANSACTION_NODE; break; case 'N': htype = TRANSACTION_NODE; break;
} }
HashedObject::pointer obj(new HashedObject(htype, index, data)); HashedObject::pointer obj = boost::make_shared<HashedObject>(htype, index, data);
obj->mHash=hash; obj->mHash = hash;
#ifdef DEBUG #ifdef DEBUG
assert(obj->checkHash()); assert(obj->checkHash());
#endif #endif
return obj; return obj;
} }
// vim:ts=4

View File

@@ -167,7 +167,7 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult)
if (!mShutdown) if (!mShutdown)
{ {
// std::cerr << "Connectted." << std::endl; // std::cerr << "Connected." << std::endl;
mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true)); mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true));
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_peer); mSocketSsl.set_verify_mode(boost::asio::ssl::verify_peer);

View File

@@ -7,6 +7,7 @@
#include "Application.h" #include "Application.h"
#include "Ledger.h" #include "Ledger.h"
#include "utils.h"
#include "../obj/src/newcoin.pb.h" #include "../obj/src/newcoin.pb.h"
#include "PackedMessage.h" #include "PackedMessage.h"
#include "Config.h" #include "Config.h"
@@ -16,7 +17,8 @@
#include "BinaryFormats.h" #include "BinaryFormats.h"
Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount),
mTimeStamp(0), mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false) mCloseTime(0), mLedgerSeq(0), mLedgerInterval(60), mClosed(false), mValidHash(false),
mAccepted(false), mImmutable(false)
{ {
mTransactionMap = boost::make_shared<SHAMap>(); mTransactionMap = boost::make_shared<SHAMap>();
mAccountStateMap = boost::make_shared<SHAMap>(); mAccountStateMap = boost::make_shared<SHAMap>();
@@ -35,22 +37,24 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s
Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq) uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq)
: mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), : mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash),
mTotCoins(totCoins), mTimeStamp(timeStamp), mLedgerSeq(ledgerSeq), mTotCoins(totCoins), mCloseTime(timeStamp), mLedgerSeq(ledgerSeq), mLedgerInterval(60),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false) mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false)
{ {
updateHash(); updateHash();
} }
Ledger::Ledger(Ledger &prevLedger, uint64 ts) : mTimeStamp(ts), Ledger::Ledger(Ledger::pointer prevLedger) : mParentHash(prevLedger->getHash()), mTotCoins(prevLedger->mTotCoins),
mLedgerSeq(prevLedger->mLedgerSeq + 1), mLedgerInterval(prevLedger->mLedgerInterval),
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false),
mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap) mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger->mAccountStateMap)
{ {
mParentHash = prevLedger.getHash(); prevLedger->setClosed();
mLedgerSeq = prevLedger.mLedgerSeq+1; prevLedger->updateHash();
mAccountStateMap->setSeq(mLedgerSeq); mAccountStateMap->setSeq(mLedgerSeq);
mCloseTime = prevLedger->getNextLedgerClose();
} }
Ledger::Ledger(const std::vector<unsigned char>& rawLedger) : mTotCoins(0), mTimeStamp(0), Ledger::Ledger(const std::vector<unsigned char>& rawLedger) : mTotCoins(0), mCloseTime(0),
mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true) mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
{ {
Serializer s(rawLedger); Serializer s(rawLedger);
@@ -60,7 +64,8 @@ Ledger::Ledger(const std::vector<unsigned char>& rawLedger) : mTotCoins(0), mTim
if (!s.get256(mParentHash, BLgPPrevLg)) return; if (!s.get256(mParentHash, BLgPPrevLg)) return;
if (!s.get256(mTransHash, BLgPTxT)) return; if (!s.get256(mTransHash, BLgPTxT)) return;
if (!s.get256(mAccountHash, BLgPAcT)) return; if (!s.get256(mAccountHash, BLgPAcT)) return;
if (!s.get64(mTimeStamp, BLgPClTs)) return; if (!s.get64(mCloseTime, BLgPClTs)) return;
if (!s.get16(mLedgerInterval, BLgPNlIn)) return;
updateHash(); updateHash();
if(mValidHash) if(mValidHash)
{ {
@@ -69,7 +74,7 @@ Ledger::Ledger(const std::vector<unsigned char>& rawLedger) : mTotCoins(0), mTim
} }
} }
Ledger::Ledger(const std::string& rawLedger) : mTotCoins(0), mTimeStamp(0), Ledger::Ledger(const std::string& rawLedger) : mTotCoins(0), mCloseTime(0),
mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true) mLedgerSeq(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true)
{ {
Serializer s(rawLedger); Serializer s(rawLedger);
@@ -79,7 +84,8 @@ Ledger::Ledger(const std::string& rawLedger) : mTotCoins(0), mTimeStamp(0),
if (!s.get256(mParentHash, BLgPPrevLg)) return; if (!s.get256(mParentHash, BLgPPrevLg)) return;
if (!s.get256(mTransHash, BLgPTxT)) return; if (!s.get256(mTransHash, BLgPTxT)) return;
if (!s.get256(mAccountHash, BLgPAcT)) return; if (!s.get256(mAccountHash, BLgPAcT)) return;
if (!s.get64(mTimeStamp, BLgPClTs)) return; if (!s.get64(mCloseTime, BLgPClTs)) return;
if (!s.get16(mLedgerInterval, BLgPNlIn)) return;
updateHash(); updateHash();
if(mValidHash) if(mValidHash)
{ {
@@ -100,7 +106,7 @@ void Ledger::updateHash()
Serializer s(116); Serializer s(116);
addRaw(s); addRaw(s);
mHash =s.getSHA512Half(); mHash = s.getSHA512Half();
mValidHash = true; mValidHash = true;
} }
@@ -111,7 +117,8 @@ void Ledger::addRaw(Serializer &s)
s.add256(mParentHash); s.add256(mParentHash);
s.add256(mTransHash); s.add256(mTransHash);
s.add256(mAccountHash); s.add256(mAccountHash);
s.add64(mTimeStamp); s.add64(mCloseTime);
s.add16(mLedgerInterval);
} }
AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID) AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
@@ -124,7 +131,7 @@ AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
if (!item) if (!item)
{ {
#ifdef DEBUG #ifdef DEBUG
// std::cerr << " notfound" << std::endl; // std::cerr << " notfound" << std::endl;
#endif #endif
return AccountState::pointer(); return AccountState::pointer();
} }
@@ -175,14 +182,6 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) const
return txn; return txn;
} }
Ledger::pointer Ledger::closeLedger(uint64 timeStamp)
{ // close this ledger, return a pointer to the next ledger
// CAUTION: New ledger needs its SHAMap's connected to storage
updateHash();
setClosed();
return Ledger::pointer(new Ledger(*this, timeStamp)); // can't use make_shared, constructor is protected
}
bool Ledger::unitTest() bool Ledger::unitTest()
{ {
#if 0 #if 0
@@ -225,13 +224,13 @@ bool Ledger::unitTest()
uint256 Ledger::getHash() uint256 Ledger::getHash()
{ {
if(!mValidHash) updateHash(); if(!mValidHash) updateHash();
return(mHash); return(mHash);
} }
void Ledger::saveAcceptedLedger(Ledger::pointer ledger) void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
{ {
std::string sql="INSERT INTO Ledgers " std::string sql="INSERT INTO Ledgers "
"(LedgerHash,LedgerSeq,TotalCoins,,ClosingTime,AccountSetHash,TransSetHash) VALUES ('"; "(LedgerHash,LedgerSeq,TotalCoins,ClosingTime,AccountSetHash,TransSetHash) VALUES ('";
sql.append(ledger->getHash().GetHex()); sql.append(ledger->getHash().GetHex());
sql.append("','"); sql.append("','");
sql.append(boost::lexical_cast<std::string>(ledger->mLedgerSeq)); sql.append(boost::lexical_cast<std::string>(ledger->mLedgerSeq));
@@ -240,7 +239,7 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
sql.append("','"); sql.append("','");
sql.append(boost::lexical_cast<std::string>(ledger->mTotCoins)); sql.append(boost::lexical_cast<std::string>(ledger->mTotCoins));
sql.append("','"); sql.append("','");
sql.append(boost::lexical_cast<std::string>(ledger->mTimeStamp)); sql.append(boost::lexical_cast<std::string>(ledger->mCloseTime));
sql.append("','"); sql.append("','");
sql.append(ledger->mAccountHash.GetHex()); sql.append(ledger->mAccountHash.GetHex());
sql.append("','"); sql.append("','");
@@ -248,7 +247,7 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
sql.append("');"); sql.append("');");
ScopedLock sl(theApp->getLedgerDB()->getDBLock()); ScopedLock sl(theApp->getLedgerDB()->getDBLock());
theApp->getLedgerDB()->getDB()->executeSQL(sql.c_str()); theApp->getLedgerDB()->getDB()->executeSQL(sql);
// write out dirty nodes // write out dirty nodes
while(ledger->mTransactionMap->flushDirty(64, TRANSACTION_NODE, ledger->mLedgerSeq)) while(ledger->mTransactionMap->flushDirty(64, TRANSACTION_NODE, ledger->mLedgerSeq))
@@ -269,7 +268,8 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
{ {
ScopedLock sl(theApp->getLedgerDB()->getDBLock()); ScopedLock sl(theApp->getLedgerDB()->getDBLock());
Database *db = theApp->getLedgerDB()->getDB(); Database *db = theApp->getLedgerDB()->getDB();
if (!db->executeSQL(sql.c_str()) || !db->startIterRows() || !db->getNextRow())
if (!db->executeSQL(sql) || !db->startIterRows())
return Ledger::pointer(); return Ledger::pointer();
db->getStr("LedgerHash", hash); db->getStr("LedgerHash", hash);
@@ -285,7 +285,7 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
ledgerSeq = db->getBigInt("LedgerSeq"); ledgerSeq = db->getBigInt("LedgerSeq");
db->endIterRows(); db->endIterRows();
} }
Ledger::pointer ret=boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, ledgerSeq); Ledger::pointer ret=boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, ledgerSeq);
if (ret->getHash() != ledgerHash) if (ret->getHash() != ledgerHash)
{ {
@@ -316,18 +316,21 @@ void Ledger::addJson(Json::Value& ret)
Json::Value ledger(Json::objectValue); Json::Value ledger(Json::objectValue);
boost::recursive_mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
ledger["ParentHash"]=mParentHash.GetHex(); ledger["ParentHash"] = mParentHash.GetHex();
if(mClosed) if(mClosed)
{ {
ledger["Hash"]=mHash.GetHex(); ledger["Hash"] = mHash.GetHex();
ledger["TransactionHash"]=mTransHash.GetHex(); ledger["TransactionHash"] = mTransHash.GetHex();
ledger["AccountHash"]=mAccountHash.GetHex(); ledger["AccountHash"] = mAccountHash.GetHex();
ledger["Closed"]=true; ledger["Closed"] = true;
ledger["Accepted"]=mAccepted; ledger["Accepted"] = mAccepted;
ledger["TotalCoins"] = boost::lexical_cast<std::string>(mTotCoins);
} }
else ledger["Closed"]=false; else ledger["Closed"] = false;
ret[boost::lexical_cast<std::string>(mLedgerSeq)]=ledger; if (mCloseTime != 0)
ledger["CloseTime"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime));
ret[boost::lexical_cast<std::string>(mLedgerSeq)] = ledger;
} }
Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger::pointer newPrevious, int limit) Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger::pointer newPrevious, int limit)
@@ -339,42 +342,42 @@ Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger
int count; int count;
// 1) Validate sequences and make sure the specified ledger is a valid prior ledger // 1) Validate sequences and make sure the specified ledger is a valid prior ledger
if(newPrevious->getLedgerSeq()!=oldPrevious->getLedgerSeq()) return Ledger::pointer(); if (newPrevious->getLedgerSeq() != oldPrevious->getLedgerSeq()) return Ledger::pointer();
// 2) Begin building a new ledger with the specified ledger as previous. // 2) Begin building a new ledger with the specified ledger as previous.
Ledger* newLedger=new Ledger(*newPrevious, mTimeStamp); Ledger::pointer newLedger = boost::make_shared<Ledger>(newPrevious);
// 3) For any transactions in our previous ledger but not in the new previous ledger, add them to the set // 3) For any transactions in our previous ledger but not in the new previous ledger, add them to the set
SHAMap::SHAMapDiff mapDifferences; SHAMap::SHAMapDiff mapDifferences;
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> > TxnDiff; std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> > TxnDiff;
if(!newPrevious->mTransactionMap->compare(oldPrevious->mTransactionMap, mapDifferences, limit)) if (!newPrevious->mTransactionMap->compare(oldPrevious->mTransactionMap, mapDifferences, limit))
return Ledger::pointer(); return Ledger::pointer();
if(!Transaction::convertToTransactions(oldPrevious->getLedgerSeq(), newPrevious->getLedgerSeq(), if (!Transaction::convertToTransactions(oldPrevious->getLedgerSeq(), newPrevious->getLedgerSeq(),
false, true, mapDifferences, TxnDiff)) false, true, mapDifferences, TxnDiff))
return Ledger::pointer(); // new previous ledger contains invalid transactions return Ledger::pointer(); // new previous ledger contains invalid transactions
// 4) Try to add those transactions to the new ledger. // 4) Try to add those transactions to the new ledger.
do do
{ {
count=0; count = 0;
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >::iterator it = TxnDiff.begin(); std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >::iterator it = TxnDiff.begin();
while (it != TxnDiff.end()) while (it != TxnDiff.end())
{ {
Transaction::pointer& tx = it->second.second; Transaction::pointer& tx = it->second.second;
if (!tx || newLedger->addTransaction(tx)) if (!tx || newLedger->addTransaction(tx)) // FIXME: addTransaction doesn't do checks
{ {
count++; ++count;
TxnDiff.erase(it++); TxnDiff.erase(it++);
} }
else ++it; else ++it;
} }
} while (count!=0); } while (count != 0);
// WRITEME: Handle rejected transactions left in TxnDiff // WRITEME: Handle rejected transactions left in TxnDiff
// 5) Try to add transactions from this ledger to the new ledger. // 5) Try to add transactions from this ledger to the new ledger.
std::map<uint256, Transaction::pointer> txnMap; std::map<uint256, Transaction::pointer> txnMap;
for(SHAMapItem::pointer mit = peekTransactionMap()->peekFirstItem(); for (SHAMapItem::pointer mit = peekTransactionMap()->peekFirstItem();
!!mit; mit = peekTransactionMap()->peekNextItem(mit->getTag())) !!mit; mit = peekTransactionMap()->peekNextItem(mit->getTag()))
{ {
uint256 txnID = mit->getTag(); uint256 txnID = mit->getTag();
@@ -385,18 +388,18 @@ Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger
do do
{ {
count=0; count = 0;
std::map<uint256, Transaction::pointer>::iterator it = txnMap.begin(); std::map<uint256, Transaction::pointer>::iterator it = txnMap.begin();
while (it != txnMap.end()) while (it != txnMap.end())
{ {
if(newLedger->addTransaction(it->second)) if (newLedger->addTransaction(it->second)) // FIXME: addTransaction doesn't do checks
{ {
count++; ++count;
txnMap.erase(it++); txnMap.erase(it++);
} }
else ++it; else ++it;
} }
} while(count!=0); } while(count != 0);
// WRITEME: Handle rejected transactions left in txnMap // WRITEME: Handle rejected transactions left in txnMap
@@ -406,7 +409,7 @@ Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger
void Ledger::setAcquiring(void) void Ledger::setAcquiring(void)
{ {
if(!mTransactionMap || !mAccountStateMap) throw SHAMapException(InvalidMap); if (!mTransactionMap || !mAccountStateMap) throw SHAMapException(InvalidMap);
mTransactionMap->setSynching(); mTransactionMap->setSynching();
mAccountStateMap->setSynching(); mAccountStateMap->setSynching();
} }
@@ -425,3 +428,25 @@ bool Ledger::isAcquiringAS(void)
{ {
return mAccountStateMap->isSynching(); return mAccountStateMap->isSynching();
} }
boost::posix_time::ptime Ledger::getCloseTime() const
{
return ptFromSeconds(mCloseTime);
}
void Ledger::setCloseTime(boost::posix_time::ptime ptm)
{
mCloseTime = iToSeconds(ptm);
}
uint64 Ledger::getNextLedgerClose() const
{
if (mCloseTime == 0)
{
uint64 closeTime = theApp->getOPs().getNetworkTimeNC() + mLedgerInterval - 1;
return closeTime - (closeTime % mLedgerInterval);
}
return mCloseTime + mLedgerInterval;
}
// vim:ts=4

View File

@@ -6,6 +6,7 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp> #include <boost/enable_shared_from_this.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "../json/value.h" #include "../json/value.h"
@@ -15,13 +16,12 @@
#include "BitcoinUtil.h" #include "BitcoinUtil.h"
#include "SHAMap.h" #include "SHAMap.h"
enum LedgerStateParms enum LedgerStateParms
{ {
lepNONE = 0, // no special flags lepNONE = 0, // no special flags
// input flags // input flags
lepCREATE, // Create if not present lepCREATE, // Create if not present
// output flags // output flags
lepOKAY, // success lepOKAY, // success
@@ -37,43 +37,42 @@ class Ledger : public boost::enable_shared_from_this<Ledger>
public: public:
typedef boost::shared_ptr<Ledger> pointer; typedef boost::shared_ptr<Ledger> pointer;
enum TransResult enum TransResult
{ {
TR_ERROR =-1, TR_ERROR = -1,
TR_SUCCESS =0, TR_SUCCESS = 0,
TR_NOTFOUND =1, TR_NOTFOUND = 1,
TR_ALREADY =2, TR_ALREADY = 2,
TR_BADTRANS =3, // the transaction itself is corrupt TR_BADTRANS = 3, // the transaction itself is corrupt
TR_BADACCT =4, // one of the accounts is invalid TR_BADACCT = 4, // one of the accounts is invalid
TR_INSUFF =5, // the sending(apply)/receiving(remove) account is broke TR_INSUFF = 5, // the sending(apply)/receiving(remove) account is broke
TR_PASTASEQ =6, // account is past this transaction TR_PASTASEQ = 6, // account is past this transaction
TR_PREASEQ =7, // account is missing transactions before this TR_PREASEQ = 7, // account is missing transactions before this
TR_BADLSEQ =8, // ledger too early TR_BADLSEQ = 8, // ledger too early
TR_TOOSMALL =9, // amount is less than Tx fee TR_TOOSMALL = 9, // amount is less than Tx fee
}; };
private: private:
uint256 mHash, mParentHash, mTransHash, mAccountHash; uint256 mHash, mParentHash, mTransHash, mAccountHash;
uint64 mTotCoins, mTimeStamp; uint64 mTotCoins;
uint64 mCloseTime; // when this ledger closes
uint32 mLedgerSeq; uint32 mLedgerSeq;
uint16 mLedgerInterval;
bool mClosed, mValidHash, mAccepted, mImmutable; bool mClosed, mValidHash, mAccepted, mImmutable;
SHAMap::pointer mTransactionMap, mAccountStateMap; SHAMap::pointer mTransactionMap, mAccountStateMap;
mutable boost::recursive_mutex mLock; mutable boost::recursive_mutex mLock;
Ledger(const Ledger&); // no implementation Ledger(const Ledger&); // no implementation
Ledger& operator=(const Ledger&); // no implementation Ledger& operator=(const Ledger&); // no implementation
protected: protected:
Ledger(Ledger& previous, uint64 timestamp); // ledger after this one
void updateHash();
bool addTransaction(Transaction::pointer); bool addTransaction(Transaction::pointer);
bool addTransaction(const uint256& id, const Serializer& txn, uint64_t fee); bool addTransaction(const uint256& id, const Serializer& txn, uint64_t fee);
static Ledger::pointer getSQL(const std::string& sqlStatement); static Ledger::pointer getSQL(const std::string& sqlStatement);
SerializedLedgerEntry::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID, SerializedLedgerEntry::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID,
@@ -82,25 +81,33 @@ protected:
public: public:
Ledger(const NewcoinAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger Ledger(const NewcoinAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger
Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq); // used for received ledgers uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq); // used for database ledgers
Ledger(const std::vector<unsigned char>& rawLedger); Ledger(const std::vector<unsigned char>& rawLedger);
Ledger(const std::string& rawLedger); Ledger(const std::string& rawLedger);
Ledger(Ledger::pointer previous); // ledger after this one
void setClosed() { mClosed=true; } void updateHash();
void setAccepted() { mAccepted=true; } void setClosed() { mClosed = true; }
bool isClosed() { return mClosed; } void setAccepted() { mAccepted = true; }
bool isAccepted() { return mAccepted; } bool isClosed() { return mClosed; }
bool isAccepted() { return mAccepted; }
// ledger signature operations // ledger signature operations
void addRaw(Serializer &s); void addRaw(Serializer &s);
uint256 getHash(); uint256 getHash();
const uint256& getParentHash() const { return mParentHash; } const uint256& getParentHash() const { return mParentHash; }
const uint256& getTransHash() const { return mTransHash; } const uint256& getTransHash() const { return mTransHash; }
const uint256& getAccountHash() const { return mAccountHash; } const uint256& getAccountHash() const { return mAccountHash; }
uint64 getTotalCoins() const { return mTotCoins; } uint64 getTotalCoins() const { return mTotCoins; }
uint64 getTimeStamp() const { return mTimeStamp; } uint64 getCloseTimeNC() const { return mCloseTime; }
uint32 getLedgerSeq() const { return mLedgerSeq; } uint32 getLedgerSeq() const { return mLedgerSeq; }
uint16 getInterval() const { return mLedgerInterval; }
// close time functions
boost::posix_time::ptime getCloseTime() const;
void setCloseTime(boost::posix_time::ptime);
uint64 getNextLedgerClose() const;
// low level functions // low level functions
SHAMap::pointer peekTransactionMap() { return mTransactionMap; } SHAMap::pointer peekTransactionMap() { return mTransactionMap; }
@@ -116,7 +123,7 @@ public:
bool hasTransaction(const uint256& TransID) const; bool hasTransaction(const uint256& TransID) const;
Transaction::pointer getTransaction(const uint256& transID) const; Transaction::pointer getTransaction(const uint256& transID) const;
Ledger::pointer switchPreviousLedger(Ledger::pointer oldPrevious, Ledger::pointer newPrevious, int limit); Ledger::pointer switchPreviousLedger(Ledger::pointer oldPrevious, Ledger::pointer newPrevious, int limit);
// high-level functions // high-level functions
AccountState::pointer getAccountState(const NewcoinAddress& acctID); AccountState::pointer getAccountState(const NewcoinAddress& acctID);
@@ -144,7 +151,6 @@ public:
const uint160& currency) const uint160& currency)
{ return getRippleIndex(account.getAccountID(), extendTo.getAccountID(), currency); } { return getRippleIndex(account.getAccountID(), extendTo.getAccountID(), currency); }
Ledger::pointer closeLedger(uint64 timestamp);
bool isCompatible(boost::shared_ptr<Ledger> other); bool isCompatible(boost::shared_ptr<Ledger> other);
bool signLedger(std::vector<unsigned char> &signature, const LocalHanko &hanko); bool signLedger(std::vector<unsigned char> &signature, const LocalHanko &hanko);
@@ -164,3 +170,4 @@ inline LedgerStateParms operator&(const LedgerStateParms& l1, const LedgerStateP
} }
#endif #endif
// vim:ts=4

View File

@@ -1,38 +1,51 @@
#include "boost/foreach.hpp"
#include "boost/make_shared.hpp"
#include "Application.h"
#include "LedgerAcquire.h" #include "LedgerAcquire.h"
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
#include <boost/bind.hpp>
#include "Application.h"
#define LEDGER_ACQUIRE_TIMEOUT 2
LedgerAcquire::LedgerAcquire(const uint256& hash) : mHash(hash), LedgerAcquire::LedgerAcquire(const uint256& hash) : mHash(hash),
mComplete(false), mFailed(false), mHaveBase(false), mHaveState(false), mHaveTransactions(false) mComplete(false), mFailed(false), mHaveBase(false), mHaveState(false), mHaveTransactions(false),
mTimer(theApp->getIOService())
{ {
; #ifdef DEBUG
std::cerr << "Acquiring ledger " << mHash.GetHex() << std::endl;
#endif
} }
void LedgerAcquire::done() void LedgerAcquire::done()
{ {
#ifdef DEBUG
std::cerr << "Done acquiring ledger " << mHash.GetHex() << std::endl;
#endif
std::vector< boost::function<void (LedgerAcquire::pointer)> > triggers; std::vector< boost::function<void (LedgerAcquire::pointer)> > triggers;
mLock.lock(); mLock.lock();
triggers=mOnComplete; triggers = mOnComplete;
mOnComplete.empty(); mOnComplete.empty();
mLock.unlock(); mLock.unlock();
for(int i=0; i<triggers.size(); i++) for (int i = 0; i<triggers.size(); ++i)
triggers[i](shared_from_this()); triggers[i](shared_from_this());
} }
void LedgerAcquire::setTimer() void LedgerAcquire::resetTimer()
{ {
// WRITEME mTimer.expires_from_now(boost::posix_time::seconds(LEDGER_ACQUIRE_TIMEOUT));
mTimer.async_wait(boost::bind(&LedgerAcquire::timerEntry,
boost::weak_ptr<LedgerAcquire>(shared_from_this()), boost::asio::placeholders::error));
} }
void LedgerAcquire::timerEntry(boost::weak_ptr<LedgerAcquire> wptr) void LedgerAcquire::timerEntry(boost::weak_ptr<LedgerAcquire> wptr, const boost::system::error_code& result)
{ {
LedgerAcquire::pointer ptr=wptr.lock(); if (result == boost::asio::error::operation_aborted) return;
if(ptr) ptr->trigger(true); LedgerAcquire::pointer ptr = wptr.lock();
if (!!ptr) ptr->trigger(Peer::pointer());
} }
void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)> trigger) void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)> trigger)
@@ -42,29 +55,49 @@ void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)>
mLock.unlock(); mLock.unlock();
} }
void LedgerAcquire::trigger(bool timer) void LedgerAcquire::trigger(Peer::pointer peer)
{ {
if(mComplete || mFailed) return; #ifdef DEBUG
std::cerr << "Trigger acquiring ledger " << mHash.GetHex() << std::endl;
if(!mHaveBase) std::cerr << "complete=" << mComplete << " failed=" << mFailed << std::endl;
std::cerr << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState << std::endl;
#endif
if (mComplete || mFailed)
return;
if (!mHaveBase)
{ {
// WRITEME: Do we need to search for peers? #ifdef DEBUG
boost::shared_ptr<newcoin::TMGetLedger> tmGL=boost::make_shared<newcoin::TMGetLedger>(); std::cerr << "need base" << std::endl;
#endif
boost::shared_ptr<newcoin::TMGetLedger> tmGL = boost::make_shared<newcoin::TMGetLedger>();
tmGL->set_ledgerhash(mHash.begin(), mHash.size()); tmGL->set_ledgerhash(mHash.begin(), mHash.size());
tmGL->set_itype(newcoin::liBASE); tmGL->set_itype(newcoin::liBASE);
sendRequest(tmGL); if (peer)
{
sendRequest(tmGL, peer);
return;
}
else sendRequest(tmGL);
} }
if(mHaveBase && !mHaveTransactions) if (mHaveBase && !mHaveTransactions)
{ {
#ifdef DEBUG
std::cerr << "need tx" << std::endl;
#endif
assert(mLedger); assert(mLedger);
if(mLedger->peekTransactionMap()->getHash().isZero()) if (mLedger->peekTransactionMap()->getHash().isZero())
{ // we need the root node { // we need the root node
boost::shared_ptr<newcoin::TMGetLedger> tmGL=boost::make_shared<newcoin::TMGetLedger>(); boost::shared_ptr<newcoin::TMGetLedger> tmGL = boost::make_shared<newcoin::TMGetLedger>();
tmGL->set_ledgerhash(mHash.begin(), mHash.size()); tmGL->set_ledgerhash(mHash.begin(), mHash.size());
tmGL->set_ledgerseq(mLedger->getLedgerSeq()); tmGL->set_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liTX_NODE); tmGL->set_itype(newcoin::liTX_NODE);
*(tmGL->add_nodeids())=SHAMapNode().getRawString(); *(tmGL->add_nodeids()) = SHAMapNode().getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL); sendRequest(tmGL);
} }
else else
@@ -72,38 +105,51 @@ void LedgerAcquire::trigger(bool timer)
std::vector<SHAMapNode> nodeIDs; std::vector<SHAMapNode> nodeIDs;
std::vector<uint256> nodeHashes; std::vector<uint256> nodeHashes;
mLedger->peekTransactionMap()->getMissingNodes(nodeIDs, nodeHashes, 128); mLedger->peekTransactionMap()->getMissingNodes(nodeIDs, nodeHashes, 128);
if(nodeIDs.empty()) if (nodeIDs.empty())
{ {
if(!mLedger->peekTransactionMap()->isValid()) mFailed=true; if (!mLedger->peekTransactionMap()->isValid()) mFailed = true;
else else
{ {
mHaveTransactions=true; mHaveTransactions = true;
if(mHaveState) mComplete=true; if (mHaveState) mComplete = true;
} }
} }
else else
{ {
boost::shared_ptr<newcoin::TMGetLedger> tmGL=boost::make_shared<newcoin::TMGetLedger>(); boost::shared_ptr<newcoin::TMGetLedger> tmGL = boost::make_shared<newcoin::TMGetLedger>();
tmGL->set_ledgerhash(mHash.begin(), mHash.size()); tmGL->set_ledgerhash(mHash.begin(), mHash.size());
tmGL->set_ledgerseq(mLedger->getLedgerSeq()); tmGL->set_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liTX_NODE); tmGL->set_itype(newcoin::liTX_NODE);
for(std::vector<SHAMapNode>::iterator it=nodeIDs.begin(); it!=nodeIDs.end(); ++it) for (std::vector<SHAMapNode>::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it)
*(tmGL->add_nodeids())=it->getRawString(); *(tmGL->add_nodeids()) = it->getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL); sendRequest(tmGL);
} }
} }
} }
if(mHaveBase && !mHaveState) if (mHaveBase && !mHaveState)
{ {
#ifdef DEBUG
std::cerr << "need as" << std::endl;
#endif
assert(mLedger); assert(mLedger);
if(mLedger->peekAccountStateMap()->getHash().isZero()) if (mLedger->peekAccountStateMap()->getHash().isZero())
{ // we need the root node { // we need the root node
boost::shared_ptr<newcoin::TMGetLedger> tmGL=boost::make_shared<newcoin::TMGetLedger>(); boost::shared_ptr<newcoin::TMGetLedger> tmGL = boost::make_shared<newcoin::TMGetLedger>();
tmGL->set_ledgerhash(mHash.begin(), mHash.size()); tmGL->set_ledgerhash(mHash.begin(), mHash.size());
tmGL->set_ledgerseq(mLedger->getLedgerSeq()); tmGL->set_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liAS_NODE); tmGL->set_itype(newcoin::liAS_NODE);
*(tmGL->add_nodeids())=SHAMapNode().getRawString(); *(tmGL->add_nodeids()) = SHAMapNode().getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL); sendRequest(tmGL);
} }
else else
@@ -111,50 +157,61 @@ void LedgerAcquire::trigger(bool timer)
std::vector<SHAMapNode> nodeIDs; std::vector<SHAMapNode> nodeIDs;
std::vector<uint256> nodeHashes; std::vector<uint256> nodeHashes;
mLedger->peekAccountStateMap()->getMissingNodes(nodeIDs, nodeHashes, 128); mLedger->peekAccountStateMap()->getMissingNodes(nodeIDs, nodeHashes, 128);
if(nodeIDs.empty()) if (nodeIDs.empty())
{ {
if(!mLedger->peekAccountStateMap()->isValid()) mFailed=true; if (!mLedger->peekAccountStateMap()->isValid()) mFailed = true;
else else
{ {
mHaveState=true; mHaveState = true;
if(mHaveTransactions) mComplete=true; if (mHaveTransactions) mComplete = true;
} }
} }
else else
{ {
boost::shared_ptr<newcoin::TMGetLedger> tmGL=boost::make_shared<newcoin::TMGetLedger>(); boost::shared_ptr<newcoin::TMGetLedger> tmGL = boost::make_shared<newcoin::TMGetLedger>();
tmGL->set_ledgerhash(mHash.begin(), mHash.size()); tmGL->set_ledgerhash(mHash.begin(), mHash.size());
tmGL->set_ledgerseq(mLedger->getLedgerSeq()); tmGL->set_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liAS_NODE); tmGL->set_itype(newcoin::liAS_NODE);
for(std::vector<SHAMapNode>::iterator it=nodeIDs.begin(); it!=nodeIDs.end(); ++it) for (std::vector<SHAMapNode>::iterator it =nodeIDs.begin(); it != nodeIDs.end(); ++it)
*(tmGL->add_nodeids())=it->getRawString(); *(tmGL->add_nodeids()) = it->getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL); sendRequest(tmGL);
} }
} }
} }
if(mComplete || mFailed) if (mComplete || mFailed)
done(); done();
else if(timer) else
setTimer(); resetTimer();
}
void LedgerAcquire::sendRequest(boost::shared_ptr<newcoin::TMGetLedger> tmGL, Peer::pointer peer)
{
peer->sendPacket(boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER));
} }
void LedgerAcquire::sendRequest(boost::shared_ptr<newcoin::TMGetLedger> tmGL) void LedgerAcquire::sendRequest(boost::shared_ptr<newcoin::TMGetLedger> tmGL)
{ {
boost::recursive_mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
if(mPeers.empty()) return; if (mPeers.empty()) return;
PackedMessage::pointer packet=boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER); PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER);
std::list<boost::weak_ptr<Peer> >::iterator it=mPeers.begin(); std::list<boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
while(it!=mPeers.end()) while(it != mPeers.end())
{ {
if(it->expired()) if (it->expired())
mPeers.erase(it++); mPeers.erase(it++);
else else
{ {
// FIXME: Track last peer sent to and time sent // FIXME: Track last peer sent to and time sent
it->lock()->sendPacket(packet); Peer::pointer peer = it->lock();
if (peer) peer->sendPacket(packet);
return; return;
} }
} }
@@ -163,33 +220,34 @@ void LedgerAcquire::sendRequest(boost::shared_ptr<newcoin::TMGetLedger> tmGL)
void LedgerAcquire::peerHas(Peer::pointer ptr) void LedgerAcquire::peerHas(Peer::pointer ptr)
{ {
boost::recursive_mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
std::list<boost::weak_ptr<Peer> >::iterator it=mPeers.begin(); std::list<boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
while(it!=mPeers.end()) while (it != mPeers.end())
{ {
Peer::pointer pr=it->lock(); Peer::pointer pr = it->lock();
if(!pr) // we have a dead entry, remove it if (!pr) // we have a dead entry, remove it
it=mPeers.erase(it); it = mPeers.erase(it);
else else
{ {
if(pr->samePeer(ptr)) return; // we already have this peer if (pr->samePeer(ptr)) return; // we already have this peer
++it; ++it;
} }
} }
mPeers.push_back(ptr); mPeers.push_back(ptr);
if (mPeers.size() == 1) trigger(ptr);
} }
void LedgerAcquire::badPeer(Peer::pointer ptr) void LedgerAcquire::badPeer(Peer::pointer ptr)
{ {
boost::recursive_mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
std::list<boost::weak_ptr<Peer> >::iterator it=mPeers.begin(); std::list<boost::weak_ptr<Peer> >::iterator it=mPeers.begin();
while(it!=mPeers.end()) while (it != mPeers.end())
{ {
Peer::pointer pr=it->lock(); Peer::pointer pr = it->lock();
if(!pr) // we have a dead entry, remove it if (!pr) // we have a dead entry, remove it
it=mPeers.erase(it); it = mPeers.erase(it);
else else
{ {
if(ptr->samePeer(pr)) if (ptr->samePeer(pr))
{ // We found a pointer to the bad peer { // We found a pointer to the bad peer
mPeers.erase(it); mPeers.erase(it);
return; return;
@@ -199,110 +257,164 @@ void LedgerAcquire::badPeer(Peer::pointer ptr)
} }
} }
bool LedgerAcquire::takeBase(const std::string& data) bool LedgerAcquire::takeBase(const std::string& data, Peer::pointer peer)
{ // Return value: true=normal, false=bad data { // Return value: true=normal, false=bad data
#ifdef DEBUG
std::cerr << "got base acquiring ledger " << mHash.GetHex() << std::endl;
#endif
boost::recursive_mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
if(mHaveBase) return true; if (mHaveBase) return true;
Ledger* ledger=new Ledger(data); mLedger = boost::make_shared<Ledger>(data);
if(ledger->getHash()!=mHash) if (mLedger->getHash() != mHash)
{ {
delete ledger; #ifdef DEBUG
std::cerr << "Acquire hash mismatch" << std::endl;
std::cerr << mLedger->getHash().GetHex() << "!=" << mHash.GetHex() << std::endl;
#endif
mLedger = Ledger::pointer();
return false; return false;
} }
mLedger=Ledger::pointer(ledger); mHaveBase = true;
if (!mLedger->getTransHash()) mHaveTransactions = true;
if (!mLedger->getAccountHash()) mHaveState = true;
mLedger->setAcquiring(); mLedger->setAcquiring();
mHaveBase=true; trigger(peer);
return true; return true;
} }
bool LedgerAcquire::takeTxNode(const std::list<SHAMapNode>& nodeIDs, bool LedgerAcquire::takeTxNode(const std::list<SHAMapNode>& nodeIDs,
const std::list<std::vector<unsigned char> >& data) const std::list<std::vector<unsigned char> >& data, Peer::pointer peer)
{ {
if(!mHaveBase) return false; if (!mHaveBase) return false;
std::list<SHAMapNode>::const_iterator nodeIDit=nodeIDs.begin(); std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
std::list<std::vector<unsigned char> >::const_iterator nodeDatait=data.begin(); std::list<std::vector<unsigned char> >::const_iterator nodeDatait = data.begin();
while(nodeIDit!=nodeIDs.end()) while (nodeIDit != nodeIDs.end())
{ {
if(!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait)) if (nodeIDit->isRoot())
{
if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait))
return false;
}
else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait))
return false; return false;
++nodeIDit; ++nodeIDit;
++nodeDatait; ++nodeDatait;
} }
if(!mLedger->peekTransactionMap()->isSynching()) mHaveTransactions=true; if (!mLedger->peekTransactionMap()->isSynching())
{
mHaveTransactions = true;
if (mHaveState) mComplete = true;
}
trigger(peer);
return true; return true;
} }
bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs, bool LedgerAcquire::takeAsNode(const std::list<SHAMapNode>& nodeIDs,
const std::list<std::vector<unsigned char> >& data) const std::list<std::vector<unsigned char> >& data, Peer::pointer peer)
{ {
if(!mHaveBase) return false; #ifdef DEBUG
std::list<SHAMapNode>::const_iterator nodeIDit=nodeIDs.begin(); std::cerr << "got ASdata acquiring ledger " << mHash.GetHex() << std::endl;
std::list<std::vector<unsigned char> >::const_iterator nodeDatait=data.begin(); #endif
while(nodeIDit!=nodeIDs.end()) if (!mHaveBase) return false;
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
std::list<std::vector<unsigned char> >::const_iterator nodeDatait = data.begin();
while (nodeIDit != nodeIDs.end())
{ {
if(!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait)) if (nodeIDit->isRoot())
{
if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait))
return false;
}
else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait))
return false; return false;
++nodeIDit; ++nodeIDit;
++nodeDatait; ++nodeDatait;
} }
if(!mLedger->peekAccountStateMap()->isSynching()) mHaveState=true; if (!mLedger->peekAccountStateMap()->isSynching())
{
mHaveState = true;
if (mHaveTransactions) mComplete = true;
}
trigger(peer);
return true; return true;
} }
LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash) LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
{ {
boost::mutex::scoped_lock sl(mLock); boost::mutex::scoped_lock sl(mLock);
LedgerAcquire::pointer& ptr=mLedgers[hash]; LedgerAcquire::pointer& ptr = mLedgers[hash];
if(ptr) return ptr; if (ptr) return ptr;
return boost::make_shared<LedgerAcquire>(hash); ptr = boost::make_shared<LedgerAcquire>(hash);
assert(mLedgers[hash] == ptr);
ptr->resetTimer(); // Cannot call in constructor
return ptr;
} }
LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash) LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash)
{ {
boost::mutex::scoped_lock sl(mLock); boost::mutex::scoped_lock sl(mLock);
std::map<uint256, LedgerAcquire::pointer>::iterator it=mLedgers.find(hash); std::map<uint256, LedgerAcquire::pointer>::iterator it = mLedgers.find(hash);
if(it!=mLedgers.end()) return it->second; if (it != mLedgers.end()) return it->second;
return LedgerAcquire::pointer(); return LedgerAcquire::pointer();
} }
bool LedgerAcquireMaster::hasLedger(const uint256& hash) bool LedgerAcquireMaster::hasLedger(const uint256& hash)
{ {
boost::mutex::scoped_lock sl(mLock); boost::mutex::scoped_lock sl(mLock);
return mLedgers.find(hash)!=mLedgers.end(); return mLedgers.find(hash) != mLedgers.end();
} }
bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet) bool LedgerAcquireMaster::dropLedger(const uint256& hash)
{ {
boost::mutex::scoped_lock sl(mLock);
return mLedgers.erase(hash);
}
bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::pointer peer)
{
#ifdef DEBUG
std::cerr << "got data for acquiring ledger ";
#endif
uint256 hash; uint256 hash;
if(packet.ledgerhash().size()!=32) return false; if (packet.ledgerhash().size() != 32)
memcpy(&hash, packet.ledgerhash().data(), 32);
LedgerAcquire::pointer ledger=find(hash);
if(!ledger) return false;
if(packet.type()==newcoin::liBASE)
{ {
if(packet.nodes_size()!=1) return false; #ifdef DEBUG
const newcoin::TMLedgerNode& node=packet.nodes(0); std::cerr << "error" << std::endl;
if(!node.has_nodedata()) return false; #endif
return ledger->takeBase(node.nodedata()); return false;
} }
else if( (packet.type()==newcoin::liTX_NODE) || (packet.type()==newcoin::liAS_NODE) ) memcpy(&hash, packet.ledgerhash().data(), 32);
#ifdef DEBUG
std::cerr << hash.GetHex() << std::endl;
#endif
LedgerAcquire::pointer ledger = find(hash);
if (!ledger) return false;
if (packet.type() == newcoin::liBASE)
{
if (packet.nodes_size() != 1) return false;
const newcoin::TMLedgerNode& node = packet.nodes(0);
if (!node.has_nodedata()) return false;
return ledger->takeBase(node.nodedata(), peer);
}
else if ((packet.type() == newcoin::liTX_NODE) || (packet.type() == newcoin::liAS_NODE))
{ {
std::list<SHAMapNode> nodeIDs; std::list<SHAMapNode> nodeIDs;
std::list<std::vector<unsigned char> > nodeData; std::list<std::vector<unsigned char> > nodeData;
if(packet.nodes().size()<=0) return false; if (packet.nodes().size()<=0) return false;
for(int i=0; i<packet.nodes().size(); i++) for (int i = 0; i<packet.nodes().size(); ++i)
{ {
const newcoin::TMLedgerNode& node=packet.nodes(i); const newcoin::TMLedgerNode& node=packet.nodes(i);
if(!node.has_nodeid() || !node.has_nodedata()) return false; if (!node.has_nodeid() || !node.has_nodedata()) return false;
nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size())); nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size()));
nodeData.push_back(std::vector<unsigned char>(node.nodedata().begin(), node.nodedata().end())); nodeData.push_back(std::vector<unsigned char>(node.nodedata().begin(), node.nodedata().end()));
} }
if(packet.type()==newcoin::liTX_NODE) return ledger->takeTxNode(nodeIDs, nodeData); if (packet.type() == newcoin::liTX_NODE) return ledger->takeTxNode(nodeIDs, nodeData, peer);
else return ledger->takeAsNode(nodeIDs, nodeData); else return ledger->takeAsNode(nodeIDs, nodeData, peer);
} }
else return false;
return false;
} }

View File

@@ -4,8 +4,10 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include "boost/enable_shared_from_this.hpp" #include <boost/enable_shared_from_this.hpp>
#include "boost/function.hpp" #include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/thread/mutex.hpp>
#include "Ledger.h" #include "Ledger.h"
#include "Peer.h" #include "Peer.h"
@@ -21,35 +23,41 @@ protected:
Ledger::pointer mLedger; Ledger::pointer mLedger;
uint256 mHash; uint256 mHash;
bool mComplete, mFailed, mHaveBase, mHaveState, mHaveTransactions; bool mComplete, mFailed, mHaveBase, mHaveState, mHaveTransactions;
boost::asio::deadline_timer mTimer;
std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete; std::vector< boost::function<void (LedgerAcquire::pointer)> > mOnComplete;
std::list<boost::weak_ptr<Peer> > mPeers; // peers known to have this ledger std::list<boost::weak_ptr<Peer> > mPeers; // peers known to have this ledger
void done(); void done();
void trigger(bool timer);
static void timerEntry(boost::weak_ptr<LedgerAcquire>); static void timerEntry(boost::weak_ptr<LedgerAcquire>, const boost::system::error_code&);
void sendRequest(boost::shared_ptr<newcoin::TMGetLedger> message); void sendRequest(boost::shared_ptr<newcoin::TMGetLedger> message);
void setTimer(); void sendRequest(boost::shared_ptr<newcoin::TMGetLedger> message, Peer::pointer peer);
void trigger(Peer::pointer peer);
public: public:
LedgerAcquire(const uint256& hash); LedgerAcquire(const uint256& hash);
const uint256& getHash() const { return mHash; } const uint256& getHash() const { return mHash; }
bool isComplete() const { return mComplete; } bool isComplete() const { return mComplete; }
bool isFailed() const { return mFailed; } bool isFailed() const { return mFailed; }
bool isBase() const { return mHaveBase; } bool isBase() const { return mHaveBase; }
bool isAcctStComplete() const { return mHaveState; } bool isAcctStComplete() const { return mHaveState; }
bool isTransComplete() const { return mHaveTransactions; } bool isTransComplete() const { return mHaveTransactions; }
Ledger::pointer getLedger() { return mLedger; } Ledger::pointer getLedger() { return mLedger; }
void addOnComplete(boost::function<void (LedgerAcquire::pointer)>); void addOnComplete(boost::function<void (LedgerAcquire::pointer)>);
void peerHas(Peer::pointer); void peerHas(Peer::pointer);
void badPeer(Peer::pointer); void badPeer(Peer::pointer);
bool takeBase(const std::string& data); bool takeBase(const std::string& data, Peer::pointer);
bool takeTxNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data); bool takeTxNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data,
bool takeAsNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data); Peer::pointer);
bool takeAsNode(const std::list<SHAMapNode>& IDs, const std::list<std::vector<unsigned char> >& data,
Peer::pointer);
void resetTimer();
}; };
class LedgerAcquireMaster class LedgerAcquireMaster
@@ -60,11 +68,13 @@ protected:
public: public:
LedgerAcquireMaster() { ; } LedgerAcquireMaster() { ; }
LedgerAcquire::pointer findCreate(const uint256& hash); LedgerAcquire::pointer findCreate(const uint256& hash);
LedgerAcquire::pointer find(const uint256& hash); LedgerAcquire::pointer find(const uint256& hash);
bool hasLedger(const uint256& ledgerHash); bool hasLedger(const uint256& ledgerHash);
bool gotLedgerData(newcoin::TMLedgerData& packet); bool dropLedger(const uint256& ledgerHash);
bool gotLedgerData(newcoin::TMLedgerData& packet, Peer::pointer);
}; };
#endif #endif
// vim:ts=4

View File

@@ -12,9 +12,10 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(Balance), STI_UINT64, SOE_REQUIRED, 0 }, { S_FIELD(Balance), STI_UINT64, SOE_REQUIRED, 0 },
{ S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(LastTxn), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(LastTxn), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 1 }, { S_FIELD(AuthorizedKey),STI_VL, SOE_IFFLAG, 1 },
{ S_FIELD(WalletLocator),STI_HASH256, SOE_IFFLAG, 2 }, { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 },
{ S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 4 }, { S_FIELD(WalletLocator),STI_HASH256, SOE_IFFLAG, 4 },
{ S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 8 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
}, },
@@ -33,6 +34,13 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
}, },
{ "GeneratorMap", ltGENERATOR_MAP, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(GeneratorID), STI_ACCOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Nickname", ltNICKNAME, { { "Nickname", ltNICKNAME, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Nickname), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(Nickname), STI_HASH256, SOE_REQUIRED, 0 },

View File

@@ -5,10 +5,11 @@
enum LedgerEntryType enum LedgerEntryType
{ {
ltINVALID=-1, ltINVALID =-1,
ltACCOUNT_ROOT=0, ltACCOUNT_ROOT =0,
ltRIPPLE_STATE=1, ltRIPPLE_STATE =1,
ltNICKNAME=2 ltGENERATOR_MAP =2,
ltNICKNAME =3
}; };
struct LedgerEntryFormat struct LedgerEntryFormat
@@ -21,3 +22,4 @@ struct LedgerEntryFormat
extern LedgerEntryFormat LedgerFormats[]; extern LedgerEntryFormat LedgerFormats[];
extern LedgerEntryFormat* getLgrFormat(LedgerEntryType t); extern LedgerEntryFormat* getLgrFormat(LedgerEntryType t);
#endif #endif
// vim:ts=4

View File

@@ -39,12 +39,12 @@ Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index)
{ {
boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
std::map<uint32, Ledger::pointer>::iterator it(mLedgersByIndex.find(index)); std::map<uint32, Ledger::pointer>::iterator it(mLedgersByIndex.find(index));
if(it!=mLedgersByIndex.end()) return it->second; if (it != mLedgersByIndex.end()) return it->second;
sl.unlock(); sl.unlock();
Ledger::pointer ret(Ledger::loadByIndex(index)); Ledger::pointer ret(Ledger::loadByIndex(index));
if(!ret) return ret; if (!ret) return ret;
assert(ret->getLedgerSeq()==index); assert(ret->getLedgerSeq() == index);
sl.lock(); sl.lock();
mLedgersByHash.canonicalize(ret->getHash(), ret); mLedgersByHash.canonicalize(ret->getHash(), ret);
@@ -54,16 +54,16 @@ Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index)
Ledger::pointer LedgerHistory::getLedgerByHash(const uint256& hash) Ledger::pointer LedgerHistory::getLedgerByHash(const uint256& hash)
{ {
Ledger::pointer ret=mLedgersByHash.fetch(hash); Ledger::pointer ret = mLedgersByHash.fetch(hash);
if(ret) return ret; if (ret) return ret;
ret=Ledger::loadByHash(hash); ret = Ledger::loadByHash(hash);
if(!ret) return ret; if (!ret) return ret;
assert(ret->getHash()==hash); assert(ret->getHash() == hash);
boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
mLedgersByHash.canonicalize(hash, ret); mLedgersByHash.canonicalize(hash, ret);
if(ret->isAccepted()) mLedgersByIndex[ret->getLedgerSeq()]=ret; if (ret->isAccepted()) mLedgersByIndex[ret->getLedgerSeq()] = ret;
return ret; return ret;
} }
@@ -71,16 +71,17 @@ Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool s
{ {
uint256 h(ledger->getHash()); uint256 h(ledger->getHash());
if(!save) if (!save)
{ // return input ledger if not in map, otherwise, return corresponding map ledger { // return input ledger if not in map, otherwise, return corresponding map ledger
Ledger::pointer ret=mLedgersByHash.fetch(h); Ledger::pointer ret = mLedgersByHash.fetch(h);
if(ret) return ret; if (ret) return ret;
return ledger; return ledger;
} }
// save input ledger in map if not in map, otherwise return corresponding map ledger // save input ledger in map if not in map, otherwise return corresponding map ledger
boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
mLedgersByHash.canonicalize(h, ledger); mLedgersByHash.canonicalize(h, ledger);
if(ledger->isAccepted()) mLedgersByIndex[ledger->getLedgerSeq()]=ledger; if (ledger->isAccepted()) mLedgersByIndex[ledger->getLedgerSeq()]=ledger;
return ledger; return ledger;
} }
// vim:ts=4

View File

@@ -11,7 +11,7 @@ class LedgerHistory
public: public:
LedgerHistory(); LedgerHistory();
void addLedger(Ledger::pointer ledger); void addLedger(Ledger::pointer ledger);
void addAcceptedLedger(Ledger::pointer ledger); void addAcceptedLedger(Ledger::pointer ledger);

View File

@@ -14,3 +14,4 @@ uint256 Ledger::getRippleIndex(const uint160& accountID, const uint160& extendTo
memcpy(base.begin() + (160/8), (accountID^currency).begin(), (256/8)-(160/8)); memcpy(base.begin() + (160/8), (accountID^currency).begin(), (256/8)-(160/8));
return base; return base;
} }
// vim:ts=4

View File

@@ -1,7 +1,6 @@
#include "LedgerMaster.h" #include "LedgerMaster.h"
#include "Application.h" #include "Application.h"
#include "NewcoinAddress.h" #include "NewcoinAddress.h"
#include "TimingService.h"
#include "Conversion.h" #include "Conversion.h"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@@ -36,6 +35,17 @@ void LedgerMaster::pushLedger(Ledger::pointer newLedger)
mEngine.setLedger(newLedger); mEngine.setLedger(newLedger);
} }
void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer current)
{
mFinalizedLedger = lastClosed;
mFinalizedLedger->setClosed();
mFinalizedLedger->setAccepted();
mCurrentLedger = current;
assert(!mCurrentLedger->isClosed());
mEngine.setLedger(mCurrentLedger);
}
#if 0 #if 0
void LedgerMaster::startFinalization() void LedgerMaster::startFinalization()

View File

@@ -45,6 +45,7 @@ public:
{ return mEngine.applyTransaction(txn, params); } { return mEngine.applyTransaction(txn, params); }
void pushLedger(Ledger::pointer newLedger); void pushLedger(Ledger::pointer newLedger);
void switchLedgers(Ledger::pointer lastClosed, Ledger::pointer newCurrent);
Ledger::pointer getLedgerBySeq(uint32 index) Ledger::pointer getLedgerBySeq(uint32 index)
{ {
@@ -66,3 +67,4 @@ public:
}; };
#endif #endif
// vim:ts=4

View File

@@ -109,3 +109,4 @@ SerializedLedgerEntry::pointer Ledger::getNickname(LedgerStateParms& parms, cons
return SerializedLedgerEntry::pointer(); return SerializedLedgerEntry::pointer();
} }
} }
// vim:ts=4

View File

@@ -16,7 +16,7 @@ public:
protected: protected:
// core account information // core account information
CKey::pointer mPublicKey; CKey::pointer mPublicKey;
NewcoinAddress mAcctID; NewcoinAddress mAccount;
std::string mComment; std::string mComment;
// family information // family information
@@ -32,7 +32,7 @@ public:
bool updateName(); // writes changed name/comment bool updateName(); // writes changed name/comment
bool updateBalance(); // writes changed balance/seq bool updateBalance(); // writes changed balance/seq
const NewcoinAddress& getAddress() const { return mAcctID; } const NewcoinAddress& getAddress() const { return mAccount; }
int getAcctFSeq() const { return mAccountFSeq; } int getAcctFSeq() const { return mAccountFSeq; }
std::string getFullName() const; std::string getFullName() const;

View File

@@ -1,8 +1,14 @@
#include "Application.h"
#include "NetworkOPs.h" #include "NetworkOPs.h"
#include <boost/bind.hpp>
#include <boost/unordered_map.hpp>
#include "utils.h"
#include "Application.h"
#include "Transaction.h" #include "Transaction.h"
// This is the primary interface into the "client" portion of the program. // This is the primary interface into the "client" portion of the program.
// Code that wants to do normal operations on the network such as // Code that wants to do normal operations on the network such as
// creating and monitoring accounts, creating transactions, and so on // creating and monitoring accounts, creating transactions, and so on
@@ -14,9 +20,18 @@
// code assumes this node is synched (and will continue to do so until // code assumes this node is synched (and will continue to do so until
// there's a functional network. // there's a functional network.
uint64 NetworkOPs::getNetworkTime() NetworkOPs::NetworkOPs(boost::asio::io_service& io_service) : mMode(omDISCONNECTED), mNetTimer(io_service)
{ {
return time(NULL); }
boost::posix_time::ptime NetworkOPs::getNetworkTimePT()
{
return boost::posix_time::second_clock::universal_time();
}
uint64 NetworkOPs::getNetworkTimeNC()
{
return iToSeconds(getNetworkTimePT());
} }
uint32 NetworkOPs::getCurrentLedgerID() uint32 NetworkOPs::getCurrentLedgerID()
@@ -26,10 +41,10 @@ uint32 NetworkOPs::getCurrentLedgerID()
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source) Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source)
{ {
Transaction::pointer dbtx=theApp->getMasterTransaction().fetch(trans->getID(), true); Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true);
if(dbtx) return dbtx; if (dbtx) return dbtx;
if(!trans->checkSign()) if (!trans->checkSign())
{ {
#ifdef DEBUG #ifdef DEBUG
std::cerr << "Transaction has bad signature" << std::endl; std::cerr << "Transaction has bad signature" << std::endl;
@@ -38,10 +53,10 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
return trans; return trans;
} }
TransactionEngineResult r=theApp->getMasterLedger().doTransaction(*trans->getSTransaction(), tepNONE); TransactionEngineResult r = theApp->getMasterLedger().doTransaction(*trans->getSTransaction(), tepNONE);
if(r==terFAILED) throw Fault(IO_ERROR); if (r == terFAILED) throw Fault(IO_ERROR);
if(r == terPRE_SEQ) if (r == terPRE_SEQ)
{ // transaction should be held { // transaction should be held
#ifdef DEBUG #ifdef DEBUG
std::cerr << "Transaction should be held" << std::endl; std::cerr << "Transaction should be held" << std::endl;
@@ -51,7 +66,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
theApp->getMasterLedger().addHeldTransaction(trans); theApp->getMasterLedger().addHeldTransaction(trans);
return trans; return trans;
} }
if ( (r==terPAST_SEQ || r==terPAST_LEDGER) ) if ((r == terPAST_SEQ) || (r == terPAST_LEDGER))
{ // duplicate or conflict { // duplicate or conflict
#ifdef DEBUG #ifdef DEBUG
std::cerr << "Transaction is obsolete" << std::endl; std::cerr << "Transaction is obsolete" << std::endl;
@@ -60,7 +75,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
return trans; return trans;
} }
if(r==terSUCCESS) if (r == terSUCCESS)
{ {
#ifdef DEBUG #ifdef DEBUG
std::cerr << "Transaction is now included, synching to wallet" << std::endl; std::cerr << "Transaction is now included, synching to wallet" << std::endl;
@@ -73,13 +88,13 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
// no cache the account balance information and always get it from the current ledger // no cache the account balance information and always get it from the current ledger
// theApp->getWallet().applyTransaction(trans); // theApp->getWallet().applyTransaction(trans);
newcoin::TMTransaction *tx=new newcoin::TMTransaction(); boost::shared_ptr<newcoin::TMTransaction> tx = boost::make_shared<newcoin::TMTransaction>();
Serializer::pointer s; Serializer::pointer s;
trans->getSTransaction()->getTransaction(*s, false); trans->getSTransaction()->getTransaction(*s, false);
tx->set_rawtransaction(&s->getData().front(), s->getLength()); tx->set_rawtransaction(&s->getData().front(), s->getLength());
tx->set_status(newcoin::tsCURRENT); tx->set_status(newcoin::tsCURRENT);
tx->set_receivetimestamp(getNetworkTime()); tx->set_receivetimestamp(getNetworkTimeNC());
tx->set_ledgerindexpossible(trans->getLedger()); tx->set_ledgerindexpossible(trans->getLedger());
PackedMessage::pointer packet(new PackedMessage(PackedMessage::MessagePointer(tx), newcoin::mtTRANSACTION)); PackedMessage::pointer packet(new PackedMessage(PackedMessage::MessagePointer(tx), newcoin::mtTRANSACTION));
@@ -104,20 +119,20 @@ Transaction::pointer NetworkOPs::findTransactionByID(const uint256& transactionI
int NetworkOPs::findTransactionsBySource(std::list<Transaction::pointer>& txns, int NetworkOPs::findTransactionsBySource(std::list<Transaction::pointer>& txns,
const NewcoinAddress& sourceAccount, uint32 minSeq, uint32 maxSeq) const NewcoinAddress& sourceAccount, uint32 minSeq, uint32 maxSeq)
{ {
AccountState::pointer state=getAccountState(sourceAccount); AccountState::pointer state = getAccountState(sourceAccount);
if(!state) return 0; if (!state) return 0;
if(minSeq>state->getSeq()) return 0; if (minSeq > state->getSeq()) return 0;
if(maxSeq>state->getSeq()) maxSeq=state->getSeq(); if (maxSeq > state->getSeq()) maxSeq = state->getSeq();
if(maxSeq>minSeq) return 0; if (maxSeq > minSeq) return 0;
int count=0; int count = 0;
for(int i=minSeq; i<=maxSeq; i++) for(int i = minSeq; i <= maxSeq; ++i)
{ {
Transaction::pointer txn=Transaction::findFrom(sourceAccount, i); Transaction::pointer txn = Transaction::findFrom(sourceAccount, i);
if(txn) if(txn)
{ {
txns.push_back(txn); txns.push_back(txn);
count++; ++count;
} }
} }
return count; return count;
@@ -134,3 +149,215 @@ AccountState::pointer NetworkOPs::getAccountState(const NewcoinAddress& accountI
{ {
return theApp->getMasterLedger().getCurrentLedger()->getAccountState(accountID); return theApp->getMasterLedger().getCurrentLedger()->getAccountState(accountID);
} }
void NetworkOPs::setStateTimer(int sec)
{ // set timer early if ledger is closing
uint64 closedTime = theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC();
uint64 now = getNetworkTimeNC();
if (mMode == omFULL)
{
if (now >= closedTime) sec = 0;
else if (sec > (closedTime - now)) sec = (closedTime - now);
}
mNetTimer.expires_from_now(boost::posix_time::seconds(sec));
mNetTimer.async_wait(boost::bind(&NetworkOPs::checkState, this, boost::asio::placeholders::error));
}
class ValidationCount
{
public:
int trustedValidations, untrustedValidations, nodesUsing;
NewcoinAddress highNode;
ValidationCount() : trustedValidations(0), untrustedValidations(0), nodesUsing(0) { ; }
bool operator>(const ValidationCount& v)
{
if (trustedValidations > v.trustedValidations) return true;
if (trustedValidations < v.trustedValidations) return false;
if (untrustedValidations > v.untrustedValidations) return true;
if (untrustedValidations < v.untrustedValidations) return false;
if (nodesUsing > v.nodesUsing) return true;
if (nodesUsing < v.nodesUsing) return false;
return highNode > v.highNode;
}
};
void NetworkOPs::checkState(const boost::system::error_code& result)
{ // Network state machine
if (result == boost::asio::error::operation_aborted)
return;
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
// do we have sufficient peers? If not, we are disconnected.
if (peerList.size() < theConfig.NETWORK_QUORUM)
{
if (mMode != omDISCONNECTED)
{
mMode = omDISCONNECTED;
std::cerr << "Node count (" << peerList.size() <<
") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ")." << std::endl;
}
setStateTimer(5);
return;
}
if (mMode == omDISCONNECTED)
{
mMode = omCONNECTED;
std::cerr << "Node count (" << peerList.size() << ") is sufficient." << std::endl;
}
// Do we have sufficient validations for our last closed ledger? Or do sufficient nodes
// agree? And do we have no better ledger available?
// If so, we are either tracking or full.
boost::unordered_map<uint256, ValidationCount, hash_SMN> ledgers;
for (std::vector<Peer::pointer>::iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
{
if (!*it)
{
std::cerr << "NOP::CS Dead pointer in peer list" << std::endl;
}
else
{
uint256 peerLedger = (*it)->getClosedLedgerHash();
if (!!peerLedger)
{
// FIXME: If we have this ledger, don't count it if it's too far past its close time
ValidationCount& vc = ledgers[peerLedger];
if ((vc.nodesUsing == 0) || ((*it)->getNodePublic() > vc.highNode))
vc.highNode = (*it)->getNodePublic();
++vc.nodesUsing;
// WRITEME: Validations, trusted peers
}
}
}
Ledger::pointer currentClosed = theApp->getMasterLedger().getClosedLedger();
uint256 closedLedger = currentClosed->getHash();
ValidationCount& vc = ledgers[closedLedger];
if ((vc.nodesUsing == 0) || (theApp->getWallet().getNodePublic() > vc.highNode))
vc.highNode = theApp->getWallet().getNodePublic();
++ledgers[closedLedger].nodesUsing;
// 3) Is there a network ledger we'd like to switch to? If so, do we have it?
bool switchLedgers = false;
for(boost::unordered_map<uint256, ValidationCount>::iterator it = ledgers.begin(), end = ledgers.end();
it != end; ++it)
{
if (it->second > vc)
{
vc = it->second;
closedLedger = it->first;
switchLedgers = true;
}
}
if (switchLedgers)
{
std::cerr << "We are not running on the consensus ledger" << std::endl;
#ifdef DEBUG
std::cerr << "Our LCL " << currentClosed->getHash().GetHex() << std::endl;
std::cerr << "Net LCL " << closedLedger.GetHex() << std::endl;
#endif
if ((mMode == omTRACKING) || (mMode == omFULL)) mMode = omTRACKING;
Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(closedLedger);
if (!consensus)
{
#ifdef DEBUG
std::cerr << "Acquiring consensus ledger" << std::endl;
#endif
LedgerAcquire::pointer acq = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
if (!acq || acq->isFailed())
{
theApp->getMasterLedgerAcquire().dropLedger(closedLedger);
std::cerr << "Network ledger cannot be acquired" << std::endl;
setStateTimer(10);
return;
}
if (!acq->isComplete())
{ // add more peers
// FIXME: A peer may not have a ledger just because it accepts it as the network's consensus
for (std::vector<Peer::pointer>::iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
if ((*it)->getClosedLedgerHash() == closedLedger)
acq->peerHas(*it);
setStateTimer(5);
return;
}
consensus = acq->getLedger();
}
switchLastClosedLedger(consensus, false);
}
if (mMode == omCONNECTED)
{
// check if the ledger is good enough to go to omTRACKING
}
if (mMode == omTRACKING)
{
// check if the ledger is good enough to go to omFULL
// check if the ledger is bad enough to go to omCONNECTED
}
if (mMode == omFULL)
{
// check if the ledger is bad enough to go to omTRACKING
}
Ledger::pointer currentLedger = theApp->getMasterLedger().getCurrentLedger();
if (getNetworkTimeNC() >= currentLedger->getCloseTimeNC())
{
currentLedger->setClosed();
switchLastClosedLedger(currentLedger, true);
}
setStateTimer(10);
}
void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool normal)
{ // set the newledger as our last closed ledger
// FIXME: Correct logic is:
// 1) Mark this ledger closed, schedule it to be saved
// 2) If normal, reprocess transactions
// 3) Open a new subsequent ledger
// 4) Walk back the previous ledger chain from our current ledger and the new last closed ledger
// find a common previous ledger, if possible. Try to insert any transactions in our ledger
// chain into the new open ledger. Broadcast any that make it in.
#ifdef DEBUG
std::cerr << "Switching last closed ledger to " << newLedger->getHash().GetHex() << std::endl;
#endif
newLedger->setClosed();
Ledger::pointer openLedger = boost::make_shared<Ledger>(newLedger);
theApp->getMasterLedger().switchLedgers(newLedger, openLedger);
if (getNetworkTimeNC() > openLedger->getCloseTimeNC())
{ // this ledger has already closed
}
boost::shared_ptr<newcoin::TMStatusChange> s = boost::make_shared<newcoin::TMStatusChange>();
s->set_newevent(normal ? newcoin::neACCEPTED_LEDGER : newcoin::neSWITCHED_LEDGER);
s->set_ledgerseq(newLedger->getLedgerSeq());
s->set_networktime(getNetworkTimeNC());
uint256 lhash = newLedger->getHash();
s->set_ledgerhash(lhash.begin(), lhash.size());
lhash = newLedger->getParentHash();
s->set_previousledgerhash(lhash.begin(), lhash.size());
#ifdef DEBUG
std::cerr << "Broadcasting ledger change" << std::endl;
#endif
PackedMessage::pointer packet =
boost::make_shared<PackedMessage>(PackedMessage::MessagePointer(s), newcoin::mtSTATUS_CHANGE);
theApp->getConnectionPool().relayMessage(NULL, packet);
}
// vim:ts=4

View File

@@ -1,40 +1,49 @@
#ifndef __NETWORK_OPS__ #ifndef __NETWORK_OPS__
#define __NETWORK_OPS__ #define __NETWORK_OPS__
#include <boost/asio.hpp>
#include "Transaction.h" #include "Transaction.h"
#include "AccountState.h" #include "AccountState.h"
#include "Ledger.h"
// Operations that clients may wish to perform against the network // Operations that clients may wish to perform against the network
// Master operational handler, server sequencer, network tracker
class Peer; class Peer;
class NetworkOPs class NetworkOPs
{ {
public:
enum Fault enum Fault
{ // exceptions these functions can throw { // exceptions these functions can throw
IO_ERROR=1, IO_ERROR = 1,
NO_NETWORK=2, NO_NETWORK = 2,
}; };
enum OperatingMode enum OperatingMode
{ // how we process transactions or account balance requests { // how we process transactions or account balance requests
FAULTED=0, // we are unable to process requests (not ready or no network) omDISCONNECTED = 0, // not ready to process requests
FULL_LOCAL=1, // we are in full local sync omCONNECTED = 1, // convinced we are talking to the network
PART_LOCAL=2, // we can validate remote data but have to request it omTRACKING = 2, // convinced we agree with the network
REMOTE=3 // we have to trust remote nodes omFULL = 3 // we have the ledger and can even validate
}; };
public: protected:
OperatingMode mMode;
boost::asio::deadline_timer mNetTimer;
// context information public:
OperatingMode getOperatingMode(); NetworkOPs(boost::asio::io_service& io_service);
// network information // network information
uint64 getNetworkTime(); uint64 getNetworkTimeNC();
boost::posix_time::ptime getNetworkTimePT();
uint32 getCurrentLedgerID(); uint32 getCurrentLedgerID();
OperatingMode getOperatingMode() { return mMode; }
// transaction operations // transaction operations
Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source=NULL); Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source = NULL);
Transaction::pointer findTransactionByID(const uint256& transactionID); Transaction::pointer findTransactionByID(const uint256& transactionID);
int findTransactionsBySource(std::list<Transaction::pointer>&, const NewcoinAddress& sourceAccount, int findTransactionsBySource(std::list<Transaction::pointer>&, const NewcoinAddress& sourceAccount,
uint32 minSeq, uint32 maxSeq); uint32 minSeq, uint32 maxSeq);
@@ -44,19 +53,24 @@ public:
// account operations // account operations
AccountState::pointer getAccountState(const NewcoinAddress& accountID); AccountState::pointer getAccountState(const NewcoinAddress& accountID);
// contact block operations
// raw object operations // raw object operations
bool findRawLedger(const uint256& ledgerHash, std::vector<unsigned char>& rawLedger); bool findRawLedger(const uint256& ledgerHash, std::vector<unsigned char>& rawLedger);
bool findRawTransaction(const uint256& transactionHash, std::vector<unsigned char>& rawTransaction); bool findRawTransaction(const uint256& transactionHash, std::vector<unsigned char>& rawTransaction);
bool findAccountNode(const uint256& nodeHash, std::vector<unsigned char>& rawAccountNode); bool findAccountNode(const uint256& nodeHash, std::vector<unsigned char>& rawAccountNode);
bool findTransactionNode(const uint256& nodeHash, std::vector<unsigned char>& rawTransactionNode); bool findTransactionNode(const uint256& nodeHash, std::vector<unsigned char>& rawTransactionNode);
// tree synchronzation operations // tree synchronization operations
bool getTransactionTreeNodes(uint32 ledgerSeq, const uint256& myNodeID, bool getTransactionTreeNodes(uint32 ledgerSeq, const uint256& myNodeID,
const std::vector<unsigned char>& myNode, std::list<std::vector<unsigned char> >& newNodes); const std::vector<unsigned char>& myNode, std::list<std::vector<unsigned char> >& newNodes);
bool getAccountStateNodes(uint32 ledgerSeq, const uint256& myNodeId, bool getAccountStateNodes(uint32 ledgerSeq, const uint256& myNodeId,
const std::vector<unsigned char>& myNode, std::list<std::vector<unsigned char> >& newNodes); const std::vector<unsigned char>& myNode, std::list<std::vector<unsigned char> >& newNodes);
// network state machine
void checkState(const boost::system::error_code& result);
void switchLastClosedLedger(Ledger::pointer newLedger, bool normal);
void setStateTimer(int seconds);
}; };
#endif #endif
// vim:ts=4

View File

@@ -3,15 +3,15 @@
#include "Config.h" #include "Config.h"
#include "BitcoinUtil.h" #include "BitcoinUtil.h"
#include "rfc1751.h" #include "rfc1751.h"
#include "utils.h"
#include "openssl/rand.h"
#include <cassert>
#include <algorithm> #include <algorithm>
#include <iostream>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <cassert>
#include <iostream>
#include <openssl/rand.h>
NewcoinAddress::NewcoinAddress() NewcoinAddress::NewcoinAddress()
{ {
@@ -273,7 +273,7 @@ void NewcoinAddress::setAccountPublic(const std::vector<unsigned char>& vPublic)
void NewcoinAddress::setAccountPublic(const NewcoinAddress& generator, int seq) void NewcoinAddress::setAccountPublic(const NewcoinAddress& generator, int seq)
{ {
CKey pubkey = CKey(generator, seq); CKey pubkey = CKey(generator, seq+1);
setAccountPublic(pubkey.GetPubKey()); setAccountPublic(pubkey.GetPubKey());
} }
@@ -282,14 +282,14 @@ void NewcoinAddress::setAccountPublic(const NewcoinAddress& generator, int seq)
// AccountPrivate // AccountPrivate
// //
uint256 NewcoinAddress::getAccountPrivate() const const std::vector<unsigned char>& NewcoinAddress::getAccountPrivate() const
{ {
switch (nVersion) { switch (nVersion) {
case VER_NONE: case VER_NONE:
throw std::runtime_error("unset source"); throw std::runtime_error("unset source");
case VER_ACCOUNT_PRIVATE: case VER_ACCOUNT_PRIVATE:
return uint256(vchData); return vchData;
default: default:
throw std::runtime_error(str(boost::format("bad source: %d") % int(nVersion))); throw std::runtime_error(str(boost::format("bad source: %d") % int(nVersion)));
@@ -325,6 +325,73 @@ void NewcoinAddress::setAccountPrivate(uint256 hash256)
SetData(VER_ACCOUNT_PRIVATE, hash256.begin(), 32); SetData(VER_ACCOUNT_PRIVATE, hash256.begin(), 32);
} }
void NewcoinAddress::setAccountPrivate(const NewcoinAddress& generator, const NewcoinAddress& seed, int seq)
{
CKey privkey = CKey(generator, seed.getFamilyPrivateKey(), seq+1);
setAccountPrivate(privkey.GetPrivKey());
}
std::vector<unsigned char> NewcoinAddress::accountPrivateEncrypt(const NewcoinAddress& naPublicTo, const std::vector<unsigned char>& vucPlainText)
{
CKey ckPrivate;
CKey ckPublic;
std::vector<unsigned char> vucCipherText;
if (!ckPublic.SetPubKey(naPublicTo.getAccountPublic()))
{
// Bad public key.
std::cerr << "accountPrivateEncrypt: Bad public key." << std::endl;
}
else if (!ckPrivate.SetPrivKey(getAccountPrivate()))
{
// Bad private key.
std::cerr << "accountPrivateEncrypt: Bad private key." << std::endl;
}
else
{
try {
vucCipherText = ckPrivate.encryptECIES(ckPublic, vucPlainText);
}
catch (...)
{
nothing();
}
}
return vucCipherText;
}
std::vector<unsigned char> NewcoinAddress::accountPrivateDecrypt(const NewcoinAddress& naPublicFrom, const std::vector<unsigned char>& vucCipherText)
{
CKey ckPrivate;
CKey ckPublic;
std::vector<unsigned char> vucPlainText;
if (!ckPublic.SetPubKey(naPublicFrom.getAccountPublic()))
{
// Bad public key.
std::cerr << "accountPrivateDecrypt: Bad public key." << std::endl;
}
else if (!ckPrivate.SetPrivKey(getAccountPrivate()))
{
// Bad private key.
std::cerr << "accountPrivateDecrypt: Bad private key." << std::endl;
}
else
{
try {
vucPlainText = ckPrivate.decryptECIES(ckPublic, vucCipherText);
}
catch (...)
{
nothing();
}
}
return vucPlainText;
}
// //
// Family Generators // Family Generators
// //

View File

@@ -78,13 +78,20 @@ public:
// //
// Accounts Private // Accounts Private
// //
uint256 getAccountPrivate() const; const std::vector<unsigned char>& getAccountPrivate() const;
std::string humanAccountPrivate() const; std::string humanAccountPrivate() const;
bool setAccountPrivate(const std::string& strPrivate); bool setAccountPrivate(const std::string& strPrivate);
void setAccountPrivate(const std::vector<unsigned char>& vPrivate); void setAccountPrivate(const std::vector<unsigned char>& vPrivate);
void setAccountPrivate(uint256 hash256); void setAccountPrivate(uint256 hash256);
void setAccountPrivate(const NewcoinAddress& generator, const NewcoinAddress& seed, int seq);
// Encrypt a message.
std::vector<unsigned char> accountPrivateEncrypt(const NewcoinAddress& naPublicTo, const std::vector<unsigned char>& vucPlainText);
// Decrypt a message.
std::vector<unsigned char> accountPrivateDecrypt(const NewcoinAddress& naPublicFrom, const std::vector<unsigned char>& vucCipherText);
// //
// Family Generators // Family Generators

View File

@@ -13,14 +13,13 @@ void PackedMessage::encodeHeader(unsigned size, int type)
} }
PackedMessage::PackedMessage(MessagePointer msg, int type) PackedMessage::PackedMessage(MessagePointer msg, int type) : mMsg(msg)
: mMsg(msg)
{ {
unsigned msg_size = mMsg->ByteSize(); unsigned msg_size = mMsg->ByteSize();
assert(msg_size); assert(msg_size);
mBuffer.resize(HEADER_SIZE + msg_size); mBuffer.resize(HEADER_SIZE + msg_size);
encodeHeader(msg_size,type); encodeHeader(msg_size, type);
if(msg_size) if (msg_size)
{ {
mMsg->SerializeToArray(&mBuffer[HEADER_SIZE], msg_size); mMsg->SerializeToArray(&mBuffer[HEADER_SIZE], msg_size);
#ifdef DEBUG #ifdef DEBUG
@@ -31,30 +30,25 @@ PackedMessage::PackedMessage(MessagePointer msg, int type)
bool PackedMessage::operator == (const PackedMessage& other) bool PackedMessage::operator == (const PackedMessage& other)
{ {
return(mBuffer==other.mBuffer); return (mBuffer == other.mBuffer);
} }
unsigned PackedMessage::getLength(std::vector<uint8_t>& buf) unsigned PackedMessage::getLength(std::vector<uint8_t>& buf)
{ {
if(buf.size() < HEADER_SIZE) return 0; if(buf.size() < HEADER_SIZE)
return 0;
int ret=buf[0]; int ret = buf[0];
ret<<=8; ret <<= 8; ret |= buf[1]; ret <<= 8; ret |= buf[2]; ret <<= 8; ret |= buf[3];
ret|=buf[1]; return ret;
ret<<=8;
ret|=buf[2];
ret<<=8;
ret|=buf[3];
return(ret);
} }
int PackedMessage::getType(std::vector<uint8_t>& buf) int PackedMessage::getType(std::vector<uint8_t>& buf)
{ {
if(buf.size() < HEADER_SIZE) return 0; if(buf.size() < HEADER_SIZE)
return 0;
int ret=buf[4]; int ret = buf[4];
ret<<=8; ret <<= 8; ret |= buf[5];
ret|=buf[5]; return ret;
return(ret);
} }

View File

@@ -19,9 +19,10 @@
// Node has this long to verify its identity from connection accepted or connection attempt. // Node has this long to verify its identity from connection accepted or connection attempt.
#define NODE_VERIFY_SECONDS 15 #define NODE_VERIFY_SECONDS 15
Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx) Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx) :
: mSocketSsl(io_service, ctx), mConnected(false),
mVerifyTimer(io_service) mSocketSsl(io_service, ctx),
mVerifyTimer(io_service)
{ {
} }
@@ -29,20 +30,20 @@ void Peer::handle_write(const boost::system::error_code& error, size_t bytes_tra
{ {
#ifdef DEBUG #ifdef DEBUG
if(error) if(error)
std::cerr << "Peer::handle_write Error: " << error << " bytes: " << bytes_transferred << std::endl; std::cerr << "Peer::handle_write Error: " << error << " bytes: " << bytes_transferred << std::endl;
else else
std::cerr << "Peer::handle_write bytes: "<< bytes_transferred << std::endl; std::cerr << "Peer::handle_write bytes: "<< bytes_transferred << std::endl;
#endif #endif
mSendingPacket=PackedMessage::pointer(); mSendingPacket = PackedMessage::pointer();
if(error) if (error)
{ {
detach(); detach("hw");
return; return;
} }
if(!mSendQ.empty()) if (!mSendQ.empty())
{ {
PackedMessage::pointer packet=mSendQ.front(); PackedMessage::pointer packet=mSendQ.front();
if(packet) if(packet)
@@ -53,17 +54,21 @@ void Peer::handle_write(const boost::system::error_code& error, size_t bytes_tra
} }
} }
void Peer::detach() void Peer::detach(const char *rsn)
{ {
#ifdef DEBUG
std::cerr << "DETACHING PEER: " << rsn << std::endl;
#endif
boost::system::error_code ecCancel; boost::system::error_code ecCancel;
(void) mVerifyTimer.cancel(); (void) mVerifyTimer.cancel();
mSendQ.clear(); mSendQ.clear();
// mSocketSsl.close();
if (!mIpPort.first.empty()) { if (!mIpPort.first.empty())
{
if (mClientConnect) if (mClientConnect)
// Connection might be part of scanning. Inform connect failed.
theApp->getConnectionPool().peerFailed(mIpPort.first, mIpPort.second); theApp->getConnectionPool().peerFailed(mIpPort.first, mIpPort.second);
theApp->getConnectionPool().peerDisconnected(shared_from_this(), mIpPort, mNodePublic); theApp->getConnectionPool().peerDisconnected(shared_from_this(), mIpPort, mNodePublic);
@@ -78,34 +83,35 @@ void Peer::handleVerifyTimer(const boost::system::error_code& ecResult)
// Timer canceled because deadline no longer needed. // Timer canceled because deadline no longer needed.
// std::cerr << "Deadline cancelled." << std::endl; // std::cerr << "Deadline cancelled." << std::endl;
nothing(); // Aborter is done. nothing(); // Aborter is done.
} }
else if (ecResult) else if (ecResult)
{ {
std::cerr << "Peer verify timer error: " << std::endl; std::cerr << "Peer verify timer error: " << std::endl;
// Can't do anything sound. // Can't do anything sound.
abort(); abort();
} }
else else
{ {
std::cerr << "Peer failed to verify in time." << std::endl; std::cerr << "Peer failed to verify in time." << std::endl;
detach(); detach("hvt");
} }
} }
// Begin trying to connect. We are not connected till we know and accept peer's public key. // Begin trying to connect. We are not connected till we know and accept peer's public key.
// Only takes IP addresses (not domains). // Only takes IP addresses (not domains).
void Peer::connect(const std::string strIp, int iPort) void Peer::connect(const std::string strIp, int iPort)
{ {
int iPortAct = iPort < 0 ? SYSTEM_PEER_PORT : iPort; int iPortAct = (iPort <= 0) ? SYSTEM_PEER_PORT : iPort;
mClientConnect = true; mClientConnect = true;
std::cerr << "Peer::connect: " << strIp << " " << iPort << std::endl; std::cerr << "Peer::connect: " << strIp << " " << iPort << std::endl;
mIpPort = make_pair(strIp, iPort); mIpPort = make_pair(strIp, iPort);
assert(!mIpPort.first.empty());
boost::asio::ip::tcp::resolver::query query(strIp, boost::lexical_cast<std::string>(iPortAct), boost::asio::ip::tcp::resolver::query query(strIp, boost::lexical_cast<std::string>(iPortAct),
boost::asio::ip::resolver_query_base::numeric_host|boost::asio::ip::resolver_query_base::numeric_service); boost::asio::ip::resolver_query_base::numeric_host|boost::asio::ip::resolver_query_base::numeric_service);
boost::asio::ip::tcp::resolver resolver(theApp->getIOService()); boost::asio::ip::tcp::resolver resolver(theApp->getIOService());
boost::system::error_code err; boost::system::error_code err;
@@ -114,7 +120,8 @@ void Peer::connect(const std::string strIp, int iPort)
if (err || itrEndpoint == boost::asio::ip::tcp::resolver::iterator()) if (err || itrEndpoint == boost::asio::ip::tcp::resolver::iterator())
{ {
std::cerr << "Peer::connect: Bad IP" << std::endl; std::cerr << "Peer::connect: Bad IP" << std::endl;
detach(); detach("c");
return;
} }
else else
{ {
@@ -124,13 +131,14 @@ void Peer::connect(const std::string strIp, int iPort)
if (err) if (err)
{ {
std::cerr << "Peer::connect: Failed to set timer." << std::endl; std::cerr << "Peer::connect: Failed to set timer." << std::endl;
detach(); detach("c2");
return;
} }
} }
if (!err) if (!err)
{ {
std::cerr << "Peer::connect: Connectting: " << mIpPort.first << " " << mIpPort.second << std::endl; std::cerr << "Peer::connect: Connecting: " << mIpPort.first << " " << mIpPort.second << std::endl;
boost::asio::async_connect( boost::asio::async_connect(
mSocketSsl.lowest_layer(), mSocketSsl.lowest_layer(),
@@ -152,7 +160,7 @@ void Peer::handleStart(const boost::system::error_code& error)
if (error) if (error)
{ {
std::cerr << "Peer::handleStart: failed:" << error << std::endl; std::cerr << "Peer::handleStart: failed:" << error << std::endl;
detach(); detach("hs");
} }
else else
{ {
@@ -167,16 +175,16 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip
if (error) if (error)
{ {
std::cerr << "Connect peer: failed:" << error << std::endl; std::cerr << "Connect peer: failed:" << error << std::endl;
detach(); detach("hc");
} }
else else
{ {
std::cerr << "Connect peer: success." << std::endl; std::cerr << "Connect peer: success." << std::endl;
mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true)); mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true));
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none); mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::client, mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::client,
boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error)); boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error));
} }
} }
@@ -196,13 +204,13 @@ void Peer::connected(const boost::system::error_code& error)
if (error) if (error)
{ {
std::cerr << "Remote peer: accept error: " << strIp << " " << iPort << " : " << error << std::endl; std::cerr << "Remote peer: accept error: " << strIp << " " << iPort << " : " << error << std::endl;
detach(); detach("ctd");
} }
else if (!theApp->getConnectionPool().peerRegister(shared_from_this(), strIp, iPort)) else if (!theApp->getConnectionPool().peerRegister(shared_from_this(), strIp, iPort))
{ {
std::cerr << "Remote peer: rejecting: " << strIp << " " << iPort << std::endl; std::cerr << "Remote peer: rejecting: " << strIp << " " << iPort << std::endl;
// XXX Reject with a rejection message: already connected // XXX Reject with a rejection message: already connected
detach(); detach("ctd2");
} }
else else
{ {
@@ -212,11 +220,12 @@ void Peer::connected(const boost::system::error_code& error)
//BOOST_LOG_TRIVIAL(info) << "Connected to Peer."; //BOOST_LOG_TRIVIAL(info) << "Connected to Peer.";
mIpPort = make_pair(strIp, iPort); mIpPort = make_pair(strIp, iPort);
assert(!mIpPort.first.empty());
mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true)); mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true));
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none); mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::server, mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::server,
boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error)); boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error));
} }
} }
@@ -247,9 +256,6 @@ void Peer::sendPacket(PackedMessage::pointer packet)
void Peer::start_read_header() void Peer::start_read_header()
{ {
#ifdef DEBUG
std::cerr << "SRH" << std::endl;
#endif
mReadbuf.clear(); mReadbuf.clear();
mReadbuf.resize(HEADER_SIZE); mReadbuf.resize(HEADER_SIZE);
boost::asio::async_read(mSocketSsl, boost::asio::buffer(mReadbuf), boost::asio::async_read(mSocketSsl, boost::asio::buffer(mReadbuf),
@@ -275,15 +281,15 @@ void Peer::handle_read_header(const boost::system::error_code& error)
// WRITEME: Compare to maximum message length, abort if too large // WRITEME: Compare to maximum message length, abort if too large
if(msg_len>(32*1024*1024)) if(msg_len>(32*1024*1024))
{ {
detach(); detach("hrh");
return; return;
} }
start_read_body(msg_len); start_read_body(msg_len);
} }
else else
{ {
detach(); detach("hrh2");
std::cerr << "Peer::handle_read_header: Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error; std::cerr << "Peer::handle_read_header: Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error;
} }
} }
@@ -296,8 +302,8 @@ void Peer::handle_read_body(const boost::system::error_code& error)
} }
else else
{ {
detach(); detach("hrb");
std::cerr << "Peer::handle_read_body: Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error; std::cerr << "Peer::handle_read_body: Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error;
} }
} }
@@ -309,11 +315,13 @@ void Peer::processReadBuffer()
std::cerr << "PRB(" << type << "), len=" << (mReadbuf.size()-HEADER_SIZE) << std::endl; std::cerr << "PRB(" << type << "), len=" << (mReadbuf.size()-HEADER_SIZE) << std::endl;
#endif #endif
// If not connected, only accept mtHELLO. Otherwise, don't accept mtHELLO. std::cerr << "Peer::processReadBuffer: " << mIpPort.first << " " << mIpPort.second << std::endl;
if (mIpPort.first.empty() == (type == newcoin::mtHELLO))
// If connected and get a mtHELLO or if not connected and get a non-mtHELLO, wrong message was sent.
if (mConnected == (type == newcoin::mtHELLO))
{ {
std::cerr << "Wrong message type: " << type << std::endl; std::cerr << "Wrong message type: " << type << std::endl;
detach(); detach("prb1");
} }
else else
{ {
@@ -324,7 +332,7 @@ void Peer::processReadBuffer()
newcoin::TMHello msg; newcoin::TMHello msg;
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE)) if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
recvHello(msg); recvHello(msg);
else std::cerr << "parse error: " << type << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error; else std::cerr << "parse error: " << type << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error;
} }
break; break;
@@ -400,6 +408,17 @@ void Peer::processReadBuffer()
} }
break; break;
case newcoin::mtSTATUS_CHANGE:
{
newcoin::TMStatusChange msg;
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
recvStatus(msg);
else std::cerr << "parse error: " << type << std::endl;
}
break;
case newcoin::mtGET_LEDGER: case newcoin::mtGET_LEDGER:
{ {
newcoin::TMGetLedger msg; newcoin::TMGetLedger msg;
@@ -474,7 +493,7 @@ void Peer::processReadBuffer()
break; break;
default: default:
std::cerr << "Unknown Msg: " << type << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error; std::cerr << "Unknown Msg: " << type << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error;
} }
} }
} }
@@ -515,21 +534,33 @@ void Peer::recvHello(newcoin::TMHello& packet)
} }
else else
{ {
// XXX At this point we could add the inbound connection to our IP list. However, the inbound IP address might be that of // At this point we could add the inbound connection to our IP list. However, the inbound IP address might be that of
// a NAT. It would be best to only add it if and only if we can immediatly verify it. // a NAT. It would be best to only add it if and only if we can immediatly verify it.
nothing(); nothing();
} }
// Consider us connected. No longer accepting mtHELLO.
mConnected = true;
// XXX Set timer: connection is in grace period to be useful. // XXX Set timer: connection is in grace period to be useful.
// XXX Set timer: connection idle (idle may vary depending on connection type.) // XXX Set timer: connection idle (idle may vary depending on connection type.)
if ((packet.has_closedledger()) && (packet.closedledger().size() == (256 / 8)))
{
memcpy(mClosedLedgerHash.begin(), packet.closedledger().data(), 256 / 8);
if ((packet.has_previousledger()) && (packet.previousledger().size() == (256 / 8)))
memcpy(mPreviousLedgerHash.begin(), packet.previousledger().data(), 256 / 8);
else mPreviousLedgerHash.zero();
mClosedLedgerTime = boost::posix_time::second_clock::universal_time();
}
bDetach = false; bDetach = false;
} }
if (bDetach) if (bDetach)
{ {
mNodePublic.clear(); mNodePublic.clear();
detach(); detach("recvh");
} }
} }
@@ -618,33 +649,55 @@ void Peer::recvAccount(newcoin::TMAccount& packet)
{ {
} }
void Peer::recvStatus(newcoin::TMStatusChange& packet)
{
#ifdef DEBUG
std::cerr << "Received status change from peer" << std::endl;
#endif
if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8)))
{ // a peer has changed ledgers
if (packet.has_previousledgerhash() && (packet.previousledgerhash().size() == (256 / 8)))
memcpy(mPreviousLedgerHash.begin(), packet.previousledgerhash().data(), 256 / 8);
else
mPreviousLedgerHash = mClosedLedgerHash;
memcpy(mClosedLedgerHash.begin(), packet.ledgerhash().data(), 256 / 8);
if (packet.has_networktime())
mClosedLedgerTime = ptFromSeconds(packet.networktime());
else
mClosedLedgerTime = theApp->getOPs().getNetworkTimePT();
#ifdef DEBUG
std::cerr << "peer LCL is " << mClosedLedgerHash.GetHex() << std::endl;
#endif
}
}
void Peer::recvGetLedger(newcoin::TMGetLedger& packet) void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
{ {
// Figure out what ledger they want // Figure out what ledger they want
Ledger::pointer ledger; Ledger::pointer ledger;
if(packet.has_ledgerhash()) if (packet.has_ledgerhash())
{ {
uint256 ledgerhash; uint256 ledgerhash;
if(packet.ledgerhash().size()!=32) if (packet.ledgerhash().size() != 32)
{ {
punishPeer(PP_INVALID_REQUEST); punishPeer(PP_INVALID_REQUEST);
return; return;
} }
memcpy(&ledgerhash, packet.ledgerhash().data(), 32); memcpy(&ledgerhash, packet.ledgerhash().data(), 32);
ledger=theApp->getMasterLedger().getLedgerByHash(ledgerhash); ledger = theApp->getMasterLedger().getLedgerByHash(ledgerhash);
} }
else if(packet.has_ledgerseq()) else if (packet.has_ledgerseq())
ledger=theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq()); ledger = theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq());
else if(packet.has_ltype() && (packet.ltype() == newcoin::ltCURRENT) ) else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCURRENT))
ledger=theApp->getMasterLedger().getCurrentLedger(); ledger = theApp->getMasterLedger().getCurrentLedger();
else if(packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSING) ) else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSING))
{ {
ledger = theApp->getMasterLedger().getClosedLedger(); ledger = theApp->getMasterLedger().getClosedLedger();
} }
else if(packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSED) ) else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSED) )
{ {
ledger = theApp->getMasterLedger().getClosedLedger(); ledger = theApp->getMasterLedger().getClosedLedger();
if(ledger && !ledger->isClosed()) if (ledger && !ledger->isClosed())
ledger = theApp->getMasterLedger().getLedgerBySeq(ledger->getLedgerSeq() - 1); ledger = theApp->getMasterLedger().getLedgerBySeq(ledger->getLedgerSeq() - 1);
} }
else else
@@ -660,18 +713,17 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
} }
// Figure out what information they want // Figure out what information they want
newcoin::TMLedgerData* data=new newcoin::TMLedgerData; boost::shared_ptr<newcoin::TMLedgerData> data = boost::make_shared<newcoin::TMLedgerData>();
uint256 lHash=ledger->getHash(); uint256 lHash = ledger->getHash();
data->set_ledgerhash(lHash.begin(), lHash.size()); data->set_ledgerhash(lHash.begin(), lHash.size());
data->set_ledgerseq(ledger->getLedgerSeq()); data->set_ledgerseq(ledger->getLedgerSeq());
data->set_type(packet.itype()); data->set_type(packet.itype());
if(packet.itype()==newcoin::liBASE) if(packet.itype() == newcoin::liBASE)
{ {
Serializer nData(116); Serializer nData(116);
ledger->addRaw(nData); ledger->addRaw(nData);
newcoin::TMLedgerNode* node=data->add_nodes(); data->add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength());
node->set_nodedata(nData.getDataPtr(), nData.getLength());
} }
else if ( (packet.itype()==newcoin::liTX_NODE) || (packet.itype()==newcoin::liAS_NODE) ) else if ( (packet.itype()==newcoin::liTX_NODE) || (packet.itype()==newcoin::liAS_NODE) )
{ {
@@ -696,13 +748,13 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
if(map->getNodeFat(mn, nodeIDs, rawNodes)) if(map->getNodeFat(mn, nodeIDs, rawNodes))
{ {
std::vector<SHAMapNode>::iterator nodeIDIterator; std::vector<SHAMapNode>::iterator nodeIDIterator;
std::list<std::vector<unsigned char> >::iterator rawNodeIterator; std::list<std::vector<unsigned char> >::iterator rawNodeIterator;
for(nodeIDIterator=nodeIDs.begin(), rawNodeIterator=rawNodes.begin(); for(nodeIDIterator=nodeIDs.begin(), rawNodeIterator=rawNodes.begin();
nodeIDIterator!=nodeIDs.end(); ++nodeIDIterator, ++rawNodeIterator) nodeIDIterator!=nodeIDs.end(); ++nodeIDIterator, ++rawNodeIterator)
{ {
newcoin::TMLedgerNode* node=data->add_nodes();
Serializer nID(33); Serializer nID(33);
nodeIDIterator->addIDRaw(nID); nodeIDIterator->addIDRaw(nID);
newcoin::TMLedgerNode* node=data->add_nodes();
node->set_nodeid(nID.getDataPtr(), nID.getLength()); node->set_nodeid(nID.getDataPtr(), nID.getLength());
node->set_nodedata(&rawNodeIterator->front(), rawNodeIterator->size()); node->set_nodedata(&rawNodeIterator->front(), rawNodeIterator->size());
} }
@@ -721,7 +773,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
void Peer::recvLedger(newcoin::TMLedgerData& packet) void Peer::recvLedger(newcoin::TMLedgerData& packet)
{ {
if(!theApp->getMasterLedgerAcquire().gotLedgerData(packet)) if(!theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this()))
punishPeer(PP_UNWANTED_DATA); punishPeer(PP_UNWANTED_DATA);
} }
@@ -764,22 +816,23 @@ void Peer::sendHello()
theApp->getWallet().getNodePrivate().signNodePrivate(mCookieHash, vchSig); theApp->getWallet().getNodePrivate().signNodePrivate(mCookieHash, vchSig);
newcoin::TMHello* h = new newcoin::TMHello(); boost::shared_ptr<newcoin::TMHello> h = boost::make_shared<newcoin::TMHello>();
h->set_version(theConfig.VERSION); h->set_version(theConfig.VERSION);
h->set_ledgerindex(theApp->getOPs().getCurrentLedgerID()); h->set_ledgerindex(theApp->getOPs().getCurrentLedgerID());
h->set_nettime(theApp->getOPs().getNetworkTime()); h->set_nettime(theApp->getOPs().getNetworkTimeNC());
h->set_nodepublic(theApp->getWallet().getNodePublic().humanNodePublic()); h->set_nodepublic(theApp->getWallet().getNodePublic().humanNodePublic());
h->set_nodeproof(&vchSig[0], vchSig.size()); h->set_nodeproof(&vchSig[0], vchSig.size());
h->set_ipv4port(theConfig.PEER_PORT); h->set_ipv4port(theConfig.PEER_PORT);
Ledger::pointer closedLedger = theApp->getMasterLedger().getClosedLedger(); Ledger::pointer closedLedger = theApp->getMasterLedger().getClosedLedger();
assert(closedLedger && closedLedger->isClosed()); assert(closedLedger && closedLedger->isClosed());
if(closedLedger->isClosed()) if (closedLedger->isClosed())
{ {
Serializer s(128); uint256 hash = closedLedger->getHash();
closedLedger->addRaw(s); h->set_closedledger(hash.begin(), hash.GetSerializeSize());
h->set_closedledger(s.getDataPtr(), s.getLength()); hash = closedLedger->getParentHash();
h->set_previousledger(hash.begin(), hash.GetSerializeSize());
} }
PackedMessage::pointer packet = boost::make_shared<PackedMessage> PackedMessage::pointer packet = boost::make_shared<PackedMessage>

View File

@@ -15,9 +15,9 @@
enum PeerPunish enum PeerPunish
{ {
PP_INVALID_REQUEST=1, // The peer sent a request that makes no sense PP_INVALID_REQUEST = 1, // The peer sent a request that makes no sense
PP_UNKNOWN_REQUEST=2, // The peer sent a request that might be garbage PP_UNKNOWN_REQUEST = 2, // The peer sent a request that might be garbage
PP_UNWANTED_DATA=3, // The peer sent us data we didn't want/need PP_UNWANTED_DATA = 3, // The peer sent us data we didn't want/need
}; };
typedef std::pair<std::string,int> ipPort; typedef std::pair<std::string,int> ipPort;
@@ -25,18 +25,23 @@ typedef std::pair<std::string,int> ipPort;
class Peer : public boost::enable_shared_from_this<Peer> class Peer : public boost::enable_shared_from_this<Peer>
{ {
public: public:
static const int psbGotHello=0, psbSentHello=1, psbInMap=2, psbTrusted=3; static const int psbGotHello = 0, psbSentHello = 1, psbInMap = 2, psbTrusted = 3;
static const int psbNoLedgers=4, psbNoTransactions=5, psbDownLevel=6; static const int psbNoLedgers = 4, psbNoTransactions = 5, psbDownLevel = 6;
void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it); void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it);
private: private:
bool mClientConnect; // In process of connecting as client. bool mClientConnect; // In process of connecting as client.
bool mConnected; // True, if hello accepted.
NewcoinAddress mNodePublic; // Node public key of peer. NewcoinAddress mNodePublic; // Node public key of peer.
ipPort mIpPort; ipPort mIpPort;
uint256 mCookieHash; uint256 mCookieHash;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> mSocketSsl; // network state information
uint256 mClosedLedgerHash, mPreviousLedgerHash;
boost::posix_time::ptime mClosedLedgerTime;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> mSocketSsl;
boost::asio::deadline_timer mVerifyTimer; boost::asio::deadline_timer mVerifyTimer;
@@ -62,8 +67,6 @@ protected:
void sendPacketForce(PackedMessage::pointer packet); void sendPacketForce(PackedMessage::pointer packet);
void sendHello(); void sendHello();
void sendTransaction(newcoin::TMTransaction& packet);
void sendValidation();
void recvHello(newcoin::TMHello& packet); void recvHello(newcoin::TMHello& packet);
void recvTransaction(newcoin::TMTransaction& packet); void recvTransaction(newcoin::TMTransaction& packet);
@@ -81,6 +84,7 @@ protected:
void recvAccount(newcoin::TMAccount& packet); void recvAccount(newcoin::TMAccount& packet);
void recvGetLedger(newcoin::TMGetLedger& packet); void recvGetLedger(newcoin::TMGetLedger& packet);
void recvLedger(newcoin::TMLedgerData& packet); void recvLedger(newcoin::TMLedgerData& packet);
void recvStatus(newcoin::TMStatusChange& packet);
void getSessionCookie(std::string& strDst); void getSessionCookie(std::string& strDst);
@@ -101,7 +105,7 @@ public:
void connect(const std::string strIp, int iPort); void connect(const std::string strIp, int iPort);
void connected(const boost::system::error_code& error); void connected(const boost::system::error_code& error);
void detach(); void detach(const char *);
bool samePeer(Peer::pointer p) { return samePeer(*p); } bool samePeer(Peer::pointer p) { return samePeer(*p); }
bool samePeer(const Peer& p) { return this == &p; } bool samePeer(const Peer& p) { return this == &p; }
@@ -118,6 +122,9 @@ public:
static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger); static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger);
static PackedMessage::pointer createValidation(Ledger::pointer ledger); static PackedMessage::pointer createValidation(Ledger::pointer ledger);
static PackedMessage::pointer createGetFullLedger(uint256& hash); static PackedMessage::pointer createGetFullLedger(uint256& hash);
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
NewcoinAddress getNodePublic() const { return mNodePublic; }
}; };
#endif #endif

View File

@@ -19,11 +19,11 @@ CKey::pointer PubKeyCache::locate(const NewcoinAddress& id)
std::vector<unsigned char> data; std::vector<unsigned char> data;
data.reserve(65); // our public keys are actually 33 bytes data.reserve(65); // our public keys are actually 33 bytes
int pkSize; int pkSize;
if(1)
{ // is it in the database { // is it in the database
ScopedLock sl(theApp->getTxnDB()->getDBLock()); ScopedLock sl(theApp->getTxnDB()->getDBLock());
Database* db=theApp->getTxnDB()->getDB(); Database* db=theApp->getTxnDB()->getDB();
if(!db->executeSQL(sql.c_str()) || !db->startIterRows() || !db->getNextRow()) if(!db->executeSQL(sql) || !db->startIterRows())
return CKey::pointer(); return CKey::pointer();
pkSize=db->getBinary("PubKey", &(data.front()), data.size()); pkSize=db->getBinary("PubKey", &(data.front()), data.size());
db->endIterRows(); db->endIterRows();
@@ -36,7 +36,6 @@ CKey::pointer PubKeyCache::locate(const NewcoinAddress& id)
return CKey::pointer(); return CKey::pointer();
} }
if(1)
{ // put it in cache (okay if we race with another retriever) { // put it in cache (okay if we race with another retriever)
boost::mutex::scoped_lock sl(mLock); boost::mutex::scoped_lock sl(mLock);
mCache.insert(std::make_pair(id, ckp)); mCache.insert(std::make_pair(id, ckp));
@@ -46,7 +45,6 @@ CKey::pointer PubKeyCache::locate(const NewcoinAddress& id)
CKey::pointer PubKeyCache::store(const NewcoinAddress& id, CKey::pointer key) CKey::pointer PubKeyCache::store(const NewcoinAddress& id, CKey::pointer key)
{ // stored if needed, returns cached copy (possibly the original) { // stored if needed, returns cached copy (possibly the original)
if(1)
{ {
boost::mutex::scoped_lock sl(mLock); boost::mutex::scoped_lock sl(mLock);
std::pair<std::map<NewcoinAddress,CKey::pointer>::iterator, bool> pit(mCache.insert(std::make_pair(id, key))); std::pair<std::map<NewcoinAddress,CKey::pointer>::iterator, bool> pit(mCache.insert(std::make_pair(id, key)));
@@ -65,7 +63,7 @@ CKey::pointer PubKeyCache::store(const NewcoinAddress& id, CKey::pointer key)
sql.append(");"); sql.append(");");
ScopedLock dbl(theApp->getTxnDB()->getDBLock()); ScopedLock dbl(theApp->getTxnDB()->getDBLock());
theApp->getTxnDB()->getDB()->executeSQL(sql.c_str(), true); theApp->getTxnDB()->getDB()->executeSQL(sql, true);
return key; return key;
} }
@@ -74,3 +72,4 @@ void PubKeyCache::clear()
boost::mutex::scoped_lock sl(mLock); boost::mutex::scoped_lock sl(mLock);
mCache.empty(); mCache.empty();
} }
// vim:ts=4

View File

@@ -253,7 +253,7 @@ Json::Value RPCServer::doNewAccount(Json::Value &params)
return JSONRPCError(500, "Family required"); return JSONRPCError(500, "Family required");
NewcoinAddress family = parseFamily(fParam); NewcoinAddress family = parseFamily(fParam);
if(!family.isValid()) return JSONRPCError(500, "Family not found."); if (!family.isValid()) return JSONRPCError(500, "Family not found.");
LocalAccount::pointer account(theApp->getWallet().getNewLocalAccount(family)); LocalAccount::pointer account(theApp->getWallet().getNewLocalAccount(family));
if(!account) if(!account)

View File

@@ -11,9 +11,9 @@
SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(Modifying) SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(Modifying)
{ {
root=boost::make_shared<SHAMapTreeNode>(SHAMapNode(0, uint256()), mSeq); root = boost::make_shared<SHAMapTreeNode>(SHAMapNode(0, uint256()), mSeq);
root->makeInner(); root->makeInner();
mTNByID[*root]=root; mTNByID[*root] = root;
} }
std::stack<SHAMapTreeNode::pointer> SHAMap::getStack(const uint256& id, bool include_nonmatching_leaf) std::stack<SHAMapTreeNode::pointer> SHAMap::getStack(const uint256& id, bool include_nonmatching_leaf)
@@ -21,27 +21,27 @@ std::stack<SHAMapTreeNode::pointer> SHAMap::getStack(const uint256& id, bool inc
// Walk the tree as far as possible to the specified identifier // Walk the tree as far as possible to the specified identifier
// produce a stack of nodes along the way, with the terminal node at the top // produce a stack of nodes along the way, with the terminal node at the top
std::stack<SHAMapTreeNode::pointer> stack; std::stack<SHAMapTreeNode::pointer> stack;
SHAMapTreeNode::pointer node=root; SHAMapTreeNode::pointer node = root;
while(!node->isLeaf()) while (!node->isLeaf())
{ {
stack.push(node); stack.push(node);
int branch=node->selectBranch(id); int branch = node->selectBranch(id);
assert(branch>=0); assert(branch >= 0);
uint256 hash=node->getChildHash(branch); uint256 hash = node->getChildHash(branch);
if(hash.isZero()) return stack; if (hash.isZero()) return stack;
node=getNode(node->getChildNodeID(branch), hash, false); node = getNode(node->getChildNodeID(branch), hash, false);
if(!node) if (!node)
{ {
if(isSynching()) return stack; if (isSynching()) return stack;
throw SHAMapException(MissingNode); throw SHAMapException(MissingNode);
} }
} }
if(include_nonmatching_leaf || (node->peekItem()->getTag()==id)) if (include_nonmatching_leaf || (node->peekItem()->getTag() == id))
stack.push(node); stack.push(node);
return stack; return stack;
@@ -51,20 +51,20 @@ void SHAMap::dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256&
{ // walk the tree up from through the inner nodes to the root { // walk the tree up from through the inner nodes to the root
// update linking hashes and add nodes to dirty list // update linking hashes and add nodes to dirty list
assert(mState!=Synching && mState!=Immutable); assert((mState != Synching) && (mState != Immutable));
while(!stack.empty()) while (!stack.empty())
{ {
SHAMapTreeNode::pointer node=stack.top(); SHAMapTreeNode::pointer node=stack.top();
stack.pop(); stack.pop();
assert(node->isInnerNode()); assert(node->isInnerNode());
int branch=node->selectBranch(target); int branch = node->selectBranch(target);
assert(branch>=0); assert(branch >= 0);
returnNode(node, true); returnNode(node, true);
if(!node->setChildHash(branch, prevHash)) if (!node->setChildHash(branch, prevHash))
{ {
std::cerr << "dirtyUp terminates early" << std::endl; std::cerr << "dirtyUp terminates early" << std::endl;
assert(false); assert(false);
@@ -73,44 +73,44 @@ void SHAMap::dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256&
#ifdef ST_DEBUG #ifdef ST_DEBUG
std::cerr << "dirtyUp sets branch " << branch << " to " << prevHash.GetHex() << std::endl; std::cerr << "dirtyUp sets branch " << branch << " to " << prevHash.GetHex() << std::endl;
#endif #endif
prevHash=node->getNodeHash(); prevHash = node->getNodeHash();
assert(prevHash.isNonZero()); assert(prevHash.isNonZero());
} }
} }
SHAMapTreeNode::pointer SHAMap::checkCacheNode(const SHAMapNode& iNode) SHAMapTreeNode::pointer SHAMap::checkCacheNode(const SHAMapNode& iNode)
{ {
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it=mTNByID.find(iNode); boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = mTNByID.find(iNode);
if(it==mTNByID.end()) return SHAMapTreeNode::pointer(); if (it == mTNByID.end()) return SHAMapTreeNode::pointer();
return it->second; return it->second;
} }
SHAMapTreeNode::pointer SHAMap::walkTo(const uint256& id, bool modify) SHAMapTreeNode::pointer SHAMap::walkTo(const uint256& id, bool modify)
{ // walk down to the terminal node for this ID { // walk down to the terminal node for this ID
SHAMapTreeNode::pointer inNode = root;
SHAMapTreeNode::pointer inNode=root; while (!inNode->isLeaf())
while(!inNode->isLeaf())
{ {
int branch=inNode->selectBranch(id); int branch = inNode->selectBranch(id);
if(inNode->isEmptyBranch(branch)) return inNode; if (inNode->isEmptyBranch(branch)) return inNode;
uint256 childHash=inNode->getChildHash(branch); uint256 childHash = inNode->getChildHash(branch);
if(childHash.isZero()) return inNode; if (childHash.isZero()) return inNode;
SHAMapTreeNode::pointer nextNode=getNode(inNode->getChildNodeID(branch), childHash, false); SHAMapTreeNode::pointer nextNode = getNode(inNode->getChildNodeID(branch), childHash, false);
if(!nextNode) throw SHAMapException(MissingNode); if (!nextNode) throw SHAMapException(MissingNode);
inNode=nextNode; inNode = nextNode;
} }
if(modify) returnNode(inNode, true); if (inNode->getTag() != id) return SHAMapTreeNode::pointer();
if (modify) returnNode(inNode, true);
return inNode; return inNode;
} }
SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& hash, bool modify) SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& hash, bool modify)
{ // retrieve a node whose node hash is known { // retrieve a node whose node hash is known
SHAMapTreeNode::pointer node=checkCacheNode(id); SHAMapTreeNode::pointer node = checkCacheNode(id);
if(node) if (node)
{ {
if(node->getNodeHash()!=hash) if (node->getNodeHash()!=hash)
{ {
#ifdef DEBUG #ifdef DEBUG
std::cerr << "Attempt to get node, hash not in tree" << std::endl; std::cerr << "Attempt to get node, hash not in tree" << std::endl;
@@ -128,10 +128,10 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has
std::vector<unsigned char> nodeData; std::vector<unsigned char> nodeData;
if(!fetchNode(hash, nodeData)) return SHAMapTreeNode::pointer(); if(!fetchNode(hash, nodeData)) return SHAMapTreeNode::pointer();
node=boost::make_shared<SHAMapTreeNode>(id, nodeData, mSeq); node = boost::make_shared<SHAMapTreeNode>(id, nodeData, mSeq);
if(node->getNodeHash()!=hash) throw SHAMapException(InvalidNode); if (node->getNodeHash() != hash) throw SHAMapException(InvalidNode);
if(!mTNByID.insert(std::make_pair(id, node)).second) if (!mTNByID.insert(std::make_pair(id, node)).second)
assert(false); assert(false);
return node; return node;
} }
@@ -139,15 +139,15 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has
void SHAMap::returnNode(SHAMapTreeNode::pointer& node, bool modify) void SHAMap::returnNode(SHAMapTreeNode::pointer& node, bool modify)
{ // make sure the node is suitable for the intended operation (copy on write) { // make sure the node is suitable for the intended operation (copy on write)
assert(node->isValid()); assert(node->isValid());
if(node && modify && (node->getSeq()!=mSeq)) if (node && modify && (node->getSeq()!=mSeq))
{ {
#ifdef DEBUG #ifdef DEBUG
std::cerr << "returnNode COW" << std::endl; std::cerr << "returnNode COW" << std::endl;
#endif #endif
if(mDirtyNodes) (*mDirtyNodes)[*node]=node; if (mDirtyNodes) (*mDirtyNodes)[*node] = node;
node=boost::make_shared<SHAMapTreeNode>(*node, mSeq); node = boost::make_shared<SHAMapTreeNode>(*node, mSeq);
assert(node->isValid()); assert(node->isValid());
mTNByID[*node]=node; mTNByID[*node] = node;
} }
} }
@@ -163,24 +163,24 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode::pointer node)
#endif #endif
do do
{ // Walk down the tree { // Walk down the tree
if(node->hasItem()) return node->peekItem(); if (node->hasItem()) return node->peekItem();
bool foundNode=false; bool foundNode = false;
for(int i=0; i<16; i++) for (int i = 0; i < 16; ++i)
if(!node->isEmptyBranch(i)) if (!node->isEmptyBranch(i))
{ {
#ifdef ST_DEBUG #ifdef ST_DEBUG
std::cerr << " FB: node " << node->getString() << std::endl; std::cerr << " FB: node " << node->getString() << std::endl;
std::cerr << " has non-empty branch " << i << " : " << std::cerr << " has non-empty branch " << i << " : " <<
node->getChildNodeID(i).getString() << ", " << node->getChildHash(i).GetHex() << std::endl; node->getChildNodeID(i).getString() << ", " << node->getChildHash(i).GetHex() << std::endl;
#endif #endif
node=getNode(node->getChildNodeID(i), node->getChildHash(i), false); node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if(!node) throw SHAMapException(MissingNode); if (!node) throw SHAMapException(MissingNode);
foundNode=true; foundNode = true;
break; break;
} }
if(!foundNode) return SHAMapItem::pointer(); if (!foundNode) return SHAMapItem::pointer();
} while(1); } while (1);
} }
SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode::pointer node) SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode::pointer node)
@@ -191,46 +191,46 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode::pointer node)
do do
{ // Walk down the tree { // Walk down the tree
if(node->hasItem()) return node->peekItem(); if (node->hasItem()) return node->peekItem();
bool foundNode=false; bool foundNode = false;
for(int i=15; i>=0; i++) for (int i = 15; i >= 0; ++i)
if(!node->isEmptyBranch(i)) if (!node->isEmptyBranch(i))
{ {
node=getNode(node->getChildNodeID(i), node->getChildHash(i), false); node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if(!node) throw SHAMapException(MissingNode); if (!node) throw SHAMapException(MissingNode);
foundNode=true; foundNode = true;
break; break;
} }
if(!foundNode) return SHAMapItem::pointer(); if (!foundNode) return SHAMapItem::pointer();
} while(1); } while (1);
} }
SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode::pointer node) SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode::pointer node)
{ {
// If there is only one item below this node, return it // If there is only one item below this node, return it
bool found; bool found;
while(!node->isLeaf()) while (!node->isLeaf())
{ {
found=false; found = false;
SHAMapTreeNode::pointer nextNode; SHAMapTreeNode::pointer nextNode;
for(int i=0; i<16; i++) for (int i = 0; i < 16; ++i)
if(!node->isEmptyBranch(i)) if (!node->isEmptyBranch(i))
{ {
if(found) return SHAMapItem::pointer(); // two leaves below if( found) return SHAMapItem::pointer(); // two leaves below
nextNode=getNode(node->getChildNodeID(i), node->getChildHash(i), false); nextNode = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if(!nextNode) throw SHAMapException(MissingNode); if (!nextNode) throw SHAMapException(MissingNode);
found=true; found = true;
} }
if(!found) if (!found)
{ {
std::cerr << node->getString() << std::endl; std::cerr << node->getString() << std::endl;
assert(false); assert(false);
return SHAMapItem::pointer(); return SHAMapItem::pointer();
} }
node=nextNode; node = nextNode;
} }
assert(node->hasItem()); assert(node->hasItem());
return node->peekItem(); return node->peekItem();
@@ -342,7 +342,7 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id)
bool SHAMap::hasItem(const uint256& id) bool SHAMap::hasItem(const uint256& id)
{ // does the tree have an item with this ID { // does the tree have an item with this ID
boost::recursive_mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
SHAMapTreeNode::pointer leaf=walkTo(id, false); SHAMapTreeNode::pointer leaf=walkTo(id, false);
if(!leaf) return false; if(!leaf) return false;
SHAMapItem::pointer item=leaf->peekItem(); SHAMapItem::pointer item=leaf->peekItem();
@@ -472,7 +472,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction)
node->makeInner(); node->makeInner();
int b1, b2; int b1, b2;
while( (b1=node->selectBranch(tag)) == (b2=node->selectBranch(otherItem->getTag())) ) while( (b1=node->selectBranch(tag)) == (b2=node->selectBranch(otherItem->getTag())) )
{ // we need a new inner node, since both go on same branch at this level { // we need a new inner node, since both go on same branch at this level
#ifdef ST_DEBUG #ifdef ST_DEBUG
@@ -618,11 +618,11 @@ void SHAMap::dump(bool hash)
} }
static std::vector<unsigned char>IntToVUC(int i) static std::vector<unsigned char>IntToVUC(int v)
{ {
std::vector<unsigned char> vuc; std::vector<unsigned char> vuc;
for(int i=0; i<32; i++) for (int i = 0; i < 32; ++i)
vuc.push_back((unsigned char) i); vuc.push_back(static_cast<unsigned char>(v));
return vuc; return vuc;
} }
@@ -675,4 +675,4 @@ bool SHAMap::TestSHAMap()
return false; return false;
return true; return true;
} }
// vim:ts=4

View File

@@ -40,14 +40,14 @@ public:
SHAMapNode(int depth, const uint256& hash); SHAMapNode(int depth, const uint256& hash);
int getDepth() const { return mDepth; } int getDepth() const { return mDepth; }
const uint256& getNodeID() const { return mNodeID; } const uint256& getNodeID() const { return mNodeID; }
bool isValid() const { return (mDepth>=0) && (mDepth<64); } bool isValid() const { return (mDepth >= 0) && (mDepth < 64); }
virtual bool isPopulated() const { return false; } virtual bool isPopulated() const { return false; }
SHAMapNode getParentNodeID() const SHAMapNode getParentNodeID() const
{ {
assert(mDepth); assert(mDepth);
return SHAMapNode(mDepth-1, mNodeID); return SHAMapNode(mDepth - 1, mNodeID);
} }
SHAMapNode getChildNodeID(int m) const; SHAMapNode getChildNodeID(int m) const;
int selectBranch(const uint256& hash) const; int selectBranch(const uint256& hash) const;
@@ -108,18 +108,18 @@ public:
void updateData(const std::vector<unsigned char>& data) { mData=data; } void updateData(const std::vector<unsigned char>& data) { mData=data; }
bool operator<(const SHAMapItem& i) const { return mTag<i.mTag; } bool operator<(const SHAMapItem& i) const { return mTag < i.mTag; }
bool operator>(const SHAMapItem& i) const { return mTag>i.mTag; } bool operator>(const SHAMapItem& i) const { return mTag > i.mTag; }
bool operator==(const SHAMapItem& i) const { return mTag==i.mTag; } bool operator==(const SHAMapItem& i) const { return mTag == i.mTag; }
bool operator!=(const SHAMapItem& i) const { return mTag!=i.mTag; } bool operator!=(const SHAMapItem& i) const { return mTag != i.mTag; }
bool operator<=(const SHAMapItem& i) const { return mTag<=i.mTag; } bool operator<=(const SHAMapItem& i) const { return mTag <= i.mTag; }
bool operator>=(const SHAMapItem& i) const { return mTag>=i.mTag; } bool operator>=(const SHAMapItem& i) const { return mTag >= i.mTag; }
bool operator<(const uint256& i) const { return mTag<i; } bool operator<(const uint256& i) const { return mTag < i; }
bool operator>(const uint256& i) const { return mTag>i; } bool operator>(const uint256& i) const { return mTag > i; }
bool operator==(const uint256& i) const { return mTag==i; } bool operator==(const uint256& i) const { return mTag == i; }
bool operator!=(const uint256& i) const { return mTag!=i; } bool operator!=(const uint256& i) const { return mTag != i; }
bool operator<=(const uint256& i) const { return mTag<=i; } bool operator<=(const uint256& i) const { return mTag <= i; }
bool operator>=(const uint256& i) const { return mTag>=i; } bool operator>=(const uint256& i) const { return mTag >= i; }
virtual void dump(); virtual void dump();
}; };
@@ -132,10 +132,10 @@ public:
enum TNType enum TNType
{ {
tnERROR =0, tnERROR = 0,
tnINNER =1, tnINNER = 1,
tnTRANSACTION =2, tnTRANSACTION = 2,
tnACCOUNT_STATE =3 tnACCOUNT_STATE = 3
}; };
private: private:
@@ -251,11 +251,11 @@ protected:
bool walkBranch(SHAMapTreeNode::pointer node, SHAMapItem::pointer otherMapItem, bool isFirstMap, bool walkBranch(SHAMapTreeNode::pointer node, SHAMapItem::pointer otherMapItem, bool isFirstMap,
SHAMapDiff& differences, int& maxCount); SHAMapDiff& differences, int& maxCount);
public: public:
// build new map // build new map
SHAMap(uint32 seq=0); SHAMap(uint32 seq = 0);
// hold the map stable across operations // hold the map stable across operations
ScopedLock Lock() const { return ScopedLock(mLock); } ScopedLock Lock() const { return ScopedLock(mLock); }
@@ -295,7 +295,7 @@ public:
// status functions // status functions
void setImmutable(void) { assert(mState != Invalid); mState = Immutable; } void setImmutable(void) { assert(mState != Invalid); mState = Immutable; }
void clearImmutable(void) { mState = Modifying; } void clearImmutable(void) { mState = Modifying; }
bool isSynching(void) const { return mState == Floating || mState == Synching; } bool isSynching(void) const { return (mState == Floating) || (mState == Synching); }
void setSynching(void) { mState = Synching; } void setSynching(void) { mState = Synching; }
void setFloating(void) { mState = Floating; } void setFloating(void) { mState = Floating; }
void clearSynching(void) { mState = Modifying; } void clearSynching(void) { mState = Modifying; }
@@ -315,6 +315,11 @@ public:
bool operator==(const SHAMap& s) { return getHash() == s.getHash(); } bool operator==(const SHAMap& s) { return getHash() == s.getHash(); }
// trusted path operations - prove a particular node is in a particular ledger
std::list<std::vector<unsigned char> > getTrustedPath(const uint256& index);
static std::vector<unsigned char> checkTrustedPath(const uint256& ledgerHash, const uint256& leafIndex,
const std::list<std::vector<unsigned char> >& path);
static bool TestSHAMap(); static bool TestSHAMap();
static bool syncTest(); static bool syncTest();
bool deepCompare(SHAMap& other); bool deepCompare(SHAMap& other);
@@ -322,3 +327,4 @@ public:
}; };
#endif #endif
// vim:ts=4

View File

@@ -97,11 +97,11 @@ SHAMapNode::SHAMapNode(int depth, const uint256 &hash) : mDepth(depth)
SHAMapNode::SHAMapNode(const void *ptr, int len) SHAMapNode::SHAMapNode(const void *ptr, int len)
{ {
if(len<33) mDepth=-1; if (len < 33) mDepth = -1;
else else
{ {
memcpy(&mNodeID, ptr, 32); memcpy(&mNodeID, ptr, 32);
mDepth=*(static_cast<const unsigned char *>(ptr) + 32); mDepth = *(static_cast<const unsigned char *>(ptr) + 32);
} }
} }
@@ -120,21 +120,21 @@ std::string SHAMapNode::getRawString() const
SHAMapNode SHAMapNode::getChildNodeID(int m) const SHAMapNode SHAMapNode::getChildNodeID(int m) const
{ // This can be optimized to avoid the << if needed { // This can be optimized to avoid the << if needed
assert((m>=0) && (m<16)); assert((m >= 0) && (m < 16));
uint256 child(mNodeID); uint256 child(mNodeID);
child.PeekAt(mDepth/8) |= m << (4*(mDepth%8)); child.PeekAt(mDepth / 8) |= m << (4 * (mDepth % 8));
return SHAMapNode(mDepth+1, child); return SHAMapNode(mDepth + 1, child);
} }
int SHAMapNode::selectBranch(const uint256& hash) const int SHAMapNode::selectBranch(const uint256& hash) const
{ // Which branch would contain the specified hash { // Which branch would contain the specified hash
if(mDepth==63) if (mDepth == 63)
{ {
assert(false); assert(false);
return -1; return -1;
} }
if((hash&smMasks[mDepth])!=mNodeID) if ((hash & smMasks[mDepth]) != mNodeID)
{ {
std::cerr << "selectBranch(" << getString() << std::endl; std::cerr << "selectBranch(" << getString() << std::endl;
std::cerr << " " << hash.GetHex() << " off branch" << std::endl; std::cerr << " " << hash.GetHex() << " off branch" << std::endl;
@@ -142,11 +142,11 @@ int SHAMapNode::selectBranch(const uint256& hash) const
return -1; // does not go under this node return -1; // does not go under this node
} }
int branch=*(hash.begin()+(mDepth/2)); int branch = *(hash.begin() + (mDepth / 2));
if(mDepth%2) branch>>=4; if (mDepth % 2) branch >>= 4;
else branch&=0xf; else branch &= 0xf;
assert(branch>=0 && branch<16); assert((branch >= 0) && (branch < 16));
return branch; return branch;
} }
@@ -164,7 +164,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq) : SHAMapN
mHash(node.mHash), mItem(node.mItem), mSeq(seq), mType(node.mType), mFullBelow(false) mHash(node.mHash), mItem(node.mItem), mSeq(seq), mType(node.mType), mFullBelow(false)
{ {
if(node.mItem) if(node.mItem)
mItem=boost::make_shared<SHAMapItem>(*node.mItem); mItem = boost::make_shared<SHAMapItem>(*node.mItem);
else else
memcpy(mHashes, node.mHashes, sizeof(mHashes)); memcpy(mHashes, node.mHashes, sizeof(mHashes));
} }
@@ -172,7 +172,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq) : SHAMapN
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::pointer item, TNType type, uint32 seq) : SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::pointer item, TNType type, uint32 seq) :
SHAMapNode(node), mItem(item), mSeq(seq), mType(type), mFullBelow(true) SHAMapNode(node), mItem(item), mSeq(seq), mType(type), mFullBelow(true)
{ {
assert(item->peekData().size()>=12); assert(item->peekData().size() >= 12);
updateHash(); updateHash();
} }
@@ -181,41 +181,41 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
{ {
Serializer s(rawNode); Serializer s(rawNode);
int type=s.removeLastByte(); int type = s.removeLastByte();
int len=s.getLength(); int len = s.getLength();
if( (type<0) || (type>3) || (len<32) ) throw SHAMapException(InvalidNode); if ((type < 0) || (type > 3) || (len < 32)) throw SHAMapException(InvalidNode);
if(type==0) if (type == 0)
{ // transaction { // transaction
mItem=boost::make_shared<SHAMapItem>(s.getSHA512Half(), s.peekData()); mItem = boost::make_shared<SHAMapItem>(s.getSHA512Half(), s.peekData());
mType=tnTRANSACTION; mType = tnTRANSACTION;
} }
else if(type==1) else if (type == 1)
{ // account state { // account state
uint256 u; uint256 u;
s.get256(u, len-32); s.get256(u, len - 32);
s.chop(256/8); s.chop(256 / 8);
if(u.isZero()) throw SHAMapException(InvalidNode); if (u.isZero()) throw SHAMapException(InvalidNode);
mItem=boost::make_shared<SHAMapItem>(u, s.peekData()); mItem = boost::make_shared<SHAMapItem>(u, s.peekData());
mType=tnACCOUNT_STATE; mType = tnACCOUNT_STATE;
} }
else if(type==2) else if (type == 2)
{ // full inner { // full inner
if(len!=512) throw SHAMapException(InvalidNode); if (len != 512) throw SHAMapException(InvalidNode);
for(int i=0; i<16; i++) for (int i = 0; i < 16; ++i)
s.get256(mHashes[i], i*32); s.get256(mHashes[i], i * 32);
mType=tnINNER; mType = tnINNER;
} }
else if(type==3) else if (type == 3)
{ // compressed inner { // compressed inner
for(int i=0; i<(len/33); i++) for (int i = 0; i < (len / 33); ++i)
{ {
int pos; int pos;
s.get8(pos, 32+(i*33)); s.get8(pos, 32 + (i * 33));
if( (pos<0) || (pos>=16)) throw SHAMapException(InvalidNode); if ((pos < 0) || (pos >= 16)) throw SHAMapException(InvalidNode);
s.get256(mHashes[pos], i*33); s.get256(mHashes[pos], i * 33);
} }
mType=tnINNER; mType = tnINNER;
} }
updateHash(); updateHash();
@@ -223,17 +223,17 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
void SHAMapTreeNode::addRaw(Serializer &s) void SHAMapTreeNode::addRaw(Serializer &s)
{ {
if(mType==tnERROR) throw SHAMapException(InvalidNode); if (mType == tnERROR) throw SHAMapException(InvalidNode);
if(mType==tnTRANSACTION) if (mType == tnTRANSACTION)
{ {
mItem->addRaw(s); mItem->addRaw(s);
s.add8(0); s.add8(0);
assert(s.getLength()>32); assert(s.getLength() > 32);
return; return;
} }
if(mType==tnACCOUNT_STATE) if (mType == tnACCOUNT_STATE)
{ {
mItem->addRaw(s); mItem->addRaw(s);
s.add256(mItem->getTag()); s.add256(mItem->getTag());
@@ -241,10 +241,10 @@ void SHAMapTreeNode::addRaw(Serializer &s)
return; return;
} }
if(getBranchCount()<12) if (getBranchCount() < 12)
{ // compressed node { // compressed node
for(int i=0; i<16; i++) for (int i = 0; i < 16; ++i)
if(mHashes[i].isNonZero()) if (mHashes[i].isNonZero())
{ {
s.add256(mHashes[i]); s.add256(mHashes[i]);
s.add8(i); s.add8(i);
@@ -253,7 +253,7 @@ void SHAMapTreeNode::addRaw(Serializer &s)
return; return;
} }
for(int i=0; i<16; i++) for (int i = 0; i < 16; ++i)
s.add256(mHashes[i]); s.add256(mHashes[i]);
s.add8(2); s.add8(2);
} }
@@ -262,44 +262,44 @@ bool SHAMapTreeNode::updateHash()
{ {
uint256 nh; uint256 nh;
if(mType==tnINNER) if (mType == tnINNER)
{ {
bool empty=true; bool empty = true;
for(int i=0; i<16; i++) for (int i = 0; i < 16; ++i)
if(mHashes[i].isNonZero()) if (mHashes[i].isNonZero())
{ {
empty=false; empty = false;
break; break;
} }
if(!empty) if(!empty)
nh=Serializer::getSHA512Half(reinterpret_cast<unsigned char *>(mHashes), sizeof(mHashes)); nh = Serializer::getSHA512Half(reinterpret_cast<unsigned char *>(mHashes), sizeof(mHashes));
} }
else if(mType==tnACCOUNT_STATE) else if (mType == tnACCOUNT_STATE)
{ {
Serializer s; Serializer s;
mItem->addRaw(s); mItem->addRaw(s);
s.add160(mItem->getTag().to160()); s.add160(mItem->getTag().to160());
nh=s.getSHA512Half(); nh = s.getSHA512Half();
} }
else if(mType==tnTRANSACTION) else if (mType == tnTRANSACTION)
{ {
nh=Serializer::getSHA512Half(mItem->peekData()); nh = Serializer::getSHA512Half(mItem->peekData());
} }
else assert(false); else assert(false);
if(nh==mHash) return false; if (nh == mHash) return false;
mHash=nh; mHash = nh;
return true; return true;
} }
bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type) bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type)
{ {
uint256 hash=getNodeHash(); uint256 hash = getNodeHash();
mType=type; mType = type;
mItem=i; mItem = i;
assert(isLeaf()); assert(isLeaf());
updateHash(); updateHash();
return getNodeHash()==hash; return getNodeHash() == hash;
} }
SHAMapItem::pointer SHAMapTreeNode::getItem() const SHAMapItem::pointer SHAMapTreeNode::getItem() const
@@ -311,17 +311,17 @@ SHAMapItem::pointer SHAMapTreeNode::getItem() const
int SHAMapTreeNode::getBranchCount() const int SHAMapTreeNode::getBranchCount() const
{ {
assert(isInner()); assert(isInner());
int ret=0; int ret = 0;
for(int i=0; i<16; ++i) for (int i = 0; i < 16; ++i)
if(mHashes[i].isNonZero()) ++ret; if (mHashes[i].isNonZero()) ++ret;
return ret; return ret;
} }
void SHAMapTreeNode::makeInner() void SHAMapTreeNode::makeInner()
{ {
mItem=SHAMapItem::pointer(); mItem = SHAMapItem::pointer();
memset(mHashes, 0, sizeof(mHashes)); memset(mHashes, 0, sizeof(mHashes));
mType=tnINNER; mType = tnINNER;
mHash.zero(); mHash.zero();
} }
@@ -332,39 +332,40 @@ void SHAMapTreeNode::dump()
std::string SHAMapTreeNode::getString() const std::string SHAMapTreeNode::getString() const
{ {
std::string ret="NodeID("; std::string ret = "NodeID(";
ret+=boost::lexical_cast<std::string>(getDepth()); ret += boost::lexical_cast<std::string>(getDepth());
ret+=","; ret += ",";
ret+=getNodeID().GetHex(); ret += getNodeID().GetHex();
ret+=")"; ret += ")";
if(isInner()) if (isInner())
{ {
for(int i=0; i<16; i++) for(int i = 0; i < 16; ++i)
if(!isEmptyBranch(i)) if (!isEmptyBranch(i))
{ {
ret+=",b"; ret += ",b";
ret+=boost::lexical_cast<std::string>(i); ret += boost::lexical_cast<std::string>(i);
} }
} }
if(isLeaf()) if (isLeaf())
{ {
ret+=",leaf"; ret += ",leaf";
} }
return ret; return ret;
} }
bool SHAMapTreeNode::setChildHash(int m, const uint256 &hash) bool SHAMapTreeNode::setChildHash(int m, const uint256 &hash)
{ {
assert( (m>=0) && (m<16) ); assert((m >= 0) && (m < 16));
assert(mType==tnINNER); assert(mType == tnINNER);
if(mHashes[m]==hash) if(mHashes[m] == hash)
return false; return false;
mHashes[m]=hash; mHashes[m] = hash;
return updateHash(); return updateHash();
} }
const uint256& SHAMapTreeNode::getChildHash(int m) const const uint256& SHAMapTreeNode::getChildHash(int m) const
{ {
assert( (m>=0) && (m<16) && (mType==tnINNER) ); assert((m >= 0) && (m < 16) && (mType == tnINNER));
return mHashes[m]; return mHashes[m];
} }
// vim:ts=4

View File

@@ -348,6 +348,26 @@ static bool confuseMap(SHAMap &map, int count)
return true; return true;
} }
std::list<std::vector<unsigned char> > SHAMap::getTrustedPath(const uint256& index)
{
boost::recursive_mutex::scoped_lock sl(mLock);
std::stack<SHAMapTreeNode::pointer> stack = SHAMap::getStack(index, false);
if (stack.empty() || !stack.top()->isLeaf())
throw std::runtime_error("requested leaf not present");
std::list< std::vector<unsigned char> > path;
Serializer s;
while (!stack.empty())
{
stack.top()->addRaw(s);
path.push_back(s.getData());
s.erase();
stack.pop();
}
return path;
}
bool SHAMap::syncTest() bool SHAMap::syncTest()
{ {
unsigned int seed; unsigned int seed;

View File

@@ -39,7 +39,7 @@ std::string SerializedLedgerEntry::getFullText() const
ret += mIndex.GetHex(); ret += mIndex.GetHex();
ret += "\" = { "; ret += "\" = { ";
ret += mFormat->t_name; ret += mFormat->t_name;
ret += ", "; ret += ", ";
ret += mObject.getFullText(); ret += mObject.getFullText();
ret += "}"; ret += "}";
return ret; return ret;
@@ -71,3 +71,4 @@ bool SerializedLedgerEntry::isEquivalent(const SerializedType& t) const
if (mObject != v->mObject) return false; if (mObject != v->mObject) return false;
return true; return true;
} }
// vim:ts=4

View File

@@ -53,7 +53,7 @@ public:
std::vector<unsigned char> getIFieldVL(SOE_Field field) const { return mObject.getValueFieldVL(field); } std::vector<unsigned char> getIFieldVL(SOE_Field field) const { return mObject.getValueFieldVL(field); }
std::vector<TaggedListItem> getIFieldTL(SOE_Field field) const { return mObject.getValueFieldTL(field); } std::vector<TaggedListItem> getIFieldTL(SOE_Field field) const { return mObject.getValueFieldTL(field); }
NewcoinAddress getIValueFieldAccount(SOE_Field field) const { return mObject.getValueFieldAccount(field); } NewcoinAddress getIValueFieldAccount(SOE_Field field) const { return mObject.getValueFieldAccount(field); }
void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); } void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); }
void setIFieldU16(SOE_Field field, uint16 v) { return mObject.setValueFieldU16(field, v); } void setIFieldU16(SOE_Field field, uint16 v) { return mObject.setValueFieldU16(field, v); }
void setIFieldU32(SOE_Field field, uint32 v) { return mObject.setValueFieldU32(field, v); } void setIFieldU32(SOE_Field field, uint32 v) { return mObject.setValueFieldU32(field, v); }
void setIFieldU64(SOE_Field field, uint32 v) { return mObject.setValueFieldU64(field, v); } void setIFieldU64(SOE_Field field, uint32 v) { return mObject.setValueFieldU64(field, v); }
@@ -74,3 +74,4 @@ public:
}; };
#endif #endif
// vim:ts=4

View File

@@ -467,6 +467,16 @@ void STObject::setValueFieldH160(SOE_Field field, const uint160& v)
cf->setValue(v); cf->setValue(v);
} }
void STObject::setValueFieldH256(SOE_Field field, const uint256& v)
{
SerializedType* rf = getPField(field);
if (!rf) throw std::runtime_error("Field not found");
if (rf->getSType() == STI_NOTPRESENT) rf = makeFieldPresent(field);
STHash256* cf = dynamic_cast<STHash256*>(rf);
if (!cf) throw std::runtime_error("Wrong field type");
cf->setValue(v);
}
void STObject::setValueFieldAccount(SOE_Field field, const uint160& v) void STObject::setValueFieldAccount(SOE_Field field, const uint160& v)
{ {
SerializedType* rf = getPField(field); SerializedType* rf = getPField(field);

View File

@@ -27,11 +27,12 @@ enum SOE_Field
sfFlags, sfExtensions, sfTargetLedger, sfSourceTag, sfIdentifier, sfFlags, sfExtensions, sfTargetLedger, sfSourceTag, sfIdentifier,
sfDestination, sfTarget, sfAmount, sfCurrency, sfDestination, sfTarget, sfAmount, sfCurrency,
sfAmountIn, sfAmountOut, sfCurrencyIn, sfCurrencyOut, sfAmountIn, sfAmountOut, sfCurrencyIn, sfCurrencyOut,
sfInvoiceID, sfExpireLedger, sfMessageKey, sfCurrentRate, sfRateLock, sfInvoiceID, sfExpireLedger, sfMessageKey, sfSigningKey, sfCurrentRate, sfRateLock,
sfAccount, sfSequence, sfBalance, sfWalletLocator, sfEmailHash, sfAccount, sfSequence, sfBalance, sfWalletLocator, sfEmailHash,
sfBorrower, sfLendfer, sfLimit, sfOfferCurrency, sfBorrower, sfLender, sfLimit, sfOfferCurrency, sfLedgerHash,
sfLastReceive, sfLastTxn, sfLender, sfNextRate, sfNextRateLgr, sfNextRateExp, sfLastReceive, sfLastTxn, sfNextRate, sfNextRateLgr, sfNextRateExp,
sfNickname, sfMinimumOffer, sfNickname, sfMinimumOffer,
sfAuthorizedKey, sfGenerator, sfGeneratorID, sfAccountID,
// test fields // test fields
sfTest1, sfTest2, sfTest3, sfTest4 sfTest1, sfTest2, sfTest3, sfTest4
@@ -131,3 +132,4 @@ public:
#endif #endif
// vim:ts=4

View File

@@ -38,14 +38,6 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit, int length
mMiddleTxn.giveObject(new STUInt64("Fee", sit.get64())); mMiddleTxn.giveObject(new STUInt64("Fee", sit.get64()));
mInnerTxn = STObject(mFormat->elements, sit, "InnerTransaction"); mInnerTxn = STObject(mFormat->elements, sit, "InnerTransaction");
updateSourceAccount();
}
void SerializedTransaction::updateSourceAccount()
{
NewcoinAddress a;
a.setAccountPublic(peekSigningPubKey());
mSourceAccount.setAccountID(a.getAccountID());
} }
int SerializedTransaction::getLength() const int SerializedTransaction::getLength() const
@@ -217,12 +209,25 @@ std::vector<unsigned char>& SerializedTransaction::peekSigningPubKey()
return v->peekValue(); return v->peekValue();
} }
const NewcoinAddress& SerializedTransaction::setSigningPubKey(const std::vector<unsigned char>& s) const NewcoinAddress& SerializedTransaction::setSigningPubKey(const NewcoinAddress& naSignPubKey)
{ {
mSignPubKey = naSignPubKey;
STVariableLength* v = dynamic_cast<STVariableLength*>(mMiddleTxn.getPIndex(TransactionISigningPubKey)); STVariableLength* v = dynamic_cast<STVariableLength*>(mMiddleTxn.getPIndex(TransactionISigningPubKey));
if (!v) throw std::runtime_error("corrupt transaction"); if (!v) throw std::runtime_error("corrupt transaction");
v->setValue(s); v->setValue(mSignPubKey.getAccountPublic());
updateSourceAccount();
return mSignPubKey;
}
const NewcoinAddress& SerializedTransaction::setSourceAccount(const NewcoinAddress& naSource)
{
mSourceAccount = naSource;
STHash160* v = dynamic_cast<STHash160*>(mMiddleTxn.getPIndex(TransactionISourceID));
if (!v) throw std::runtime_error("corrupt transaction");
v->setValue(mSourceAccount.getAccountID());
return mSourceAccount; return mSourceAccount;
} }
@@ -283,3 +288,4 @@ Json::Value SerializedTransaction::getJson(int options) const
ret["Inner"] = mInnerTxn.getJson(options); ret["Inner"] = mInnerTxn.getJson(options);
return ret; return ret;
} }
// vim:ts=4

View File

@@ -16,14 +16,13 @@ public:
typedef boost::shared_ptr<SerializedTransaction> pointer; typedef boost::shared_ptr<SerializedTransaction> pointer;
protected: protected:
NewcoinAddress mSignPubKey;
NewcoinAddress mSourceAccount; NewcoinAddress mSourceAccount;
TransactionType mType; TransactionType mType;
STVariableLength mSignature; STVariableLength mSignature;
STObject mMiddleTxn, mInnerTxn; STObject mMiddleTxn, mInnerTxn;
TransactionFormat* mFormat; TransactionFormat* mFormat;
void updateSourceAccount();
public: public:
SerializedTransaction(SerializerIterator& sit, int length); // -1=all remaining, 0=get from sit SerializedTransaction(SerializerIterator& sit, int length); // -1=all remaining, 0=get from sit
SerializedTransaction(TransactionType type); SerializedTransaction(TransactionType type);
@@ -42,7 +41,7 @@ public:
const std::vector<unsigned char>& peekSignature() const; const std::vector<unsigned char>& peekSignature() const;
void setSignature(const std::vector<unsigned char>& s); void setSignature(const std::vector<unsigned char>& s);
uint256 getSigningHash() const; uint256 getSigningHash() const;
// middle transaction functions // middle transaction functions
uint32 getVersion() const; uint32 getVersion() const;
void setVersion(uint32); void setVersion(uint32);
@@ -55,14 +54,15 @@ public:
std::vector<unsigned char> getSigningPubKey() const; std::vector<unsigned char> getSigningPubKey() const;
const std::vector<unsigned char>& peekSigningPubKey() const; const std::vector<unsigned char>& peekSigningPubKey() const;
std::vector<unsigned char>& peekSigningPubKey(); std::vector<unsigned char>& peekSigningPubKey();
const NewcoinAddress& setSigningPubKey(const std::vector<unsigned char>& s); const NewcoinAddress& setSigningPubKey(const NewcoinAddress& naSignPubKey);
const NewcoinAddress& setSourceAccount(const NewcoinAddress& naSource);
std::string getTransactionType() const { return mFormat->t_name; } std::string getTransactionType() const { return mFormat->t_name; }
// inner transaction functions // inner transaction functions
uint32 getFlags() const { return mInnerTxn.getFlags(); } uint32 getFlags() const { return mInnerTxn.getFlags(); }
void setFlag(uint32 v) { mInnerTxn.setFlag(v); } void setFlag(uint32 v) { mInnerTxn.setFlag(v); }
void clearFlag(uint32 v) { mInnerTxn.clearFlag(v); } void clearFlag(uint32 v) { mInnerTxn.clearFlag(v); }
uint32 getSequence() const; uint32 getSequence() const;
void setSequence(uint32); void setSequence(uint32);
@@ -116,3 +116,4 @@ public:
}; };
#endif #endif
// vim:ts=4

View File

@@ -5,6 +5,7 @@
#include "SerializedObject.h" #include "SerializedObject.h"
#include "TransactionFormats.h" #include "TransactionFormats.h"
#include "NewcoinAddress.h" #include "NewcoinAddress.h"
#include "utils.h"
std::string SerializedType::getFullText() const std::string SerializedType::getFullText() const
{ {
@@ -133,18 +134,14 @@ bool STHash256::isEquivalent(const SerializedType& t) const
return v && (value == v->value); return v && (value == v->value);
} }
static std::string hex(const std::vector<unsigned char>& value) STVariableLength::STVariableLength(SerializerIterator& st, const char *name) : SerializedType(name)
{ {
int dlen=value.size(), i=0; value = st.getVL();
char psz[dlen*2 + 1];
for(std::vector<unsigned char>::const_iterator it=value.begin(), end=value.end(); it!=end; ++it)
sprintf(psz + 2*(i++), "%02X", *it);
return std::string(psz, psz + value.size()*2);
} }
std::string STVariableLength::getText() const std::string STVariableLength::getText() const
{ {
return hex(value); return strHex(value);
} }
STVariableLength* STVariableLength::construct(SerializerIterator& u, const char *name) STVariableLength* STVariableLength::construct(SerializerIterator& u, const char *name)
@@ -225,7 +222,7 @@ std::string STTaggedList::getText() const
{ {
ret += boost::lexical_cast<std::string>(it->first); ret += boost::lexical_cast<std::string>(it->first);
ret += ","; ret += ",";
ret += hex(it->second); ret += strHex(it->second);
} }
return ret; return ret;
} }

View File

@@ -66,7 +66,7 @@ public:
STUInt8(unsigned char v=0) : value(v) { ; } STUInt8(unsigned char v=0) : value(v) { ; }
STUInt8(const char *n, unsigned char v=0) : SerializedType(n), value(v) { ; } STUInt8(const char *n, unsigned char v=0) : SerializedType(n), value(v) { ; }
static STUInt8* construct(SerializerIterator&, const char *name=NULL); static STUInt8* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 1; } int getLength() const { return 1; }
SerializedTypeID getSType() const { return STI_UINT8; } SerializedTypeID getSType() const { return STI_UINT8; }
@@ -91,7 +91,7 @@ public:
STUInt16(uint16 v=0) : value(v) { ; } STUInt16(uint16 v=0) : value(v) { ; }
STUInt16(const char *n, uint16 v=0) : SerializedType(n), value(v) { ; } STUInt16(const char *n, uint16 v=0) : SerializedType(n), value(v) { ; }
static STUInt16* construct(SerializerIterator&, const char *name=NULL); static STUInt16* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 2; } int getLength() const { return 2; }
SerializedTypeID getSType() const { return STI_UINT16; } SerializedTypeID getSType() const { return STI_UINT16; }
@@ -116,7 +116,7 @@ public:
STUInt32(uint32 v=0) : value(v) { ; } STUInt32(uint32 v=0) : value(v) { ; }
STUInt32(const char *n, uint32 v=0) : SerializedType(n), value(v) { ; } STUInt32(const char *n, uint32 v=0) : SerializedType(n), value(v) { ; }
static STUInt32* construct(SerializerIterator&, const char *name=NULL); static STUInt32* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 4; } int getLength() const { return 4; }
SerializedTypeID getSType() const { return STI_UINT32; } SerializedTypeID getSType() const { return STI_UINT32; }
@@ -141,7 +141,7 @@ public:
STUInt64(uint64 v=0) : value(v) { ; } STUInt64(uint64 v=0) : value(v) { ; }
STUInt64(const char *n, uint64 v=0) : SerializedType(n), value(v) { ; } STUInt64(const char *n, uint64 v=0) : SerializedType(n), value(v) { ; }
static STUInt64* construct(SerializerIterator&, const char *name=NULL); static STUInt64* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 8; } int getLength() const { return 8; }
SerializedTypeID getSType() const { return STI_UINT64; } SerializedTypeID getSType() const { return STI_UINT64; }
@@ -247,10 +247,11 @@ protected:
public: public:
STHash128(const uint128& v=uint128()) : value(v) { ; } STHash128(const uint128& v) : value(v) { ; }
STHash128(const char *n, const uint128& v=uint128()) : SerializedType(n), value(v) { ; } STHash128(const char *n, const uint128& v) : SerializedType(n), value(v) { ; }
STHash128(const char *n) : SerializedType(n) { ; }
STHash128() { ; } STHash128() { ; }
static STHash128* construct(SerializerIterator&, const char *name=NULL); static STHash128* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 20; } int getLength() const { return 20; }
SerializedTypeID getSType() const { return STI_HASH128; } SerializedTypeID getSType() const { return STI_HASH128; }
@@ -273,10 +274,11 @@ protected:
public: public:
STHash160(const uint160& v=uint160()) : value(v) { ; } STHash160(const uint160& v) : value(v) { ; }
STHash160(const char *n, const uint160& v=uint160()) : SerializedType(n), value(v) { ; } STHash160(const char *n, const uint160& v) : SerializedType(n), value(v) { ; }
STHash160(const char *n) : SerializedType(n) { ; }
STHash160() { ; } STHash160() { ; }
static STHash160* construct(SerializerIterator&, const char *name=NULL); static STHash160* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 20; } int getLength() const { return 20; }
SerializedTypeID getSType() const { return STI_HASH160; } SerializedTypeID getSType() const { return STI_HASH160; }
@@ -300,9 +302,10 @@ protected:
public: public:
STHash256(const uint256& v) : value(v) { ; } STHash256(const uint256& v) : value(v) { ; }
STHash256(const char *n, const uint256& v=uint256()) : SerializedType(n), value(v) { ; } STHash256(const char *n, const uint256& v) : SerializedType(n), value(v) { ; }
STHash256(const char *n) : SerializedType(n) { ; }
STHash256() { ; } STHash256() { ; }
static STHash256* construct(SerializerIterator&, const char *name=NULL); static STHash256* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 32; } int getLength() const { return 32; }
SerializedTypeID getSType() const { return STI_HASH256; } SerializedTypeID getSType() const { return STI_HASH256; }
@@ -328,8 +331,9 @@ public:
STVariableLength(const std::vector<unsigned char>& v) : value(v) { ; } STVariableLength(const std::vector<unsigned char>& v) : value(v) { ; }
STVariableLength(const char *n, const std::vector<unsigned char>& v) : SerializedType(n), value(v) { ; } STVariableLength(const char *n, const std::vector<unsigned char>& v) : SerializedType(n), value(v) { ; }
STVariableLength(const char *n) : SerializedType(n) { ; } STVariableLength(const char *n) : SerializedType(n) { ; }
STVariableLength(SerializerIterator&, const char *name = NULL);
STVariableLength() { ; } STVariableLength() { ; }
static STVariableLength* construct(SerializerIterator&, const char *name=NULL); static STVariableLength* construct(SerializerIterator&, const char *name = NULL);
int getLength() const; int getLength() const;
virtual SerializedTypeID getSType() const { return STI_VL; } virtual SerializedTypeID getSType() const { return STI_VL; }
@@ -380,7 +384,7 @@ public:
STTaggedList(const char *n) : SerializedType(n) { ; } STTaggedList(const char *n) : SerializedType(n) { ; }
STTaggedList(const std::vector<TaggedListItem>& v) : value(v) { ; } STTaggedList(const std::vector<TaggedListItem>& v) : value(v) { ; }
STTaggedList(const char *n, const std::vector<TaggedListItem>& v) : SerializedType(n), value(v) { ; } STTaggedList(const char *n, const std::vector<TaggedListItem>& v) : SerializedType(n), value(v) { ; }
static STTaggedList* construct(SerializerIterator&, const char *name=NULL); static STTaggedList* construct(SerializerIterator&, const char *name = NULL);
int getLength() const; int getLength() const;
SerializedTypeID getSType() const { return STI_TL; } SerializedTypeID getSType() const { return STI_TL; }
@@ -406,3 +410,4 @@ public:
}; };
#endif #endif
// vim:ts=4

View File

@@ -0,0 +1,93 @@
#include "SerializedValidation.h"
SOElement SerializedValidation::sValidationFormat[] = {
{ sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 },
{ sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 0 },
{ sfSigningKey, "SigningKey", STI_VL, SOE_REQUIRED, 0 },
{ sfExtensions, "Extensions", STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 },
};
const uint32 SerializedValidation::sFullFlag = 0x00010000;
const uint32 SerializedValidation::sValidationMagic = 0x4c575200; // "LGR"
SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSignature)
: STObject(sValidationFormat, sit), mSignature(sit, "Signature")
{
if (!isValid()) throw std::runtime_error("Invalid validation");
}
SerializedValidation::SerializedValidation(const uint256& ledgerHash, CKey::pointer nodeKey, bool isFull)
: STObject(sValidationFormat), mSignature("Signature")
{
setValueFieldH256(sfLedgerHash, ledgerHash);
setValueFieldVL(sfSigningKey, nodeKey->GetPubKey());
if (!isFull) setFlag(sFullFlag);
if (!nodeKey->Sign(getSigningHash(), mSignature.peekValue()))
throw std::runtime_error("Unable to sign validation");
}
uint256 SerializedValidation::getSigningHash() const
{
Serializer s;
s.add32(sValidationMagic);
add(s);
return s.getSHA512Half();
}
uint256 SerializedValidation::getLedgerHash() const
{
return getValueFieldH256(sfLedgerHash);
}
bool SerializedValidation::isValid() const
{
try
{
CKey pubKey;
return pubKey.SetPubKey(getValueFieldVL(sfSigningKey)) &&
pubKey.Verify(getSigningHash(), mSignature.peekValue());
}
catch (...)
{
return false;
}
}
NewcoinAddress SerializedValidation::getSignerPublic() const
{
NewcoinAddress a;
a.setNodePublic(getValueFieldVL(sfSigningKey));
return a;
}
bool SerializedValidation::isFull() const
{
return (getFlags() & sFullFlag) != 0;
}
void SerializedValidation::addSigned(Serializer& s) const
{
add(s);
mSignature.add(s);
}
void SerializedValidation::addSignature(Serializer& s) const
{
mSignature.add(s);
}
std::vector<unsigned char> SerializedValidation::getSigned() const
{
Serializer s;
addSigned(s);
return s.peekData();
}
std::vector<unsigned char> SerializedValidation::getSignature() const
{
return mSignature.peekValue();
}
// vim:ts=4

View File

@@ -0,0 +1,38 @@
#ifndef __VALIDATION__
#define __VALIDATION__
#include "SerializedObject.h"
class SerializedValidation : public STObject
{
protected:
STVariableLength mSignature;
public:
typedef boost::shared_ptr<SerializedValidation> pointer;
static SOElement sValidationFormat[16];
static const uint32 sFullFlag;
static const uint32 sValidationMagic;
// These throw if the object is not valid
SerializedValidation(SerializerIterator& sit, bool checkSignature = true);
SerializedValidation(const Serializer& s, bool checkSignature = true);
SerializedValidation(const uint256& ledgerHash, CKey::pointer nodeKey, bool isFull);
uint256 getLedgerHash() const;
NewcoinAddress getSignerPublic() const;
bool isValid() const;
bool isFull() const;
CKey::pointer getSigningKey() const;
uint256 getSigningHash() const;
void addSigned(Serializer&) const;
void addSignature(Serializer&) const;
std::vector<unsigned char> getSigned() const;
std::vector<unsigned char> getSignature() const;
};
#endif
// vim:ts=4

View File

@@ -81,28 +81,31 @@ int Serializer::addRaw(const void *ptr, int len)
bool Serializer::get16(uint16& o, int offset) const bool Serializer::get16(uint16& o, int offset) const
{ {
if ((offset + 2) > mData.size()) return false; if ((offset + 2) > mData.size()) return false;
o = mData.at(offset++); const unsigned char *ptr = &mData[offset];
o <<= 8; o |= mData.at(offset); o = *ptr++; o <<= 8; o |= *ptr;
return true; return true;
} }
bool Serializer::get32(uint32& o, int offset) const bool Serializer::get32(uint32& o, int offset) const
{ {
if ((offset + 4) > mData.size()) return false; if ((offset + 4) > mData.size()) return false;
o=mData.at(offset++); const unsigned char *ptr = &mData[offset];
o<<=8; o |= mData.at(offset++); o <<= 8; o |= mData.at(offset++); o = *ptr++;
o<<=8; o |= mData.at(offset); o <<= 8; o |= *ptr++;
o <<= 8; o |= *ptr++;
o <<= 8; o |= *ptr;
return true; return true;
} }
bool Serializer::get64(uint64& o, int offset) const bool Serializer::get64(uint64& o, int offset) const
{ {
if ((offset + 8) > mData.size()) return false; if ((offset + 8) > mData.size()) return false;
o=mData.at(offset++); const unsigned char *ptr = &mData[offset];
o<<=8; o|= mData.at(offset++); o <<= 8; o |= mData.at(offset++); o = *ptr++;
o<<=8; o|= mData.at(offset++); o <<= 8; o |= mData.at(offset++); o <<= 8; o |= *ptr++; o <<= 8; o |= *ptr++;
o<<=8; o|= mData.at(offset++); o <<= 8; o |= mData.at(offset++); o <<= 8; o |= *ptr++; o <<= 8; o |= *ptr++;
o<<=8; o|= mData.at(offset); o <<= 8; o |= *ptr++; o <<= 8; o |= *ptr++;
o <<= 8; o |= *ptr;
return true; return true;
} }
@@ -172,7 +175,7 @@ int Serializer::removeLastByte()
bool Serializer::getRaw(std::vector<unsigned char>& o, int offset, int length) const bool Serializer::getRaw(std::vector<unsigned char>& o, int offset, int length) const
{ {
if ((offset + length) > mData.size()) return false; if ((offset + length) > mData.size()) return false;
o.assign(mData.begin() + offset, mData.begin() + offset+length); o.assign(mData.begin() + offset, mData.begin() + offset + length);
return true; return true;
} }
@@ -233,12 +236,12 @@ bool Serializer::checkSignature(int pubkeyOffset, int signatureOffset) const
CKey pubCKey; CKey pubCKey;
if (!pubCKey.SetPubKey(pubkey)) return false; if (!pubCKey.SetPubKey(pubkey)) return false;
return pubCKey.Verify(getSHA512Half(signatureOffset), signature); return pubCKey.Verify(getSHA512Half(signatureOffset), signature);
} }
bool Serializer::checkSignature(const std::vector<unsigned char> &signature, CKey& key) const bool Serializer::checkSignature(const std::vector<unsigned char> &signature, CKey& key) const
{ {
return key.Verify(getSHA512Half(), signature); return key.Verify(getSHA512Half(), signature);
} }
bool Serializer::makeSignature(std::vector<unsigned char> &signature, CKey& key) const bool Serializer::makeSignature(std::vector<unsigned char> &signature, CKey& key) const
@@ -259,7 +262,7 @@ int Serializer::addVL(const std::vector<unsigned char>& vector)
{ {
int ret = addRaw(encodeVL(vector.size())); int ret = addRaw(encodeVL(vector.size()));
addRaw(vector); addRaw(vector);
assert(mData.size() + (ret + vector.size() + encodeLengthLength(vector.size()))); assert(mData.size() == (ret + vector.size() + encodeLengthLength(vector.size())));
return ret; return ret;
} }
@@ -362,12 +365,12 @@ bool Serializer::getVLLength(int& length, int offset) const
try try
{ {
if (lenLen == 1) if (lenLen == 1)
length=decodeVLLength(b1); length = decodeVLLength(b1);
else if (lenLen == 2) else if (lenLen == 2)
{ {
int b2; int b2;
if (!get8(b2, offset++)) return false; if (!get8(b2, offset++)) return false;
length=decodeVLLength(b1, b2); length = decodeVLLength(b1, b2);
} }
else if (lenLen == 3) else if (lenLen == 3)
{ {
@@ -391,7 +394,7 @@ bool Serializer::getTaggedList(std::list<TaggedListItem>& list, int offset, int&
int startOffset = offset; int startOffset = offset;
int numElem; int numElem;
if (!get8(numElem, offset++)) return false; if (!get8(numElem, offset++)) return false;
for (int i = 0; i<numElem; i++) for (int i = 0; i<numElem; ++i)
{ {
int tag, len; int tag, len;
std::vector<unsigned char> data; std::vector<unsigned char> data;
@@ -407,10 +410,10 @@ bool Serializer::getTaggedList(std::list<TaggedListItem>& list, int offset, int&
bool Serializer::getTaggedList(std::vector<TaggedListItem>& list, int offset, int& length) const bool Serializer::getTaggedList(std::vector<TaggedListItem>& list, int offset, int& length) const
{ {
list.clear(); list.clear();
int startOffset=offset; int startOffset = offset;
int numElem; int numElem;
if (!get8(numElem, offset++)) return false; if (!get8(numElem, offset++)) return false;
for (int i=0; i<numElem; i++) for (int i = 0; i<numElem; ++i)
{ {
int tag, len; int tag, len;
std::vector<unsigned char> data; std::vector<unsigned char> data;
@@ -502,7 +505,7 @@ unsigned char SerializerIterator::get8()
{ {
int val; int val;
if (!mSerializer.get8(val, mPos)) throw std::runtime_error("invalid serializer get8"); if (!mSerializer.get8(val, mPos)) throw std::runtime_error("invalid serializer get8");
mPos++; ++mPos;
return val; return val;
} }
@@ -510,7 +513,7 @@ uint16 SerializerIterator::get16()
{ {
uint16 val; uint16 val;
if (!mSerializer.get16(val, mPos)) throw std::runtime_error("invalid serializer get16"); if (!mSerializer.get16(val, mPos)) throw std::runtime_error("invalid serializer get16");
mPos += 16/8; mPos += 16 / 8;
return val; return val;
} }
@@ -518,7 +521,7 @@ uint32 SerializerIterator::get32()
{ {
uint32 val; uint32 val;
if (!mSerializer.get32(val, mPos)) throw std::runtime_error("invalid serializer get32"); if (!mSerializer.get32(val, mPos)) throw std::runtime_error("invalid serializer get32");
mPos += 32/8; mPos += 32 / 8;
return val; return val;
} }
@@ -526,7 +529,7 @@ uint64 SerializerIterator::get64()
{ {
uint64 val; uint64 val;
if (!mSerializer.get64(val, mPos)) throw std::runtime_error("invalid serializer get64"); if (!mSerializer.get64(val, mPos)) throw std::runtime_error("invalid serializer get64");
mPos += 64/8; mPos += 64 / 8;
return val; return val;
} }
@@ -534,7 +537,7 @@ uint128 SerializerIterator::get128()
{ {
uint128 val; uint128 val;
if (!mSerializer.get128(val, mPos)) throw std::runtime_error("invalid serializer get128"); if (!mSerializer.get128(val, mPos)) throw std::runtime_error("invalid serializer get128");
mPos += 128/8; mPos += 128 / 8;
return val; return val;
} }
@@ -542,7 +545,7 @@ uint160 SerializerIterator::get160()
{ {
uint160 val; uint160 val;
if (!mSerializer.get160(val, mPos)) throw std::runtime_error("invalid serializer get160"); if (!mSerializer.get160(val, mPos)) throw std::runtime_error("invalid serializer get160");
mPos += 160/8; mPos += 160 / 8;
return val; return val;
} }
@@ -550,7 +553,7 @@ uint256 SerializerIterator::get256()
{ {
uint256 val; uint256 val;
if (!mSerializer.get256(val, mPos)) throw std::runtime_error("invalid serializer get256"); if (!mSerializer.get256(val, mPos)) throw std::runtime_error("invalid serializer get256");
mPos += 256/8; mPos += 256 / 8;
return val; return val;
} }
@@ -571,3 +574,4 @@ std::vector<TaggedListItem> SerializerIterator::getTaggedList()
mPos += length; mPos += length;
return tl; return tl;
} }
// vim:ts=4

View File

@@ -1,57 +0,0 @@
#include "TimingService.h"
#include "Config.h"
#include "Application.h"
#include <iostream>
#include <ctime>
#include <boost/bind.hpp>
using namespace std;
using namespace boost;
/*
Only needs to start once we determine the network time
*/
TimingService::TimingService() : mLedgerTimer(NULL), mPropTimer(NULL), mValidTimer(NULL)
{
}
void TimingService::start(boost::asio::io_service& ioService)
{
// TODO: calculate the amount of seconds left in the current ledger
mLedgerTimer=new asio::deadline_timer(ioService, posix_time::seconds(theConfig.LEDGER_SECONDS)),
mLedgerTimer->async_wait(boost::bind(&TimingService::handleLedger, this));
mPropTimer=new asio::deadline_timer(ioService, posix_time::seconds(theConfig.LEDGER_PROPOSAL_DELAY_SECONDS));
}
void TimingService::handleLedger()
{
cout << "publish ledger" << endl;
#if 0
theApp->getLedgerMaster().startFinalization();
mLedgerTimer->expires_at(mLedgerTimer->expires_at() + boost::posix_time::seconds(theConfig.LEDGER_SECONDS));
mLedgerTimer->async_wait(boost::bind(&TimingService::handleLedger, this));
mPropTimer->expires_at(mLedgerTimer->expires_at() + boost::posix_time::seconds(theConfig.LEDGER_PROPOSAL_DELAY_SECONDS));
mPropTimer->async_wait(boost::bind(&TimingService::handleProp, this));
#endif
}
void TimingService::handleProp()
{
// theApp->getLedgerMaster().sendProposal();
}
void TimingService::handleValid()
{
// theApp->getLedgerMaster().endFinalization();
}
int TimingService::getCurrentLedgerIndex()
{
return( (time(NULL)-theConfig.NETWORK_START_TIME)/theConfig.LEDGER_SECONDS );
}

View File

@@ -1,26 +0,0 @@
#ifndef __TIMINGSERVICE__
#define __TIMINGSERVICE__
#include <boost/asio.hpp>
/* responsible for keeping track of network time
and kicking off the publishing process
*/
class TimingService
{
boost::asio::deadline_timer* mLedgerTimer;
boost::asio::deadline_timer* mPropTimer;
boost::asio::deadline_timer* mValidTimer;
void handleLedger();
void handleProp();
void handleValid();
public:
TimingService();
void start(boost::asio::io_service& ioService);
static int getCurrentLedgerIndex();
};
#endif

View File

@@ -23,7 +23,14 @@ Transaction::Transaction(LocalAccount::pointer fromLocalAccount, const NewcoinAd
mFromPubKey = fromLocalAccount->getPublicKey(); mFromPubKey = fromLocalAccount->getPublicKey();
assert(mFromPubKey); assert(mFromPubKey);
mTransaction->setSigningPubKey(mFromPubKey->GetPubKey());
// XXX Temporary: We don't really have local accounts.
NewcoinAddress signPubKey;
signPubKey.setAccountPublic(mFromPubKey->GetPubKey());
mTransaction->setSigningPubKey(signPubKey);
mTransaction->setSourceAccount(mAccountFrom);
mTransaction->setSequence(accountState->getSeq()); mTransaction->setSequence(accountState->getSeq());
assert(mTransaction->getSequence() != 0); assert(mTransaction->getSequence() != 0);
@@ -105,6 +112,7 @@ Transaction::Transaction(const std::vector<unsigned char>& raw, bool validate) :
mStatus = NEW; mStatus = NEW;
} }
#if 0
Transaction::Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toID, Transaction::Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toID,
CKey::pointer pubKey, uint64 amount, uint64 fee, uint32 fromSeq, uint32 fromLedger, CKey::pointer pubKey, uint64 amount, uint64 fee, uint32 fromSeq, uint32 fromLedger,
uint32 ident, const std::vector<unsigned char>& signature, uint32 ledgerSeq, TransStatus st) : uint32 ident, const std::vector<unsigned char>& signature, uint32 ledgerSeq, TransStatus st) :
@@ -113,7 +121,8 @@ Transaction::Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toI
mTransaction = boost::make_shared<SerializedTransaction>(ttMAKE_PAYMENT); mTransaction = boost::make_shared<SerializedTransaction>(ttMAKE_PAYMENT);
mTransaction->setSignature(signature); mTransaction->setSignature(signature);
mTransaction->setTransactionFee(fee); mTransaction->setTransactionFee(fee);
mTransaction->setSigningPubKey(pubKey->GetPubKey()); mTransaction->setSigningPubKey(pubKey); // BROKEN
mTransaction->setSourceAccount(mAccountFrom); // BROKEN
mTransaction->setSequence(fromSeq); mTransaction->setSequence(fromSeq);
if (fromLedger != 0) if (fromLedger != 0)
{ {
@@ -129,6 +138,7 @@ Transaction::Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toI
mTransaction->setITFieldAccount(sfDestination, toID.getAccountID()); mTransaction->setITFieldAccount(sfDestination, toID.getAccountID());
updateID(); updateID();
} }
#endif
bool Transaction::sign(LocalAccount::pointer fromLocalAccount) bool Transaction::sign(LocalAccount::pointer fromLocalAccount)
{ {
@@ -225,10 +235,10 @@ bool Transaction::save() const
theApp->getTxnDB()->getDB()->escape(static_cast<const unsigned char *>(s.getDataPtr()), s.getLength(), rawTxn); theApp->getTxnDB()->getDB()->escape(static_cast<const unsigned char *>(s.getDataPtr()), s.getLength(), rawTxn);
sql.append(rawTxn); sql.append(rawTxn);
sql.append(");"); sql.append(");");
ScopedLock sl(theApp->getTxnDB()->getDBLock()); ScopedLock sl(theApp->getTxnDB()->getDBLock());
Database* db = theApp->getTxnDB()->getDB(); Database* db = theApp->getTxnDB()->getDB();
return db->executeSQL(sql.c_str()); return db->executeSQL(sql);
} }
Transaction::pointer Transaction::transactionFromSQL(const std::string& sql) Transaction::pointer Transaction::transactionFromSQL(const std::string& sql)
@@ -237,12 +247,11 @@ Transaction::pointer Transaction::transactionFromSQL(const std::string& sql)
std::string status; std::string status;
rawTxn.reserve(2048); rawTxn.reserve(2048);
if(1)
{ {
ScopedLock sl(theApp->getTxnDB()->getDBLock()); ScopedLock sl(theApp->getTxnDB()->getDBLock());
Database* db = theApp->getTxnDB()->getDB(); Database* db = theApp->getTxnDB()->getDB();
if (!db->executeSQL(sql.c_str(), true) || !db->startIterRows() || !db->getNextRow()) if (!db->executeSQL(sql, true) || !db->startIterRows())
return Transaction::pointer(); return Transaction::pointer();
db->getStr("Status", status); db->getStr("Status", status);
@@ -258,7 +267,7 @@ Transaction::pointer Transaction::transactionFromSQL(const std::string& sql)
Transaction::pointer tr = boost::make_shared<Transaction>(txn, true); Transaction::pointer tr = boost::make_shared<Transaction>(txn, true);
TransStatus st(INVALID); TransStatus st(INVALID);
switch(status[0]) switch (status[0])
{ {
case 'N': st = NEW; break; case 'N': st = NEW; break;
case 'A': st = INCLUDED; break; case 'A': st = INCLUDED; break;
@@ -340,7 +349,7 @@ static bool isHex(char j)
if ((j >= 'a') && (j <= 'f')) return true; if ((j >= 'a') && (j <= 'f')) return true;
return false; return false;
} }
bool Transaction::isHexTxID(const std::string& txid) bool Transaction::isHexTxID(const std::string& txid)
{ {
if (txid.size() != 64) return false; if (txid.size() != 64) return false;
@@ -382,3 +391,4 @@ Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const
return ret; return ret;
} }
// vim:ts=4

View File

@@ -6,21 +6,63 @@
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn, TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
TransactionEngineParams params) TransactionEngineParams params)
{ {
TransactionEngineResult result = terSUCCESS;
uint256 txID = txn.getTransactionID(); uint256 txID = txn.getTransactionID();
if(!txID) return terINVALID; if(!txID) return terINVALID;
// extract signing key // Extract signing key
// Transactions contain a signing key. This allows us to trivially verify a transaction has at least been properly signed
// without going to disk. Each transaction also notes a source account id. This is used to verify that the signing key is
// associated with the account.
CKey acctKey; CKey acctKey;
if (!acctKey.SetPubKey(txn.peekSigningPubKey())) return terINVALID; if (!acctKey.SetPubKey(txn.peekSigningPubKey())) return terINVALID;
// check signature // check signature
if (!txn.checkSign(acctKey)) return terINVALID; if (!txn.checkSign(acctKey)) return terINVALID;
bool bPrepaid = false;
// Customize behavoir based on transaction type.
switch(txn.getTxnType())
{
case ttCLAIM:
bPrepaid = true;
break;
case ttMAKE_PAYMENT:
case ttINVOICE:
case ttEXCHANGE_OFFER:
result = terSUCCESS;
break;
case ttINVALID:
result = terINVALID;
break;
default:
result = terUNKNOWN;
break;
}
if (terSUCCESS != result)
return result;
uint64 txnFee = txn.getTransactionFee(); uint64 txnFee = txn.getTransactionFee();
if ( (params & tepNO_CHECK_FEE) != tepNONE) if ( (params & tepNO_CHECK_FEE) != tepNONE)
{ {
// WRITEME: Check if fee is adequate if (bPrepaid)
if (txnFee == 0) return terINSUF_FEE_P; {
if (txnFee)
// Transaction is malformed.
return terINSUF_FEE_P;
}
else
{
// WRITEME: Check if fee is adequate
if (txnFee == 0)
return terINSUF_FEE_P;
}
} }
// get source account ID // get source account ID
@@ -30,39 +72,59 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
boost::recursive_mutex::scoped_lock sl(mLedger->mLock); boost::recursive_mutex::scoped_lock sl(mLedger->mLock);
// find source account // find source account
// If we are only verifying some transactions, this would be probablistic.
LedgerStateParms qry = lepNONE; LedgerStateParms qry = lepNONE;
SerializedLedgerEntry::pointer src = mLedger->getAccountRoot(qry, srcAccount); SerializedLedgerEntry::pointer src = mLedger->getAccountRoot(qry, srcAccount);
if (!src) return terNO_ACCOUNT; if (!src) return terNO_ACCOUNT;
// deduct the fee, so it's not available during the transaction // deduct the fee, so it's not available during the transaction
// we only write the account back if the transaction succeeds // we only write the account back if the transaction succeeds
uint64 balance = src->getIFieldU64(sfBalance); if (txnFee)
if (balance < txnFee)
return terINSUF_FEE_B;
src->setIFieldU64(sfBalance, balance - txnFee);
// validate sequence
uint32 t_seq = txn.getSequence();
uint32 a_seq = src->getIFieldU32(sfSequence);
if (t_seq != a_seq)
{ {
// WRITEME: Special case code for changing transaction key uint64 balance = src->getIFieldU64(sfBalance);
if (a_seq < t_seq) return terPRE_SEQ;
if (mLedger->hasTransaction(txID)) if (balance < txnFee)
return terALREADY; return terINSUF_FEE_B;
return terPAST_SEQ;
src->setIFieldU64(sfBalance, balance - txnFee);
}
// Validate sequence
uint32 t_seq = txn.getSequence();
if (bPrepaid)
{
if (t_seq)
return terPAST_SEQ;
}
else
{
uint32 a_seq = src->getIFieldU32(sfSequence);
if (t_seq != a_seq)
{
// WRITEME: Special case code for changing transaction key
if (a_seq < t_seq) return terPRE_SEQ;
if (mLedger->hasTransaction(txID))
return terALREADY;
return terPAST_SEQ;
}
else src->setIFieldU32(sfSequence, t_seq);
} }
else src->setIFieldU32(sfSequence, t_seq);
std::vector<AffectedAccount> accounts; std::vector<AffectedAccount> accounts;
accounts.push_back(std::make_pair(taaMODIFY, src)); accounts.push_back(std::make_pair(taaMODIFY, src));
TransactionEngineResult result = terUNKNOWN;
switch(txn.getTxnType()) switch(txn.getTxnType())
{ {
case ttINVALID: case ttINVALID:
result = terINVALID; result = terINVALID;
break; break;
case ttCLAIM:
result = doClaim(txn, accounts);
break;
case ttMAKE_PAYMENT: case ttMAKE_PAYMENT:
result = doPayment(txn, accounts); result = doPayment(txn, accounts);
break; break;
@@ -85,8 +147,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
// WRITEME: Special case code for changing transaction key // WRITEME: Special case code for changing transaction key
for(std::vector<AffectedAccount>::iterator it=accounts.begin(), end=accounts.end(); for(std::vector<AffectedAccount>::iterator it=accounts.begin(), end=accounts.end();
it != end; ++it) it != end; ++it)
{ { if (it->first == taaCREATE)
if ( (it->first==taaMODIFY) || (it->first==taaCREATE) ) {
if (mLedger->writeBack(lepCREATE, it->second) & lepERROR)
assert(false);
}
else if (it->first==taaMODIFY)
{ {
if(mLedger->writeBack(lepNONE, it->second) & lepERROR) if(mLedger->writeBack(lepNONE, it->second) & lepERROR)
assert(false); assert(false);
@@ -106,6 +172,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
return result; return result;
} }
TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
return terUNKNOWN;
}
TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn, TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts) std::vector<AffectedAccount>& accounts)
{ {
@@ -187,3 +259,4 @@ TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction&
{ {
return terUNKNOWN; return terUNKNOWN;
} }
// vim:ts=4

View File

@@ -25,6 +25,7 @@ enum TransactionEngineResult
terUNFUNDED, // Source account had insufficient balance for transactin terUNFUNDED, // Source account had insufficient balance for transactin
terNO_PATH, // No path existed or met transaction/balance requirements terNO_PATH, // No path existed or met transaction/balance requirements
terPAST_SEQ, // This sequence number has already past terPAST_SEQ, // This sequence number has already past
terBAD_SEQ, // This sequence number should be zero for prepaid transactions.
terPRE_SEQ, // Missing/inapplicable prior transaction terPRE_SEQ, // Missing/inapplicable prior transaction
terPAST_LEDGER, // The transaction expired and can't be applied terPAST_LEDGER, // The transaction expired and can't be applied
}; };
@@ -51,13 +52,14 @@ class TransactionEngine
protected: protected:
Ledger::pointer mLedger; Ledger::pointer mLedger;
TransactionEngineResult doPayment(const SerializedTransaction&, std::vector<AffectedAccount>&); TransactionEngineResult doCancel(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doClaim(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doDelete(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doInvoice(const SerializedTransaction&, std::vector<AffectedAccount>&); TransactionEngineResult doInvoice(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doOffer(const SerializedTransaction&, std::vector<AffectedAccount>&); TransactionEngineResult doOffer(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doTake(const SerializedTransaction&, std::vector<AffectedAccount>&); TransactionEngineResult doPayment(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doCancel(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doStore(const SerializedTransaction&, std::vector<AffectedAccount>&); TransactionEngineResult doStore(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doDelete(const SerializedTransaction&, std::vector<AffectedAccount>&); TransactionEngineResult doTake(const SerializedTransaction&, std::vector<AffectedAccount>&);
public: public:
TransactionEngine() { ; } TransactionEngine() { ; }
@@ -80,3 +82,4 @@ inline TransactionEngineParams operator&(const TransactionEngineParams& l1, cons
} }
#endif #endif
// vim:ts=4

View File

@@ -13,7 +13,14 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 },
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 4 },
{ S_FIELD(InvoiceID), STI_HASH256, SOE_IFFLAG, 8 }, { S_FIELD(InvoiceID), STI_HASH256, SOE_IFFLAG, 8 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
{ "Claim", ttCLAIM, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(GeneratorID), STI_AMOUNT, SOE_REQUIRED, 0 },
{ S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
}, },
{ "Invoice", ttINVOICE, { { "Invoice", ttINVOICE, {
@@ -25,7 +32,7 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 4 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 4 },
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 8 }, { S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 8 },
{ S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 16 }, { S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 16 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
}, },
{ "Offer", ttEXCHANGE_OFFER, { { "Offer", ttEXCHANGE_OFFER, {
@@ -39,7 +46,7 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 32 }, { S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 32 },
{ S_FIELD(ExpireLedger), STI_UINT32, SOE_IFFLAG, 64 }, { S_FIELD(ExpireLedger), STI_UINT32, SOE_IFFLAG, 64 },
{ S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 128 }, { S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 128 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
}, },
{ NULL, ttINVALID } { NULL, ttINVALID }
@@ -55,3 +62,4 @@ TransactionFormat* getTxnFormat(TransactionType t)
} }
return NULL; return NULL;
} }
// vim:ts=4

View File

@@ -5,10 +5,11 @@
enum TransactionType enum TransactionType
{ {
ttINVALID=-1, ttINVALID = -1,
ttMAKE_PAYMENT=0, ttMAKE_PAYMENT = 0,
ttINVOICE=1, ttCLAIM = 1,
ttEXCHANGE_OFFER=2 ttINVOICE = 2,
ttEXCHANGE_OFFER = 3
}; };
struct TransactionFormat struct TransactionFormat
@@ -18,10 +19,14 @@ struct TransactionFormat
SOElement elements[16]; SOElement elements[16];
}; };
const int32 TransactionMagic=0x54584E00; const int32 TransactionMagic = 0x54584E00; // 'TXN'
const int TransactionIVersion=0, TransactionISigningPubKey=1, TransactionISequence=2; const int TransactionIVersion = 0;
const int TransactionIType=3, TransactionIFee=4; const int TransactionISigningPubKey = 1;
const int TransactionISourceID = 2;
const int TransactionISequence = 3;
const int TransactionIType = 4;
const int TransactionIFee = 5;
const int TransactionMinLen=32; const int TransactionMinLen=32;
const int TransactionMaxLen=1048576; const int TransactionMaxLen=1048576;
@@ -29,3 +34,4 @@ const int TransactionMaxLen=1048576;
extern TransactionFormat InnerTxnFormats[]; extern TransactionFormat InnerTxnFormats[];
extern TransactionFormat* getTxnFormat(TransactionType t); extern TransactionFormat* getTxnFormat(TransactionType t);
#endif #endif
// vim:ts=4

View File

@@ -38,3 +38,4 @@ bool TransactionMaster::canonicalize(Transaction::pointer& txn, bool may_be_new)
theApp->getIOService().post(boost::bind(&Transaction::saveTransaction, txn)); theApp->getIOService().post(boost::bind(&Transaction::saveTransaction, txn));
return false; return false;
} }
// vim:ts=4

View File

@@ -22,3 +22,4 @@ public:
}; };
#endif #endif
// vim:ts=4

View File

@@ -39,7 +39,7 @@ void ValidationCollection::addToDB(newcoin::Validation& valid,int weCare)
db->escape(hanko.begin(),hanko.GetSerializeSize(),hankoStr); db->escape(hanko.begin(),hanko.GetSerializeSize(),hankoStr);
db->escape(sig.begin(),sig.GetSerializeSize(),sigStr); db->escape(sig.begin(),sig.GetSerializeSize(),sigStr);
string sql=strprintf("INSERT INTO Validations (LedgerIndex,Hash,Hanko,SeqNum,Sig,WeCare) values (%d,%s,%s,%d,%s,%d)",valid.ledgerindex(),hashStr.c_str(),hankoStr.c_str(),valid.seqnum(),sigStr.c_str(),weCare); string sql=strprintf("INSERT INTO Validations (LedgerIndex,Hash,Hanko,SeqNum,Sig,WeCare) values (%d,%s,%s,%d,%s,%d)",valid.ledgerindex(),hashStr.c_str(),hankoStr.c_str(),valid.seqnum(),sigStr.c_str(),weCare);
db->executeSQL(sql.c_str()); db->executeSQL(sql);
} }
@@ -50,24 +50,18 @@ bool ValidationCollection::hasValidation(uint32 ledgerIndex,uint160& hanko,uint3
db->escape(hanko.begin(),hanko.GetSerializeSize(),hankoStr); db->escape(hanko.begin(),hanko.GetSerializeSize(),hankoStr);
string sql=strprintf("SELECT ValidationID,seqnum from Validations where LedgerIndex=%d and hanko=%s", string sql=strprintf("SELECT ValidationID,seqnum from Validations where LedgerIndex=%d and hanko=%s",
ledgerIndex,hankoStr.c_str()); ledgerIndex,hankoStr.c_str());
if(db->executeSQL(sql.c_str())) if(db->executeSQL(sql) && db->startIterRows())
{ {
if(db->startIterRows()) uint32 currentSeqNum=db->getInt(1);
if(currentSeqNum>=seqnum)
{ {
if(db->getNextRow()) db->endIterRows();
{ return(true);
uint32 currentSeqNum=db->getInt(1);
if(currentSeqNum>=seqnum)
{
db->endIterRows();
return(true);
}
// delete the old validation we were storing
sql=strprintf("DELETE FROM Validations where ValidationID=%d",db->getInt(0));
db->endIterRows();
db->executeSQL(sql.c_str());
}
} }
// delete the old validation we were storing
sql=strprintf("DELETE FROM Validations where ValidationID=%d",db->getInt(0));
db->endIterRows();
db->executeSQL(sql);
} }
return(false); return(false);
} }
@@ -191,7 +185,6 @@ void ValidationCollection::getValidations(uint32 ledgerIndex,vector<newcoin::Val
string sql=strprintf("SELECT * From Validations where LedgerIndex=%d and wecare=1",ledgerIndex); string sql=strprintf("SELECT * From Validations where LedgerIndex=%d and wecare=1",ledgerIndex);
// TODO: ValidationCollection::getValidations(uint32 ledgerIndex) // TODO: ValidationCollection::getValidations(uint32 ledgerIndex)
} }
@@ -203,7 +196,6 @@ bool ValidationCollection::getConsensusLedger(uint32 ledgerIndex, uint256& ourHa
bool ret=false; bool ret=false;
if(mIndexGroups.count(ledgerIndex)) if(mIndexGroups.count(ledgerIndex))
{ {
unsigned int maxVotes=theConfig.MIN_VOTES_FOR_CONSENSUS; unsigned int maxVotes=theConfig.MIN_VOTES_FOR_CONSENSUS;
vector< Group >& groups=mIndexGroups[ledgerIndex]; vector< Group >& groups=mIndexGroups[ledgerIndex];
Group empty; Group empty;
@@ -228,6 +220,7 @@ bool ValidationCollection::getConsensusLedger(uint32 ledgerIndex, uint256& ourHa
} }
} }
} }
return(ret); return(ret);
} }
// vim:ts=4

View File

@@ -28,8 +28,8 @@
LocalAccount::LocalAccount(boost::shared_ptr<LocalAccountFamily> family, int familySeq) : LocalAccount::LocalAccount(boost::shared_ptr<LocalAccountFamily> family, int familySeq) :
mPublicKey(family->getPublicKey(familySeq)), mFamily(family), mAccountFSeq(familySeq) mPublicKey(family->getPublicKey(familySeq)), mFamily(family), mAccountFSeq(familySeq)
{ {
mAcctID.setAccountPublic(mPublicKey->GetPubKey()); mAccount.setAccountPublic(mPublicKey->GetPubKey());
if(theApp!=NULL) mPublicKey = theApp->getPubKeyCache().store(mAcctID, mPublicKey); if (theApp != NULL) mPublicKey = theApp->getPubKeyCache().store(mAccount, mPublicKey);
} }
std::string LocalAccount::getFullName() const std::string LocalAccount::getFullName() const
@@ -52,7 +52,7 @@ std::string LocalAccount::getFamilyName() const
AccountState::pointer LocalAccount::getAccountState() const AccountState::pointer LocalAccount::getAccountState() const
{ {
return theApp->getOPs().getAccountState(mAcctID); return theApp->getOPs().getAccountState(mAccount);
} }
uint64 LocalAccount::getEffectiveBalance() const uint64 LocalAccount::getEffectiveBalance() const
@@ -73,12 +73,13 @@ Json::Value LocalAccount::getJson() const
ret["IsLocked"] = mFamily->isLocked(); ret["IsLocked"] = mFamily->isLocked();
AccountState::pointer as = getAccountState(); AccountState::pointer as = getAccountState();
if (!as) ret["Account"] = "None"; if (!as) ret["State"] = "None";
else else
{ {
assert(as->getAccountID().getAccountID() == mAccount.getAccountID());
Json::Value acct(Json::objectValue); Json::Value acct(Json::objectValue);
as->addJson(acct); as->addJson(acct);
ret["Account"] = acct; ret["State"] = acct;
} }
return ret; return ret;
@@ -190,7 +191,7 @@ LocalAccountFamily::pointer LocalAccountFamily::readFamily(const NewcoinAddress&
ScopedLock sl(theApp->getWalletDB()->getDBLock()); ScopedLock sl(theApp->getWalletDB()->getDBLock());
Database *db=theApp->getWalletDB()->getDB(); Database *db=theApp->getWalletDB()->getDB();
if(!db->executeSQL(sql.c_str()) || !db->startIterRows() || !db->getNextRow()) if(!db->executeSQL(sql) || !db->startIterRows())
return LocalAccountFamily::pointer(); return LocalAccountFamily::pointer();
db->getStr("Comment", comment); db->getStr("Comment", comment);
@@ -223,7 +224,7 @@ void LocalAccountFamily::write(bool is_new)
sql.append(");"); sql.append(");");
ScopedLock sl(theApp->getWalletDB()->getDBLock()); ScopedLock sl(theApp->getWalletDB()->getDBLock());
theApp->getWalletDB()->getDB()->executeSQL(sql.c_str()); theApp->getWalletDB()->getDB()->executeSQL(sql);
} }
std::string LocalAccountFamily::getSQLFields() std::string LocalAccountFamily::getSQLFields()
@@ -446,7 +447,7 @@ void Wallet::load()
ScopedLock sl(theApp->getWalletDB()->getDBLock()); ScopedLock sl(theApp->getWalletDB()->getDBLock());
Database *db=theApp->getWalletDB()->getDB(); Database *db=theApp->getWalletDB()->getDB();
if(!db->executeSQL(sql.c_str())) if(!db->executeSQL(sql))
{ {
#ifdef DEBUG #ifdef DEBUG
std::cerr << "Unable to load wallet" << std::endl; std::cerr << "Unable to load wallet" << std::endl;
@@ -456,8 +457,7 @@ void Wallet::load()
if(!db->startIterRows()) return; if(!db->startIterRows()) return;
while(db->getNextRow()) do {
{
std::string strGenerator, strComment; std::string strGenerator, strComment;
db->getStr("FamilyGenerator", strGenerator); db->getStr("FamilyGenerator", strGenerator);
@@ -476,7 +476,8 @@ void Wallet::load()
f->setComment(strComment); f->setComment(strComment);
} }
else assert(false); else assert(false);
} } while(db->getNextRow());
db->endIterRows(); db->endIterRows();
} }
@@ -484,17 +485,17 @@ void Wallet::load()
LocalAccount::pointer Wallet::getNewLocalAccount(const NewcoinAddress& family) LocalAccount::pointer Wallet::getNewLocalAccount(const NewcoinAddress& family)
{ {
boost::recursive_mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
std::map<NewcoinAddress, LocalAccountFamily::pointer>::iterator fit=mFamilies.find(family); std::map<NewcoinAddress, LocalAccountFamily::pointer>::iterator fit = mFamilies.find(family);
if(fit==mFamilies.end()) return LocalAccount::pointer(); if (fit == mFamilies.end()) return LocalAccount::pointer();
uint32 seq=fit->second->getSeq(); uint32 seq = fit->second->getSeq();
NewcoinAddress acct=fit->second->getAccount(seq, true); NewcoinAddress acct = fit->second->getAccount(seq, true);
fit->second->setSeq(seq+1); // FIXME: writeout new seq fit->second->setSeq(seq + 1); // FIXME: writeout new seq
std::map<NewcoinAddress, LocalAccount::pointer>::iterator ait=mAccounts.find(acct); std::map<NewcoinAddress, LocalAccount::pointer>::iterator ait = mAccounts.find(acct);
if(ait!=mAccounts.end()) return ait->second; if (ait != mAccounts.end()) return ait->second;
LocalAccount::pointer lac=boost::make_shared<LocalAccount>(fit->second, seq); LocalAccount::pointer lac = boost::make_shared<LocalAccount>(fit->second, seq);
mAccounts.insert(std::make_pair(acct, lac)); mAccounts.insert(std::make_pair(acct, lac));
sl.unlock(); sl.unlock();

View File

@@ -32,8 +32,8 @@ protected:
NewcoinAddress mNodePublicKey; NewcoinAddress mNodePublicKey;
NewcoinAddress mNodePrivateKey; NewcoinAddress mNodePrivateKey;
DH* mDh512; DH* mDh512;
DH* mDh1024; DH* mDh1024;
std::map<NewcoinAddress, LocalAccountFamily::pointer> mFamilies; std::map<NewcoinAddress, LocalAccountFamily::pointer> mFamilies;
std::map<NewcoinAddress, LocalAccount::pointer> mAccounts; std::map<NewcoinAddress, LocalAccount::pointer> mAccounts;
@@ -53,8 +53,8 @@ public:
// - Maintain peer connectivity through validation and peer management. // - Maintain peer connectivity through validation and peer management.
void start(); void start();
NewcoinAddress& getNodePublic() { return mNodePublicKey; } const NewcoinAddress& getNodePublic() const { return mNodePublicKey; }
NewcoinAddress& getNodePrivate() { return mNodePrivateKey; } const NewcoinAddress& getNodePrivate() const { return mNodePrivateKey; }
DH* getDh512() { return DHparams_dup(mDh512); } DH* getDh512() { return DHparams_dup(mDh512); }
DH* getDh1024() { return DHparams_dup(mDh1024); } DH* getDh1024() { return DHparams_dup(mDh1024); }

View File

@@ -238,6 +238,7 @@ public:
} }
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; }
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; }

View File

@@ -10,7 +10,6 @@ enum MessageType {
mtGET_CONTACTS= 10; mtGET_CONTACTS= 10;
mtCONTACT= 11; mtCONTACT= 11;
// operations for 'small' nodes // operations for 'small' nodes
mtSEARCH_TRANSACTION= 20; mtSEARCH_TRANSACTION= 20;
mtGET_ACCOUNT= 21; mtGET_ACCOUNT= 21;
@@ -22,6 +21,7 @@ enum MessageType {
mtLEDGER= 32; mtLEDGER= 32;
mtPROPOSE_LEDGER= 33; mtPROPOSE_LEDGER= 33;
mtCLOSE_LEDGER= 35; mtCLOSE_LEDGER= 35;
mtSTATUS_CHANGE= 36;
// data replication and synchronization // data replication and synchronization
mtGET_VALIDATIONS= 40; mtGET_VALIDATIONS= 40;
@@ -41,7 +41,8 @@ message TMHello {
optional bytes nodePublic = 4; // node may opt to remain anonymous optional bytes nodePublic = 4; // node may opt to remain anonymous
optional bytes nodeProof = 5; optional bytes nodeProof = 5;
optional uint32 ipv4Port = 6; optional uint32 ipv4Port = 6;
optional bytes closedLedger = 7; optional bytes closedLedger = 7; // our last closed ledger
optional bytes previousLedger = 8; // the ledger before the last closed ledger
} }
@@ -71,6 +72,33 @@ message TMTransaction {
optional bytes conflictingTransaction = 13; optional bytes conflictingTransaction = 13;
} }
enum NodeStatus {
nsCONNECTING = 1; // acquiring connections
nsCONNECTED = 2; // convinced we are connected to the real network
nsMONITORING = 3; // we know what the previous ledger is
nsVALIDATING = 4; // we have the full ledger contents
}
enum NodeEvent {
neCLOSED_LEDGER = 1; // closing a ledger because its close time has come
neACCEPTED_LEDGER = 2; // accepting a closed ledger, we have finished computing it
neSWITCHED_LEDGER = 3; // switching ledgers due to network consensus
neSHUTTING_DOWN = 4;
}
message TMStatusChange {
optional NodeStatus newStatus = 1;
optional NodeEvent newEvent = 2;
optional uint32 ledgerSeq = 3;
optional bytes ledgerHash = 4;
optional bytes previousLedgerHash = 5;
optional uint64 networkTime = 6;
}
message TMProposeLedger { message TMProposeLedger {
required uint32 closingSeq = 1; required uint32 closingSeq = 1;
required uint32 secondsSinceClose = 2; required uint32 secondsSinceClose = 2;

View File

@@ -69,7 +69,7 @@ void DH_der_gen_hex(std::string& strDer, int iKeyLength)
DH_der_gen(strBuf, iKeyLength); DH_der_gen(strBuf, iKeyLength);
strHex(strDer, strBuf); strDer = strHex(strBuf);
} }
DH* DH_der_load(const std::string& strDer) DH* DH_der_load(const std::string& strDer)

View File

@@ -36,8 +36,10 @@ std::string strJoin(Iterator first, Iterator last, std::string strSeperator)
char charHex(int iDigit); char charHex(int iDigit);
template<class Iterator> template<class Iterator>
void strHex(std::string& strDst, Iterator first, int iSize) std::string strHex(Iterator first, int iSize)
{ {
std::string strDst;
strDst.resize(iSize*2); strDst.resize(iSize*2);
for (int i = 0; i < iSize; i++) { for (int i = 0; i < iSize; i++) {
@@ -46,14 +48,16 @@ void strHex(std::string& strDst, Iterator first, int iSize)
strDst[i*2] = charHex(c >> 4); strDst[i*2] = charHex(c >> 4);
strDst[i*2+1] = charHex(c & 15); strDst[i*2+1] = charHex(c & 15);
} }
return strDst;
} }
inline void strHex(std::string& strDst, const std::string& strSrc) { inline const std::string strHex(const std::string& strSrc) {
strHex(strDst, strSrc.begin(), strSrc.size()); return strHex(strSrc.begin(), strSrc.size());
} }
inline void strHex(std::string& strDst, const std::vector<unsigned char> vchData) { inline std::string strHex(const std::vector<unsigned char> vchData) {
strHex(strDst, vchData.begin(), vchData.size()); return strHex(vchData.begin(), vchData.size());
} }
int charUnHex(char cDigit); int charUnHex(char cDigit);