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);
}
#if 0
int Database::getSingleDBValueInt(const char* sql)
{
int ret;
if( executeSQL(sql) && startIterRows() && getNextRow())
if( executeSQL(sql) && startIterRows()
{
ret=getInt(0);
endIterRows();
}else
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret=0;
}
return(ret);
}
#endif
#if 0
float Database::getSingleDBValueFloat(const char* sql)
{
float ret;
if( executeSQL(sql) && startIterRows() && getNextRow())
if(executeSQL(sql) && startIterRows() && getNextRow())
{
ret=getFloat(0);
endIterRows();
}else
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret=0;
}
return(ret);
}
#endif
#if 0
char* Database::getSingleDBValueStr(const char* sql,std::string& retStr)
{
char* ret;
if( executeSQL(sql) && startIterRows() && getNextRow())
if(executeSQL(sql) && startIterRows())
{
ret=getStr(0,retStr);
endIterRows();
}else
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret=0;
}
return(ret);
}
#endif
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 uint64 getBigInt(int colIndex)=0;
int getSingleDBValueInt(const char* sql);
float getSingleDBValueFloat(const char* sql);
char* getSingleDBValueStr(const char* sql, std::string& retStr);
// int getSingleDBValueInt(const char* sql);
// float getSingleDBValueFloat(const char* sql);
// char* getSingleDBValueStr(const char* sql, std::string& retStr);
};

View File

@@ -20,9 +20,11 @@ public:
typedef boost::shared_ptr<AccountState> pointer;
private:
NewcoinAddress mAccountID;
SerializedLedgerEntry::pointer mLedgerEntry;
bool mValid;
NewcoinAddress mAccountID;
NewcoinAddress mAuthorizedKey;
SerializedLedgerEntry::pointer mLedgerEntry;
bool mValid;
public:
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());
mDatabase=new SqliteDatabase(path.c_str());
mDatabase->connect();
for(int i=0; i<initCount; i++)
for(int i = 0; i < initCount; ++i)
mDatabase->executeSQL(initStrings[i], true);
}
@@ -41,11 +41,9 @@ DatabaseCon::~DatabaseCon()
delete mDatabase;
}
Application::Application() :
mUNL(mIOService),
Application::Application() : mNetOps(mIOService), mUNL(mIOService),
mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL),
mConnectionPool(mIOService),
mPeerDoor(NULL), mRPCDoor(NULL)
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL)
{
nothing();
}
@@ -57,7 +55,7 @@ void Application::stop()
{
mIOService.stop();
std::cerr << "Stopped: " << mIOService.stopped() << std::endl;
std::cerr << "Stopped: " << mIOService.stopped() << std::endl;
}
void Application::run()
@@ -82,43 +80,96 @@ void Application::run()
//
// Allow peer connections.
//
if(theConfig.PEER_PORT)
if(!theConfig.PEER_IP.empty() && theConfig.PEER_PORT)
{
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.
//
if(theConfig.RPC_PORT)
if(!theConfig.RPC_IP.empty() && theConfig.RPC_PORT)
{
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();
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
NewcoinAddress rootFamilySeed; // Hold the 128 password.
NewcoinAddress rootFamilyGenerator; // Hold the generator.
NewcoinAddress rootAddress;
// NewcoinAddress rootAddress;
rootFamilySeed.setFamilySeed(CKey::PassPhraseToKey("This is my payphrase."));
rootFamilyGenerator.setFamilyGenerator(rootFamilySeed);
rootAddress.setAccountPublic(rootFamilyGenerator, 0);
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));
firstLedger->updateHash();
firstLedger->setClosed();
firstLedger->setAccepted();
mMasterLedger.pushLedger(firstLedger);
Ledger::pointer secondLedger = firstLedger->closeLedger(time(NULL));
Ledger::pointer secondLedger = boost::make_shared<Ledger>(firstLedger);
mMasterLedger.pushLedger(secondLedger);
assert(!!secondLedger->getAccountState(rootAddress));
mMasterLedger.setSynced();
@@ -126,6 +177,7 @@ void Application::run()
mWallet.load();
// mWallet.syncToLedger(true, &(*secondLedger));
mNetOps.setStateTimer(5);
// temporary
mIOService.run(); // This blocks

View File

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

View File

@@ -1,31 +1,15 @@
#ifndef __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)
const int BLgSize=192;
const int BLgSize=190;
const int BLgPIndex=0, BLgLIndex=4; // ledger index
const int BLgPTotCoins=4, BLgLTotCoins=8; // total native coins
const int BLgPPrevLg=12, BLgLPrevLg=32; // previous ledger hash
const int BLgPTxT=44, BLgLTxT=32; // transaction tree hash
const int BLgPAcT=76, BLgLPAct=32; // account state hash
const int BLgPClTs=108, BLgLClTs=8; // closing timestamp
const int BLgPConf=116, BLgLPConf=4; // confidence
const int BLgPSig=120, 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
const int BLgPNlIn=116, BLgLNlIn=2;
const int BLgPSig=118, BLgLSig=72; // signature
#endif

View File

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

View File

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

View File

@@ -7,7 +7,7 @@
#define VALIDATORS_SITE "redstem.com"
#define VALIDATORS_FILE_NAME "validators.txt"
const int SYSTEM_PEER_PORT=6561;
const int SYSTEM_PEER_PORT = 6561;
// Allow anonymous DH.
#define DEFAULT_PEER_SSL_CIPHER_LIST "ALL:!LOW:!EXP:!MD5:@STRENGTH"
@@ -35,8 +35,9 @@ public:
int LEDGER_PROPOSAL_DELAY_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 BELIEF_QUORUM; // Percent agreement needed to sync ledger w/o validations
int VALIDATION_QUORUM; // Minimum validations to consider ledger authoritative
// node networking parameters
std::string PEER_IP;

View File

@@ -123,8 +123,9 @@ void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg)
BOOST_FOREACH(naPeer pair, mConnectedMap)
{
Peer::pointer peer = pair.second;
if(!fromPeer || !(peer.get() == fromPeer))
if (!peer)
std::cerr << "CP::RM null peer in list" << std::endl;
else if (!fromPeer || !(peer.get() == fromPeer))
peer->sendPacket(msg);
}
}
@@ -176,7 +177,7 @@ bool ConnectionPool::connectTo(const std::string& strIp, int iPort)
if (it == mIpMap.end())
{
// Did not find it. Not already connecting or connected.
std::cerr << "ConnectionPool::connectTo: Connectting: "
std::cerr << "ConnectionPool::connectTo: Connecting: "
<< strIp << " " << iPort << std::endl;
Peer::pointer peer(Peer::create(theApp->getIOService(), mCtx));
@@ -208,8 +209,23 @@ Json::Value ConnectionPool::getPeersJson()
BOOST_FOREACH(naPeer pair, mConnectedMap)
{
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;
@@ -221,7 +237,7 @@ bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& na)
bool bSuccess;
std::cerr << "ConnectionPool::peerConnected: " << na.humanNodePublic() << std::endl;
assert(!!peer);
if (na == theApp->getWallet().getNodePublic())
{
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)
{
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;
// Look for more to scan.
scanRefresh();
}
}

View File

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

View File

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

View File

@@ -167,7 +167,7 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult)
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.set_verify_mode(boost::asio::ssl::verify_peer);

View File

@@ -7,6 +7,7 @@
#include "Application.h"
#include "Ledger.h"
#include "utils.h"
#include "../obj/src/newcoin.pb.h"
#include "PackedMessage.h"
#include "Config.h"
@@ -16,7 +17,8 @@
#include "BinaryFormats.h"
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>();
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,
uint64 totCoins, uint64 timeStamp, uint32 ledgerSeq)
: 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)
{
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),
mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap)
mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger->mAccountStateMap)
{
mParentHash = prevLedger.getHash();
mLedgerSeq = prevLedger.mLedgerSeq+1;
prevLedger->setClosed();
prevLedger->updateHash();
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)
{
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(mTransHash, BLgPTxT)) 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();
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)
{
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(mTransHash, BLgPTxT)) 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();
if(mValidHash)
{
@@ -100,7 +106,7 @@ void Ledger::updateHash()
Serializer s(116);
addRaw(s);
mHash =s.getSHA512Half();
mHash = s.getSHA512Half();
mValidHash = true;
}
@@ -111,7 +117,8 @@ void Ledger::addRaw(Serializer &s)
s.add256(mParentHash);
s.add256(mTransHash);
s.add256(mAccountHash);
s.add64(mTimeStamp);
s.add64(mCloseTime);
s.add16(mLedgerInterval);
}
AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
@@ -124,7 +131,7 @@ AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID)
if (!item)
{
#ifdef DEBUG
// std::cerr << " notfound" << std::endl;
// std::cerr << " notfound" << std::endl;
#endif
return AccountState::pointer();
}
@@ -175,14 +182,6 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) const
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()
{
#if 0
@@ -225,13 +224,13 @@ bool Ledger::unitTest()
uint256 Ledger::getHash()
{
if(!mValidHash) updateHash();
return(mHash);
return(mHash);
}
void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
{
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("','");
sql.append(boost::lexical_cast<std::string>(ledger->mLedgerSeq));
@@ -240,7 +239,7 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
sql.append("','");
sql.append(boost::lexical_cast<std::string>(ledger->mTotCoins));
sql.append("','");
sql.append(boost::lexical_cast<std::string>(ledger->mTimeStamp));
sql.append(boost::lexical_cast<std::string>(ledger->mCloseTime));
sql.append("','");
sql.append(ledger->mAccountHash.GetHex());
sql.append("','");
@@ -248,7 +247,7 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
sql.append("');");
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
theApp->getLedgerDB()->getDB()->executeSQL(sql.c_str());
theApp->getLedgerDB()->getDB()->executeSQL(sql);
// write out dirty nodes
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());
Database *db = theApp->getLedgerDB()->getDB();
if (!db->executeSQL(sql.c_str()) || !db->startIterRows() || !db->getNextRow())
if (!db->executeSQL(sql) || !db->startIterRows())
return Ledger::pointer();
db->getStr("LedgerHash", hash);
@@ -285,7 +285,7 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
ledgerSeq = db->getBigInt("LedgerSeq");
db->endIterRows();
}
Ledger::pointer ret=boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, ledgerSeq);
if (ret->getHash() != ledgerHash)
{
@@ -316,18 +316,21 @@ void Ledger::addJson(Json::Value& ret)
Json::Value ledger(Json::objectValue);
boost::recursive_mutex::scoped_lock sl(mLock);
ledger["ParentHash"]=mParentHash.GetHex();
ledger["ParentHash"] = mParentHash.GetHex();
if(mClosed)
{
ledger["Hash"]=mHash.GetHex();
ledger["TransactionHash"]=mTransHash.GetHex();
ledger["AccountHash"]=mAccountHash.GetHex();
ledger["Closed"]=true;
ledger["Accepted"]=mAccepted;
ledger["Hash"] = mHash.GetHex();
ledger["TransactionHash"] = mTransHash.GetHex();
ledger["AccountHash"] = mAccountHash.GetHex();
ledger["Closed"] = true;
ledger["Accepted"] = mAccepted;
ledger["TotalCoins"] = boost::lexical_cast<std::string>(mTotCoins);
}
else ledger["Closed"]=false;
ret[boost::lexical_cast<std::string>(mLedgerSeq)]=ledger;
else ledger["Closed"] = false;
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)
@@ -339,42 +342,42 @@ Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger
int count;
// 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.
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
SHAMap::SHAMapDiff mapDifferences;
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();
if(!Transaction::convertToTransactions(oldPrevious->getLedgerSeq(), newPrevious->getLedgerSeq(),
if (!Transaction::convertToTransactions(oldPrevious->getLedgerSeq(), newPrevious->getLedgerSeq(),
false, true, mapDifferences, TxnDiff))
return Ledger::pointer(); // new previous ledger contains invalid transactions
// 4) Try to add those transactions to the new ledger.
do
{
count=0;
count = 0;
std::map<uint256, std::pair<Transaction::pointer, Transaction::pointer> >::iterator it = TxnDiff.begin();
while (it != TxnDiff.end())
{
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++);
}
else ++it;
}
} while (count!=0);
} while (count != 0);
// WRITEME: Handle rejected transactions left in TxnDiff
// 5) Try to add transactions from this ledger to the new ledger.
std::map<uint256, Transaction::pointer> txnMap;
for(SHAMapItem::pointer mit = peekTransactionMap()->peekFirstItem();
for (SHAMapItem::pointer mit = peekTransactionMap()->peekFirstItem();
!!mit; mit = peekTransactionMap()->peekNextItem(mit->getTag()))
{
uint256 txnID = mit->getTag();
@@ -385,18 +388,18 @@ Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger
do
{
count=0;
count = 0;
std::map<uint256, Transaction::pointer>::iterator it = txnMap.begin();
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++);
}
else ++it;
}
} while(count!=0);
} while(count != 0);
// WRITEME: Handle rejected transactions left in txnMap
@@ -406,7 +409,7 @@ Ledger::pointer Ledger::switchPreviousLedger(Ledger::pointer oldPrevious, Ledger
void Ledger::setAcquiring(void)
{
if(!mTransactionMap || !mAccountStateMap) throw SHAMapException(InvalidMap);
if (!mTransactionMap || !mAccountStateMap) throw SHAMapException(InvalidMap);
mTransactionMap->setSynching();
mAccountStateMap->setSynching();
}
@@ -425,3 +428,25 @@ bool Ledger::isAcquiringAS(void)
{
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/enable_shared_from_this.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "../json/value.h"
@@ -15,13 +16,12 @@
#include "BitcoinUtil.h"
#include "SHAMap.h"
enum LedgerStateParms
{
lepNONE = 0, // no special flags
// input flags
lepCREATE, // Create if not present
lepCREATE, // Create if not present
// output flags
lepOKAY, // success
@@ -37,43 +37,42 @@ class Ledger : public boost::enable_shared_from_this<Ledger>
public:
typedef boost::shared_ptr<Ledger> pointer;
enum TransResult
{
TR_ERROR =-1,
TR_SUCCESS =0,
TR_NOTFOUND =1,
TR_ALREADY =2,
TR_BADTRANS =3, // the transaction itself is corrupt
TR_BADACCT =4, // one of the accounts is invalid
TR_INSUFF =5, // the sending(apply)/receiving(remove) account is broke
TR_PASTASEQ =6, // account is past this transaction
TR_PREASEQ =7, // account is missing transactions before this
TR_BADLSEQ =8, // ledger too early
TR_TOOSMALL =9, // amount is less than Tx fee
TR_ERROR = -1,
TR_SUCCESS = 0,
TR_NOTFOUND = 1,
TR_ALREADY = 2,
TR_BADTRANS = 3, // the transaction itself is corrupt
TR_BADACCT = 4, // one of the accounts is invalid
TR_INSUFF = 5, // the sending(apply)/receiving(remove) account is broke
TR_PASTASEQ = 6, // account is past this transaction
TR_PREASEQ = 7, // account is missing transactions before this
TR_BADLSEQ = 8, // ledger too early
TR_TOOSMALL = 9, // amount is less than Tx fee
};
private:
uint256 mHash, mParentHash, mTransHash, mAccountHash;
uint64 mTotCoins, mTimeStamp;
uint64 mTotCoins;
uint64 mCloseTime; // when this ledger closes
uint32 mLedgerSeq;
uint16 mLedgerInterval;
bool mClosed, mValidHash, mAccepted, mImmutable;
SHAMap::pointer mTransactionMap, mAccountStateMap;
mutable boost::recursive_mutex mLock;
Ledger(const Ledger&); // no implementation
Ledger& operator=(const Ledger&); // no implementation
protected:
Ledger(Ledger& previous, uint64 timestamp); // ledger after this one
void updateHash();
bool addTransaction(Transaction::pointer);
bool addTransaction(const uint256& id, const Serializer& txn, uint64_t fee);
static Ledger::pointer getSQL(const std::string& sqlStatement);
SerializedLedgerEntry::pointer getASNode(LedgerStateParms& parms, const uint256& nodeID,
@@ -82,25 +81,33 @@ protected:
public:
Ledger(const NewcoinAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger
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::string& rawLedger);
Ledger(Ledger::pointer previous); // ledger after this one
void setClosed() { mClosed=true; }
void setAccepted() { mAccepted=true; }
bool isClosed() { return mClosed; }
bool isAccepted() { return mAccepted; }
void updateHash();
void setClosed() { mClosed = true; }
void setAccepted() { mAccepted = true; }
bool isClosed() { return mClosed; }
bool isAccepted() { return mAccepted; }
// ledger signature operations
void addRaw(Serializer &s);
uint256 getHash();
const uint256& getParentHash() const { return mParentHash; }
const uint256& getTransHash() const { return mTransHash; }
const uint256& getAccountHash() const { return mAccountHash; }
uint64 getTotalCoins() const { return mTotCoins; }
uint64 getTimeStamp() const { return mTimeStamp; }
uint32 getLedgerSeq() const { return mLedgerSeq; }
const uint256& getParentHash() const { return mParentHash; }
const uint256& getTransHash() const { return mTransHash; }
const uint256& getAccountHash() const { return mAccountHash; }
uint64 getTotalCoins() const { return mTotCoins; }
uint64 getCloseTimeNC() const { return mCloseTime; }
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
SHAMap::pointer peekTransactionMap() { return mTransactionMap; }
@@ -116,7 +123,7 @@ public:
bool hasTransaction(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
AccountState::pointer getAccountState(const NewcoinAddress& acctID);
@@ -144,7 +151,6 @@ public:
const uint160& currency)
{ return getRippleIndex(account.getAccountID(), extendTo.getAccountID(), currency); }
Ledger::pointer closeLedger(uint64 timestamp);
bool isCompatible(boost::shared_ptr<Ledger> other);
bool signLedger(std::vector<unsigned char> &signature, const LocalHanko &hanko);
@@ -164,3 +170,4 @@ inline LedgerStateParms operator&(const LedgerStateParms& l1, const LedgerStateP
}
#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 <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),
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()
{
#ifdef DEBUG
std::cerr << "Done acquiring ledger " << mHash.GetHex() << std::endl;
#endif
std::vector< boost::function<void (LedgerAcquire::pointer)> > triggers;
mLock.lock();
triggers=mOnComplete;
triggers = mOnComplete;
mOnComplete.empty();
mLock.unlock();
for(int i=0; i<triggers.size(); i++)
for (int i = 0; i<triggers.size(); ++i)
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(ptr) ptr->trigger(true);
if (result == boost::asio::error::operation_aborted) return;
LedgerAcquire::pointer ptr = wptr.lock();
if (!!ptr) ptr->trigger(Peer::pointer());
}
void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)> trigger)
@@ -42,29 +55,49 @@ void LedgerAcquire::addOnComplete(boost::function<void (LedgerAcquire::pointer)>
mLock.unlock();
}
void LedgerAcquire::trigger(bool timer)
void LedgerAcquire::trigger(Peer::pointer peer)
{
if(mComplete || mFailed) return;
if(!mHaveBase)
#ifdef DEBUG
std::cerr << "Trigger acquiring ledger " << mHash.GetHex() << std::endl;
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?
boost::shared_ptr<newcoin::TMGetLedger> tmGL=boost::make_shared<newcoin::TMGetLedger>();
#ifdef DEBUG
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_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);
if(mLedger->peekTransactionMap()->getHash().isZero())
if (mLedger->peekTransactionMap()->getHash().isZero())
{ // 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_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liTX_NODE);
*(tmGL->add_nodeids())=SHAMapNode().getRawString();
*(tmGL->add_nodeids()) = SHAMapNode().getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL);
}
else
@@ -72,38 +105,51 @@ void LedgerAcquire::trigger(bool timer)
std::vector<SHAMapNode> nodeIDs;
std::vector<uint256> nodeHashes;
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
{
mHaveTransactions=true;
if(mHaveState) mComplete=true;
mHaveTransactions = true;
if (mHaveState) mComplete = true;
}
}
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_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liTX_NODE);
for(std::vector<SHAMapNode>::iterator it=nodeIDs.begin(); it!=nodeIDs.end(); ++it)
*(tmGL->add_nodeids())=it->getRawString();
for (std::vector<SHAMapNode>::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it)
*(tmGL->add_nodeids()) = it->getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL);
}
}
}
if(mHaveBase && !mHaveState)
if (mHaveBase && !mHaveState)
{
#ifdef DEBUG
std::cerr << "need as" << std::endl;
#endif
assert(mLedger);
if(mLedger->peekAccountStateMap()->getHash().isZero())
if (mLedger->peekAccountStateMap()->getHash().isZero())
{ // 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_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liAS_NODE);
*(tmGL->add_nodeids())=SHAMapNode().getRawString();
*(tmGL->add_nodeids()) = SHAMapNode().getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL);
}
else
@@ -111,50 +157,61 @@ void LedgerAcquire::trigger(bool timer)
std::vector<SHAMapNode> nodeIDs;
std::vector<uint256> nodeHashes;
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
{
mHaveState=true;
if(mHaveTransactions) mComplete=true;
mHaveState = true;
if (mHaveTransactions) mComplete = true;
}
}
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_ledgerseq(mLedger->getLedgerSeq());
tmGL->set_itype(newcoin::liAS_NODE);
for(std::vector<SHAMapNode>::iterator it=nodeIDs.begin(); it!=nodeIDs.end(); ++it)
*(tmGL->add_nodeids())=it->getRawString();
for (std::vector<SHAMapNode>::iterator it =nodeIDs.begin(); it != nodeIDs.end(); ++it)
*(tmGL->add_nodeids()) = it->getRawString();
if (peer)
{
sendRequest(tmGL, peer);
return;
}
sendRequest(tmGL);
}
}
}
if(mComplete || mFailed)
if (mComplete || mFailed)
done();
else if(timer)
setTimer();
else
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)
{
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();
while(it!=mPeers.end())
std::list<boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
while(it != mPeers.end())
{
if(it->expired())
if (it->expired())
mPeers.erase(it++);
else
{
// FIXME: Track last peer sent to and time sent
it->lock()->sendPacket(packet);
Peer::pointer peer = it->lock();
if (peer) peer->sendPacket(packet);
return;
}
}
@@ -163,33 +220,34 @@ void LedgerAcquire::sendRequest(boost::shared_ptr<newcoin::TMGetLedger> tmGL)
void LedgerAcquire::peerHas(Peer::pointer ptr)
{
boost::recursive_mutex::scoped_lock sl(mLock);
std::list<boost::weak_ptr<Peer> >::iterator it=mPeers.begin();
while(it!=mPeers.end())
std::list<boost::weak_ptr<Peer> >::iterator it = mPeers.begin();
while (it != mPeers.end())
{
Peer::pointer pr=it->lock();
if(!pr) // we have a dead entry, remove it
it=mPeers.erase(it);
Peer::pointer pr = it->lock();
if (!pr) // we have a dead entry, remove it
it = mPeers.erase(it);
else
{
if(pr->samePeer(ptr)) return; // we already have this peer
if (pr->samePeer(ptr)) return; // we already have this peer
++it;
}
}
mPeers.push_back(ptr);
if (mPeers.size() == 1) trigger(ptr);
}
void LedgerAcquire::badPeer(Peer::pointer ptr)
{
boost::recursive_mutex::scoped_lock sl(mLock);
std::list<boost::weak_ptr<Peer> >::iterator it=mPeers.begin();
while(it!=mPeers.end())
while (it != mPeers.end())
{
Peer::pointer pr=it->lock();
if(!pr) // we have a dead entry, remove it
it=mPeers.erase(it);
Peer::pointer pr = it->lock();
if (!pr) // we have a dead entry, remove it
it = mPeers.erase(it);
else
{
if(ptr->samePeer(pr))
if (ptr->samePeer(pr))
{ // We found a pointer to the bad peer
mPeers.erase(it);
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
#ifdef DEBUG
std::cerr << "got base acquiring ledger " << mHash.GetHex() << std::endl;
#endif
boost::recursive_mutex::scoped_lock sl(mLock);
if(mHaveBase) return true;
Ledger* ledger=new Ledger(data);
if(ledger->getHash()!=mHash)
if (mHaveBase) return true;
mLedger = boost::make_shared<Ledger>(data);
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;
}
mLedger=Ledger::pointer(ledger);
mHaveBase = true;
if (!mLedger->getTransHash()) mHaveTransactions = true;
if (!mLedger->getAccountHash()) mHaveState = true;
mLedger->setAcquiring();
mHaveBase=true;
trigger(peer);
return true;
}
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;
std::list<SHAMapNode>::const_iterator nodeIDit=nodeIDs.begin();
std::list<std::vector<unsigned char> >::const_iterator nodeDatait=data.begin();
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->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;
++nodeIDit;
++nodeDatait;
}
if(!mLedger->peekTransactionMap()->isSynching()) mHaveTransactions=true;
if (!mLedger->peekTransactionMap()->isSynching())
{
mHaveTransactions = true;
if (mHaveState) mComplete = true;
}
trigger(peer);
return true;
}
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;
std::list<SHAMapNode>::const_iterator nodeIDit=nodeIDs.begin();
std::list<std::vector<unsigned char> >::const_iterator nodeDatait=data.begin();
while(nodeIDit!=nodeIDs.end())
#ifdef DEBUG
std::cerr << "got ASdata acquiring ledger " << mHash.GetHex() << std::endl;
#endif
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;
++nodeIDit;
++nodeDatait;
}
if(!mLedger->peekAccountStateMap()->isSynching()) mHaveState=true;
if (!mLedger->peekAccountStateMap()->isSynching())
{
mHaveState = true;
if (mHaveTransactions) mComplete = true;
}
trigger(peer);
return true;
}
LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash)
{
boost::mutex::scoped_lock sl(mLock);
LedgerAcquire::pointer& ptr=mLedgers[hash];
if(ptr) return ptr;
return boost::make_shared<LedgerAcquire>(hash);
LedgerAcquire::pointer& ptr = mLedgers[hash];
if (ptr) return ptr;
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)
{
boost::mutex::scoped_lock sl(mLock);
std::map<uint256, LedgerAcquire::pointer>::iterator it=mLedgers.find(hash);
if(it!=mLedgers.end()) return it->second;
std::map<uint256, LedgerAcquire::pointer>::iterator it = mLedgers.find(hash);
if (it != mLedgers.end()) return it->second;
return LedgerAcquire::pointer();
}
bool LedgerAcquireMaster::hasLedger(const uint256& hash)
{
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;
if(packet.ledgerhash().size()!=32) return false;
memcpy(&hash, packet.ledgerhash().data(), 32);
LedgerAcquire::pointer ledger=find(hash);
if(!ledger) return false;
if(packet.type()==newcoin::liBASE)
if (packet.ledgerhash().size() != 32)
{
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());
#ifdef DEBUG
std::cerr << "error" << std::endl;
#endif
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<std::vector<unsigned char> > nodeData;
if(packet.nodes().size()<=0) return false;
for(int i=0; i<packet.nodes().size(); i++)
if (packet.nodes().size()<=0) return false;
for (int i = 0; i<packet.nodes().size(); ++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()));
nodeData.push_back(std::vector<unsigned char>(node.nodedata().begin(), node.nodedata().end()));
}
if(packet.type()==newcoin::liTX_NODE) return ledger->takeTxNode(nodeIDs, nodeData);
else return ledger->takeAsNode(nodeIDs, nodeData);
if (packet.type() == newcoin::liTX_NODE) return ledger->takeTxNode(nodeIDs, nodeData, peer);
else return ledger->takeAsNode(nodeIDs, nodeData, peer);
}
else return false;
return false;
}

View File

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

View File

@@ -12,9 +12,10 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(Balance), STI_UINT64, SOE_REQUIRED, 0 },
{ S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(LastTxn), STI_UINT32, SOE_REQUIRED, 0 },
{ S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 1 },
{ S_FIELD(WalletLocator),STI_HASH256, SOE_IFFLAG, 2 },
{ S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 4 },
{ S_FIELD(AuthorizedKey),STI_VL, SOE_IFFLAG, 1 },
{ S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 },
{ S_FIELD(WalletLocator),STI_HASH256, SOE_IFFLAG, 4 },
{ S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 8 },
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
},
@@ -33,6 +34,13 @@ LedgerEntryFormat LedgerFormats[]=
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
{ 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, {
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
{ S_FIELD(Nickname), STI_HASH256, SOE_REQUIRED, 0 },

View File

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

View File

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

View File

@@ -11,7 +11,7 @@ class LedgerHistory
public:
LedgerHistory();
void addLedger(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));
return base;
}
// vim:ts=4

View File

@@ -1,7 +1,6 @@
#include "LedgerMaster.h"
#include "Application.h"
#include "NewcoinAddress.h"
#include "TimingService.h"
#include "Conversion.h"
#include <boost/foreach.hpp>
@@ -36,6 +35,17 @@ void LedgerMaster::pushLedger(Ledger::pointer 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
void LedgerMaster::startFinalization()

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,14 @@
#include "Application.h"
#include "NetworkOPs.h"
#include <boost/bind.hpp>
#include <boost/unordered_map.hpp>
#include "utils.h"
#include "Application.h"
#include "Transaction.h"
// This is the primary interface into the "client" portion of the program.
// Code that wants to do normal operations on the network such as
// 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
// 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()
@@ -26,10 +41,10 @@ uint32 NetworkOPs::getCurrentLedgerID()
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source)
{
Transaction::pointer dbtx=theApp->getMasterTransaction().fetch(trans->getID(), true);
if(dbtx) return dbtx;
Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true);
if (dbtx) return dbtx;
if(!trans->checkSign())
if (!trans->checkSign())
{
#ifdef DEBUG
std::cerr << "Transaction has bad signature" << std::endl;
@@ -38,10 +53,10 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
return trans;
}
TransactionEngineResult r=theApp->getMasterLedger().doTransaction(*trans->getSTransaction(), tepNONE);
if(r==terFAILED) throw Fault(IO_ERROR);
TransactionEngineResult r = theApp->getMasterLedger().doTransaction(*trans->getSTransaction(), tepNONE);
if (r == terFAILED) throw Fault(IO_ERROR);
if(r == terPRE_SEQ)
if (r == terPRE_SEQ)
{ // transaction should be held
#ifdef DEBUG
std::cerr << "Transaction should be held" << std::endl;
@@ -51,7 +66,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
theApp->getMasterLedger().addHeldTransaction(trans);
return trans;
}
if ( (r==terPAST_SEQ || r==terPAST_LEDGER) )
if ((r == terPAST_SEQ) || (r == terPAST_LEDGER))
{ // duplicate or conflict
#ifdef DEBUG
std::cerr << "Transaction is obsolete" << std::endl;
@@ -60,7 +75,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
return trans;
}
if(r==terSUCCESS)
if (r == terSUCCESS)
{
#ifdef DEBUG
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
// theApp->getWallet().applyTransaction(trans);
newcoin::TMTransaction *tx=new newcoin::TMTransaction();
boost::shared_ptr<newcoin::TMTransaction> tx = boost::make_shared<newcoin::TMTransaction>();
Serializer::pointer s;
trans->getSTransaction()->getTransaction(*s, false);
tx->set_rawtransaction(&s->getData().front(), s->getLength());
tx->set_status(newcoin::tsCURRENT);
tx->set_receivetimestamp(getNetworkTime());
tx->set_receivetimestamp(getNetworkTimeNC());
tx->set_ledgerindexpossible(trans->getLedger());
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,
const NewcoinAddress& sourceAccount, uint32 minSeq, uint32 maxSeq)
{
AccountState::pointer state=getAccountState(sourceAccount);
if(!state) return 0;
if(minSeq>state->getSeq()) return 0;
if(maxSeq>state->getSeq()) maxSeq=state->getSeq();
if(maxSeq>minSeq) return 0;
AccountState::pointer state = getAccountState(sourceAccount);
if (!state) return 0;
if (minSeq > state->getSeq()) return 0;
if (maxSeq > state->getSeq()) maxSeq = state->getSeq();
if (maxSeq > minSeq) return 0;
int count=0;
for(int i=minSeq; i<=maxSeq; i++)
int count = 0;
for(int i = minSeq; i <= maxSeq; ++i)
{
Transaction::pointer txn=Transaction::findFrom(sourceAccount, i);
Transaction::pointer txn = Transaction::findFrom(sourceAccount, i);
if(txn)
{
txns.push_back(txn);
count++;
++count;
}
}
return count;
@@ -134,3 +149,215 @@ AccountState::pointer NetworkOPs::getAccountState(const NewcoinAddress& accountI
{
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__
#define __NETWORK_OPS__
#include <boost/asio.hpp>
#include "Transaction.h"
#include "AccountState.h"
#include "Ledger.h"
// Operations that clients may wish to perform against the network
// Master operational handler, server sequencer, network tracker
class Peer;
class NetworkOPs
{
public:
enum Fault
{ // exceptions these functions can throw
IO_ERROR=1,
NO_NETWORK=2,
IO_ERROR = 1,
NO_NETWORK = 2,
};
enum OperatingMode
{ // how we process transactions or account balance requests
FAULTED=0, // we are unable to process requests (not ready or no network)
FULL_LOCAL=1, // we are in full local sync
PART_LOCAL=2, // we can validate remote data but have to request it
REMOTE=3 // we have to trust remote nodes
omDISCONNECTED = 0, // not ready to process requests
omCONNECTED = 1, // convinced we are talking to the network
omTRACKING = 2, // convinced we agree with the network
omFULL = 3 // we have the ledger and can even validate
};
public:
protected:
OperatingMode mMode;
boost::asio::deadline_timer mNetTimer;
// context information
OperatingMode getOperatingMode();
public:
NetworkOPs(boost::asio::io_service& io_service);
// network information
uint64 getNetworkTime();
uint64 getNetworkTimeNC();
boost::posix_time::ptime getNetworkTimePT();
uint32 getCurrentLedgerID();
OperatingMode getOperatingMode() { return mMode; }
// 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);
int findTransactionsBySource(std::list<Transaction::pointer>&, const NewcoinAddress& sourceAccount,
uint32 minSeq, uint32 maxSeq);
@@ -44,19 +53,24 @@ public:
// account operations
AccountState::pointer getAccountState(const NewcoinAddress& accountID);
// contact block operations
// raw object operations
bool findRawLedger(const uint256& ledgerHash, std::vector<unsigned char>& rawLedger);
bool findRawTransaction(const uint256& transactionHash, std::vector<unsigned char>& rawTransaction);
bool findAccountNode(const uint256& nodeHash, std::vector<unsigned char>& rawAccountNode);
bool findTransactionNode(const uint256& nodeHash, std::vector<unsigned char>& rawTransactionNode);
// tree synchronzation operations
// tree synchronization operations
bool getTransactionTreeNodes(uint32 ledgerSeq, const uint256& myNodeID,
const std::vector<unsigned char>& myNode, std::list<std::vector<unsigned char> >& newNodes);
bool getAccountStateNodes(uint32 ledgerSeq, const uint256& myNodeId,
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
// vim:ts=4

View File

@@ -3,15 +3,15 @@
#include "Config.h"
#include "BitcoinUtil.h"
#include "rfc1751.h"
#include "utils.h"
#include "openssl/rand.h"
#include <cassert>
#include <algorithm>
#include <iostream>
#include <boost/format.hpp>
#include <boost/functional/hash.hpp>
#include <boost/test/unit_test.hpp>
#include <cassert>
#include <iostream>
#include <openssl/rand.h>
NewcoinAddress::NewcoinAddress()
{
@@ -273,7 +273,7 @@ void NewcoinAddress::setAccountPublic(const std::vector<unsigned char>& vPublic)
void NewcoinAddress::setAccountPublic(const NewcoinAddress& generator, int seq)
{
CKey pubkey = CKey(generator, seq);
CKey pubkey = CKey(generator, seq+1);
setAccountPublic(pubkey.GetPubKey());
}
@@ -282,14 +282,14 @@ void NewcoinAddress::setAccountPublic(const NewcoinAddress& generator, int seq)
// AccountPrivate
//
uint256 NewcoinAddress::getAccountPrivate() const
const std::vector<unsigned char>& NewcoinAddress::getAccountPrivate() const
{
switch (nVersion) {
case VER_NONE:
throw std::runtime_error("unset source");
case VER_ACCOUNT_PRIVATE:
return uint256(vchData);
return vchData;
default:
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);
}
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
//

View File

@@ -78,13 +78,20 @@ public:
//
// Accounts Private
//
uint256 getAccountPrivate() const;
const std::vector<unsigned char>& getAccountPrivate() const;
std::string humanAccountPrivate() const;
bool setAccountPrivate(const std::string& strPrivate);
void setAccountPrivate(const std::vector<unsigned char>& vPrivate);
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

View File

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

View File

@@ -19,9 +19,10 @@
// Node has this long to verify its identity from connection accepted or connection attempt.
#define NODE_VERIFY_SECONDS 15
Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx)
: mSocketSsl(io_service, ctx),
mVerifyTimer(io_service)
Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx) :
mConnected(false),
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
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
std::cerr << "Peer::handle_write bytes: "<< bytes_transferred << std::endl;
std::cerr << "Peer::handle_write bytes: "<< bytes_transferred << std::endl;
#endif
mSendingPacket=PackedMessage::pointer();
mSendingPacket = PackedMessage::pointer();
if(error)
if (error)
{
detach();
detach("hw");
return;
}
if(!mSendQ.empty())
if (!mSendQ.empty())
{
PackedMessage::pointer packet=mSendQ.front();
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;
(void) mVerifyTimer.cancel();
mSendQ.clear();
// mSocketSsl.close();
if (!mIpPort.first.empty()) {
if (!mIpPort.first.empty())
{
if (mClientConnect)
// Connection might be part of scanning. Inform connect failed.
theApp->getConnectionPool().peerFailed(mIpPort.first, mIpPort.second);
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.
// std::cerr << "Deadline cancelled." << std::endl;
nothing(); // Aborter is done.
nothing(); // Aborter is done.
}
else if (ecResult)
{
{
std::cerr << "Peer verify timer error: " << std::endl;
// Can't do anything sound.
abort();
}
}
else
{
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).
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;
std::cerr << "Peer::connect: " << strIp << " " << iPort << std::endl;
std::cerr << "Peer::connect: " << strIp << " " << iPort << std::endl;
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::tcp::resolver resolver(theApp->getIOService());
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())
{
std::cerr << "Peer::connect: Bad IP" << std::endl;
detach();
detach("c");
return;
}
else
{
@@ -124,13 +131,14 @@ void Peer::connect(const std::string strIp, int iPort)
if (err)
{
std::cerr << "Peer::connect: Failed to set timer." << std::endl;
detach();
detach("c2");
return;
}
}
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(
mSocketSsl.lowest_layer(),
@@ -152,7 +160,7 @@ void Peer::handleStart(const boost::system::error_code& error)
if (error)
{
std::cerr << "Peer::handleStart: failed:" << error << std::endl;
detach();
detach("hs");
}
else
{
@@ -167,16 +175,16 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip
if (error)
{
std::cerr << "Connect peer: failed:" << error << std::endl;
detach();
detach("hc");
}
else
{
std::cerr << "Connect peer: success." << std::endl;
mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true));
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true));
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));
}
}
@@ -196,13 +204,13 @@ void Peer::connected(const boost::system::error_code& error)
if (error)
{
std::cerr << "Remote peer: accept error: " << strIp << " " << iPort << " : " << error << std::endl;
detach();
detach("ctd");
}
else if (!theApp->getConnectionPool().peerRegister(shared_from_this(), strIp, iPort))
{
std::cerr << "Remote peer: rejecting: " << strIp << " " << iPort << std::endl;
// XXX Reject with a rejection message: already connected
detach();
detach("ctd2");
}
else
{
@@ -212,11 +220,12 @@ void Peer::connected(const boost::system::error_code& error)
//BOOST_LOG_TRIVIAL(info) << "Connected to Peer.";
mIpPort = make_pair(strIp, iPort);
assert(!mIpPort.first.empty());
mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true));
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true));
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));
}
}
@@ -247,9 +256,6 @@ void Peer::sendPacket(PackedMessage::pointer packet)
void Peer::start_read_header()
{
#ifdef DEBUG
std::cerr << "SRH" << std::endl;
#endif
mReadbuf.clear();
mReadbuf.resize(HEADER_SIZE);
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
if(msg_len>(32*1024*1024))
{
detach();
detach("hrh");
return;
}
start_read_body(msg_len);
}
else
{
detach();
std::cerr << "Peer::handle_read_header: Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error;
detach("hrh2");
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
{
detach();
std::cerr << "Peer::handle_read_body: Error: " << error << std::endl; //else BOOST_LOG_TRIVIAL(info) << "Error: " << error;
detach("hrb");
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;
#endif
// If not connected, only accept mtHELLO. Otherwise, don't accept mtHELLO.
if (mIpPort.first.empty() == (type == newcoin::mtHELLO))
std::cerr << "Peer::processReadBuffer: " << mIpPort.first << " " << mIpPort.second << std::endl;
// 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;
detach();
detach("prb1");
}
else
{
@@ -324,7 +332,7 @@ void Peer::processReadBuffer()
newcoin::TMHello msg;
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
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;
@@ -400,6 +408,17 @@ void Peer::processReadBuffer()
}
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:
{
newcoin::TMGetLedger msg;
@@ -474,7 +493,7 @@ void Peer::processReadBuffer()
break;
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
{
// 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.
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 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;
}
if (bDetach)
{
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)
{
// Figure out what ledger they want
Ledger::pointer ledger;
if(packet.has_ledgerhash())
if (packet.has_ledgerhash())
{
uint256 ledgerhash;
if(packet.ledgerhash().size()!=32)
if (packet.ledgerhash().size() != 32)
{
punishPeer(PP_INVALID_REQUEST);
return;
}
memcpy(&ledgerhash, packet.ledgerhash().data(), 32);
ledger=theApp->getMasterLedger().getLedgerByHash(ledgerhash);
ledger = theApp->getMasterLedger().getLedgerByHash(ledgerhash);
}
else if(packet.has_ledgerseq())
ledger=theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq());
else if(packet.has_ltype() && (packet.ltype() == newcoin::ltCURRENT) )
ledger=theApp->getMasterLedger().getCurrentLedger();
else if(packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSING) )
else if (packet.has_ledgerseq())
ledger = theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq());
else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCURRENT))
ledger = theApp->getMasterLedger().getCurrentLedger();
else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSING))
{
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();
if(ledger && !ledger->isClosed())
if (ledger && !ledger->isClosed())
ledger = theApp->getMasterLedger().getLedgerBySeq(ledger->getLedgerSeq() - 1);
}
else
@@ -660,18 +713,17 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
}
// Figure out what information they want
newcoin::TMLedgerData* data=new newcoin::TMLedgerData;
uint256 lHash=ledger->getHash();
boost::shared_ptr<newcoin::TMLedgerData> data = boost::make_shared<newcoin::TMLedgerData>();
uint256 lHash = ledger->getHash();
data->set_ledgerhash(lHash.begin(), lHash.size());
data->set_ledgerseq(ledger->getLedgerSeq());
data->set_type(packet.itype());
if(packet.itype()==newcoin::liBASE)
if(packet.itype() == newcoin::liBASE)
{
Serializer nData(116);
ledger->addRaw(nData);
newcoin::TMLedgerNode* node=data->add_nodes();
node->set_nodedata(nData.getDataPtr(), nData.getLength());
data->add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength());
}
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))
{
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();
nodeIDIterator!=nodeIDs.end(); ++nodeIDIterator, ++rawNodeIterator)
{
newcoin::TMLedgerNode* node=data->add_nodes();
Serializer nID(33);
nodeIDIterator->addIDRaw(nID);
newcoin::TMLedgerNode* node=data->add_nodes();
node->set_nodeid(nID.getDataPtr(), nID.getLength());
node->set_nodedata(&rawNodeIterator->front(), rawNodeIterator->size());
}
@@ -721,7 +773,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
void Peer::recvLedger(newcoin::TMLedgerData& packet)
{
if(!theApp->getMasterLedgerAcquire().gotLedgerData(packet))
if(!theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this()))
punishPeer(PP_UNWANTED_DATA);
}
@@ -764,22 +816,23 @@ void Peer::sendHello()
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_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_nodeproof(&vchSig[0], vchSig.size());
h->set_ipv4port(theConfig.PEER_PORT);
Ledger::pointer closedLedger = theApp->getMasterLedger().getClosedLedger();
assert(closedLedger && closedLedger->isClosed());
if(closedLedger->isClosed())
if (closedLedger->isClosed())
{
Serializer s(128);
closedLedger->addRaw(s);
h->set_closedledger(s.getDataPtr(), s.getLength());
uint256 hash = closedLedger->getHash();
h->set_closedledger(hash.begin(), hash.GetSerializeSize());
hash = closedLedger->getParentHash();
h->set_previousledger(hash.begin(), hash.GetSerializeSize());
}
PackedMessage::pointer packet = boost::make_shared<PackedMessage>

View File

@@ -15,9 +15,9 @@
enum PeerPunish
{
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_UNWANTED_DATA=3, // The peer sent us data we didn't want/need
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_UNWANTED_DATA = 3, // The peer sent us data we didn't want/need
};
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>
{
public:
static const int psbGotHello=0, psbSentHello=1, psbInMap=2, psbTrusted=3;
static const int psbNoLedgers=4, psbNoTransactions=5, psbDownLevel=6;
static const int psbGotHello = 0, psbSentHello = 1, psbInMap = 2, psbTrusted = 3;
static const int psbNoLedgers = 4, psbNoTransactions = 5, psbDownLevel = 6;
void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it);
private:
bool mClientConnect; // In process of connecting as client.
bool mConnected; // True, if hello accepted.
NewcoinAddress mNodePublic; // Node public key of peer.
ipPort mIpPort;
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;
@@ -62,8 +67,6 @@ protected:
void sendPacketForce(PackedMessage::pointer packet);
void sendHello();
void sendTransaction(newcoin::TMTransaction& packet);
void sendValidation();
void recvHello(newcoin::TMHello& packet);
void recvTransaction(newcoin::TMTransaction& packet);
@@ -81,6 +84,7 @@ protected:
void recvAccount(newcoin::TMAccount& packet);
void recvGetLedger(newcoin::TMGetLedger& packet);
void recvLedger(newcoin::TMLedgerData& packet);
void recvStatus(newcoin::TMStatusChange& packet);
void getSessionCookie(std::string& strDst);
@@ -101,7 +105,7 @@ public:
void connect(const std::string strIp, int iPort);
void connected(const boost::system::error_code& error);
void detach();
void detach(const char *);
bool samePeer(Peer::pointer p) { return samePeer(*p); }
bool samePeer(const Peer& p) { return this == &p; }
@@ -118,6 +122,9 @@ public:
static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger);
static PackedMessage::pointer createValidation(Ledger::pointer ledger);
static PackedMessage::pointer createGetFullLedger(uint256& hash);
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
NewcoinAddress getNodePublic() const { return mNodePublic; }
};
#endif

View File

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

View File

@@ -253,7 +253,7 @@ Json::Value RPCServer::doNewAccount(Json::Value &params)
return JSONRPCError(500, "Family required");
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));
if(!account)

View File

@@ -11,9 +11,9 @@
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();
mTNByID[*root]=root;
mTNByID[*root] = root;
}
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
// produce a stack of nodes along the way, with the terminal node at the top
std::stack<SHAMapTreeNode::pointer> stack;
SHAMapTreeNode::pointer node=root;
SHAMapTreeNode::pointer node = root;
while(!node->isLeaf())
while (!node->isLeaf())
{
stack.push(node);
int branch=node->selectBranch(id);
assert(branch>=0);
int branch = node->selectBranch(id);
assert(branch >= 0);
uint256 hash=node->getChildHash(branch);
if(hash.isZero()) return stack;
uint256 hash = node->getChildHash(branch);
if (hash.isZero()) return stack;
node=getNode(node->getChildNodeID(branch), hash, false);
if(!node)
node = getNode(node->getChildNodeID(branch), hash, false);
if (!node)
{
if(isSynching()) return stack;
if (isSynching()) return stack;
throw SHAMapException(MissingNode);
}
}
if(include_nonmatching_leaf || (node->peekItem()->getTag()==id))
if (include_nonmatching_leaf || (node->peekItem()->getTag() == id))
stack.push(node);
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
// 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();
stack.pop();
assert(node->isInnerNode());
int branch=node->selectBranch(target);
assert(branch>=0);
int branch = node->selectBranch(target);
assert(branch >= 0);
returnNode(node, true);
if(!node->setChildHash(branch, prevHash))
if (!node->setChildHash(branch, prevHash))
{
std::cerr << "dirtyUp terminates early" << std::endl;
assert(false);
@@ -73,44 +73,44 @@ void SHAMap::dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256&
#ifdef ST_DEBUG
std::cerr << "dirtyUp sets branch " << branch << " to " << prevHash.GetHex() << std::endl;
#endif
prevHash=node->getNodeHash();
prevHash = node->getNodeHash();
assert(prevHash.isNonZero());
}
}
SHAMapTreeNode::pointer SHAMap::checkCacheNode(const SHAMapNode& iNode)
{
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it=mTNByID.find(iNode);
if(it==mTNByID.end()) return SHAMapTreeNode::pointer();
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = mTNByID.find(iNode);
if (it == mTNByID.end()) return SHAMapTreeNode::pointer();
return it->second;
}
SHAMapTreeNode::pointer SHAMap::walkTo(const uint256& id, bool modify)
{ // 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);
if(inNode->isEmptyBranch(branch)) return inNode;
uint256 childHash=inNode->getChildHash(branch);
if(childHash.isZero()) return inNode;
int branch = inNode->selectBranch(id);
if (inNode->isEmptyBranch(branch)) return inNode;
uint256 childHash = inNode->getChildHash(branch);
if (childHash.isZero()) return inNode;
SHAMapTreeNode::pointer nextNode=getNode(inNode->getChildNodeID(branch), childHash, false);
if(!nextNode) throw SHAMapException(MissingNode);
inNode=nextNode;
SHAMapTreeNode::pointer nextNode = getNode(inNode->getChildNodeID(branch), childHash, false);
if (!nextNode) throw SHAMapException(MissingNode);
inNode = nextNode;
}
if(modify) returnNode(inNode, true);
if (inNode->getTag() != id) return SHAMapTreeNode::pointer();
if (modify) returnNode(inNode, true);
return inNode;
}
SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& hash, bool modify)
{ // retrieve a node whose node hash is known
SHAMapTreeNode::pointer node=checkCacheNode(id);
if(node)
SHAMapTreeNode::pointer node = checkCacheNode(id);
if (node)
{
if(node->getNodeHash()!=hash)
if (node->getNodeHash()!=hash)
{
#ifdef DEBUG
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;
if(!fetchNode(hash, nodeData)) return SHAMapTreeNode::pointer();
node=boost::make_shared<SHAMapTreeNode>(id, nodeData, mSeq);
if(node->getNodeHash()!=hash) throw SHAMapException(InvalidNode);
node = boost::make_shared<SHAMapTreeNode>(id, nodeData, mSeq);
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);
return node;
}
@@ -139,15 +139,15 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has
void SHAMap::returnNode(SHAMapTreeNode::pointer& node, bool modify)
{ // make sure the node is suitable for the intended operation (copy on write)
assert(node->isValid());
if(node && modify && (node->getSeq()!=mSeq))
if (node && modify && (node->getSeq()!=mSeq))
{
#ifdef DEBUG
std::cerr << "returnNode COW" << std::endl;
#endif
if(mDirtyNodes) (*mDirtyNodes)[*node]=node;
node=boost::make_shared<SHAMapTreeNode>(*node, mSeq);
if (mDirtyNodes) (*mDirtyNodes)[*node] = node;
node = boost::make_shared<SHAMapTreeNode>(*node, mSeq);
assert(node->isValid());
mTNByID[*node]=node;
mTNByID[*node] = node;
}
}
@@ -163,24 +163,24 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode::pointer node)
#endif
do
{ // Walk down the tree
if(node->hasItem()) return node->peekItem();
if (node->hasItem()) return node->peekItem();
bool foundNode=false;
for(int i=0; i<16; i++)
if(!node->isEmptyBranch(i))
bool foundNode = false;
for (int i = 0; i < 16; ++i)
if (!node->isEmptyBranch(i))
{
#ifdef ST_DEBUG
std::cerr << " FB: node " << node->getString() << std::endl;
std::cerr << " has non-empty branch " << i << " : " <<
node->getChildNodeID(i).getString() << ", " << node->getChildHash(i).GetHex() << std::endl;
#endif
node=getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if(!node) throw SHAMapException(MissingNode);
foundNode=true;
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if (!node) throw SHAMapException(MissingNode);
foundNode = true;
break;
}
if(!foundNode) return SHAMapItem::pointer();
} while(1);
if (!foundNode) return SHAMapItem::pointer();
} while (1);
}
SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode::pointer node)
@@ -191,46 +191,46 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode::pointer node)
do
{ // Walk down the tree
if(node->hasItem()) return node->peekItem();
if (node->hasItem()) return node->peekItem();
bool foundNode=false;
for(int i=15; i>=0; i++)
if(!node->isEmptyBranch(i))
bool foundNode = false;
for (int i = 15; i >= 0; ++i)
if (!node->isEmptyBranch(i))
{
node=getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if(!node) throw SHAMapException(MissingNode);
foundNode=true;
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if (!node) throw SHAMapException(MissingNode);
foundNode = true;
break;
}
if(!foundNode) return SHAMapItem::pointer();
} while(1);
if (!foundNode) return SHAMapItem::pointer();
} while (1);
}
SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode::pointer node)
{
// If there is only one item below this node, return it
bool found;
while(!node->isLeaf())
while (!node->isLeaf())
{
found=false;
found = false;
SHAMapTreeNode::pointer nextNode;
for(int i=0; i<16; i++)
if(!node->isEmptyBranch(i))
for (int i = 0; i < 16; ++i)
if (!node->isEmptyBranch(i))
{
if(found) return SHAMapItem::pointer(); // two leaves below
nextNode=getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if(!nextNode) throw SHAMapException(MissingNode);
found=true;
if( found) return SHAMapItem::pointer(); // two leaves below
nextNode = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
if (!nextNode) throw SHAMapException(MissingNode);
found = true;
}
if(!found)
if (!found)
{
std::cerr << node->getString() << std::endl;
assert(false);
return SHAMapItem::pointer();
}
node=nextNode;
node = nextNode;
}
assert(node->hasItem());
return node->peekItem();
@@ -342,7 +342,7 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id)
bool SHAMap::hasItem(const uint256& 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);
if(!leaf) return false;
SHAMapItem::pointer item=leaf->peekItem();
@@ -472,7 +472,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction)
node->makeInner();
int b1, b2;
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
#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;
for(int i=0; i<32; i++)
vuc.push_back((unsigned char) i);
for (int i = 0; i < 32; ++i)
vuc.push_back(static_cast<unsigned char>(v));
return vuc;
}
@@ -675,4 +675,4 @@ bool SHAMap::TestSHAMap()
return false;
return true;
}
// vim:ts=4

View File

@@ -40,14 +40,14 @@ public:
SHAMapNode(int depth, const uint256& hash);
int getDepth() const { return mDepth; }
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; }
SHAMapNode getParentNodeID() const
{
assert(mDepth);
return SHAMapNode(mDepth-1, mNodeID);
return SHAMapNode(mDepth - 1, mNodeID);
}
SHAMapNode getChildNodeID(int m) const;
int selectBranch(const uint256& hash) const;
@@ -108,18 +108,18 @@ public:
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 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 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; }
virtual void dump();
};
@@ -132,10 +132,10 @@ public:
enum TNType
{
tnERROR =0,
tnINNER =1,
tnTRANSACTION =2,
tnACCOUNT_STATE =3
tnERROR = 0,
tnINNER = 1,
tnTRANSACTION = 2,
tnACCOUNT_STATE = 3
};
private:
@@ -251,11 +251,11 @@ protected:
bool walkBranch(SHAMapTreeNode::pointer node, SHAMapItem::pointer otherMapItem, bool isFirstMap,
SHAMapDiff& differences, int& maxCount);
public:
// build new map
SHAMap(uint32 seq=0);
SHAMap(uint32 seq = 0);
// hold the map stable across operations
ScopedLock Lock() const { return ScopedLock(mLock); }
@@ -295,7 +295,7 @@ public:
// status functions
void setImmutable(void) { assert(mState != Invalid); mState = Immutable; }
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 setFloating(void) { mState = Floating; }
void clearSynching(void) { mState = Modifying; }
@@ -315,6 +315,11 @@ public:
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 syncTest();
bool deepCompare(SHAMap& other);
@@ -322,3 +327,4 @@ public:
};
#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)
{
if(len<33) mDepth=-1;
if (len < 33) mDepth = -1;
else
{
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
{ // This can be optimized to avoid the << if needed
assert((m>=0) && (m<16));
assert((m >= 0) && (m < 16));
uint256 child(mNodeID);
child.PeekAt(mDepth/8) |= m << (4*(mDepth%8));
return SHAMapNode(mDepth+1, child);
child.PeekAt(mDepth / 8) |= m << (4 * (mDepth % 8));
return SHAMapNode(mDepth + 1, child);
}
int SHAMapNode::selectBranch(const uint256& hash) const
{ // Which branch would contain the specified hash
if(mDepth==63)
if (mDepth == 63)
{
assert(false);
return -1;
}
if((hash&smMasks[mDepth])!=mNodeID)
if ((hash & smMasks[mDepth]) != mNodeID)
{
std::cerr << "selectBranch(" << getString() << 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
}
int branch=*(hash.begin()+(mDepth/2));
if(mDepth%2) branch>>=4;
else branch&=0xf;
int branch = *(hash.begin() + (mDepth / 2));
if (mDepth % 2) branch >>= 4;
else branch &= 0xf;
assert(branch>=0 && branch<16);
assert((branch >= 0) && (branch < 16));
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)
{
if(node.mItem)
mItem=boost::make_shared<SHAMapItem>(*node.mItem);
mItem = boost::make_shared<SHAMapItem>(*node.mItem);
else
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) :
SHAMapNode(node), mItem(item), mSeq(seq), mType(type), mFullBelow(true)
{
assert(item->peekData().size()>=12);
assert(item->peekData().size() >= 12);
updateHash();
}
@@ -181,41 +181,41 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
{
Serializer s(rawNode);
int type=s.removeLastByte();
int len=s.getLength();
if( (type<0) || (type>3) || (len<32) ) throw SHAMapException(InvalidNode);
int type = s.removeLastByte();
int len = s.getLength();
if ((type < 0) || (type > 3) || (len < 32)) throw SHAMapException(InvalidNode);
if(type==0)
if (type == 0)
{ // transaction
mItem=boost::make_shared<SHAMapItem>(s.getSHA512Half(), s.peekData());
mType=tnTRANSACTION;
mItem = boost::make_shared<SHAMapItem>(s.getSHA512Half(), s.peekData());
mType = tnTRANSACTION;
}
else if(type==1)
else if (type == 1)
{ // account state
uint256 u;
s.get256(u, len-32);
s.chop(256/8);
if(u.isZero()) throw SHAMapException(InvalidNode);
mItem=boost::make_shared<SHAMapItem>(u, s.peekData());
mType=tnACCOUNT_STATE;
s.get256(u, len - 32);
s.chop(256 / 8);
if (u.isZero()) throw SHAMapException(InvalidNode);
mItem = boost::make_shared<SHAMapItem>(u, s.peekData());
mType = tnACCOUNT_STATE;
}
else if(type==2)
else if (type == 2)
{ // full inner
if(len!=512) throw SHAMapException(InvalidNode);
for(int i=0; i<16; i++)
s.get256(mHashes[i], i*32);
mType=tnINNER;
if (len != 512) throw SHAMapException(InvalidNode);
for (int i = 0; i < 16; ++i)
s.get256(mHashes[i], i * 32);
mType = tnINNER;
}
else if(type==3)
else if (type == 3)
{ // compressed inner
for(int i=0; i<(len/33); i++)
for (int i = 0; i < (len / 33); ++i)
{
int pos;
s.get8(pos, 32+(i*33));
if( (pos<0) || (pos>=16)) throw SHAMapException(InvalidNode);
s.get256(mHashes[pos], i*33);
s.get8(pos, 32 + (i * 33));
if ((pos < 0) || (pos >= 16)) throw SHAMapException(InvalidNode);
s.get256(mHashes[pos], i * 33);
}
mType=tnINNER;
mType = tnINNER;
}
updateHash();
@@ -223,17 +223,17 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
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);
s.add8(0);
assert(s.getLength()>32);
assert(s.getLength() > 32);
return;
}
if(mType==tnACCOUNT_STATE)
if (mType == tnACCOUNT_STATE)
{
mItem->addRaw(s);
s.add256(mItem->getTag());
@@ -241,10 +241,10 @@ void SHAMapTreeNode::addRaw(Serializer &s)
return;
}
if(getBranchCount()<12)
if (getBranchCount() < 12)
{ // compressed node
for(int i=0; i<16; i++)
if(mHashes[i].isNonZero())
for (int i = 0; i < 16; ++i)
if (mHashes[i].isNonZero())
{
s.add256(mHashes[i]);
s.add8(i);
@@ -253,7 +253,7 @@ void SHAMapTreeNode::addRaw(Serializer &s)
return;
}
for(int i=0; i<16; i++)
for (int i = 0; i < 16; ++i)
s.add256(mHashes[i]);
s.add8(2);
}
@@ -262,44 +262,44 @@ bool SHAMapTreeNode::updateHash()
{
uint256 nh;
if(mType==tnINNER)
if (mType == tnINNER)
{
bool empty=true;
for(int i=0; i<16; i++)
if(mHashes[i].isNonZero())
bool empty = true;
for (int i = 0; i < 16; ++i)
if (mHashes[i].isNonZero())
{
empty=false;
empty = false;
break;
}
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;
mItem->addRaw(s);
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);
if(nh==mHash) return false;
mHash=nh;
if (nh == mHash) return false;
mHash = nh;
return true;
}
bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type)
{
uint256 hash=getNodeHash();
mType=type;
mItem=i;
uint256 hash = getNodeHash();
mType = type;
mItem = i;
assert(isLeaf());
updateHash();
return getNodeHash()==hash;
return getNodeHash() == hash;
}
SHAMapItem::pointer SHAMapTreeNode::getItem() const
@@ -311,17 +311,17 @@ SHAMapItem::pointer SHAMapTreeNode::getItem() const
int SHAMapTreeNode::getBranchCount() const
{
assert(isInner());
int ret=0;
for(int i=0; i<16; ++i)
if(mHashes[i].isNonZero()) ++ret;
int ret = 0;
for (int i = 0; i < 16; ++i)
if (mHashes[i].isNonZero()) ++ret;
return ret;
}
void SHAMapTreeNode::makeInner()
{
mItem=SHAMapItem::pointer();
mItem = SHAMapItem::pointer();
memset(mHashes, 0, sizeof(mHashes));
mType=tnINNER;
mType = tnINNER;
mHash.zero();
}
@@ -332,39 +332,40 @@ void SHAMapTreeNode::dump()
std::string SHAMapTreeNode::getString() const
{
std::string ret="NodeID(";
ret+=boost::lexical_cast<std::string>(getDepth());
ret+=",";
ret+=getNodeID().GetHex();
ret+=")";
if(isInner())
std::string ret = "NodeID(";
ret += boost::lexical_cast<std::string>(getDepth());
ret += ",";
ret += getNodeID().GetHex();
ret += ")";
if (isInner())
{
for(int i=0; i<16; i++)
if(!isEmptyBranch(i))
for(int i = 0; i < 16; ++i)
if (!isEmptyBranch(i))
{
ret+=",b";
ret+=boost::lexical_cast<std::string>(i);
ret += ",b";
ret += boost::lexical_cast<std::string>(i);
}
}
if(isLeaf())
if (isLeaf())
{
ret+=",leaf";
ret += ",leaf";
}
return ret;
}
bool SHAMapTreeNode::setChildHash(int m, const uint256 &hash)
{
assert( (m>=0) && (m<16) );
assert(mType==tnINNER);
if(mHashes[m]==hash)
assert((m >= 0) && (m < 16));
assert(mType == tnINNER);
if(mHashes[m] == hash)
return false;
mHashes[m]=hash;
mHashes[m] = hash;
return updateHash();
}
const uint256& SHAMapTreeNode::getChildHash(int m) const
{
assert( (m>=0) && (m<16) && (mType==tnINNER) );
assert((m >= 0) && (m < 16) && (mType == tnINNER));
return mHashes[m];
}
// vim:ts=4

View File

@@ -348,6 +348,26 @@ static bool confuseMap(SHAMap &map, int count)
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()
{
unsigned int seed;

View File

@@ -39,7 +39,7 @@ std::string SerializedLedgerEntry::getFullText() const
ret += mIndex.GetHex();
ret += "\" = { ";
ret += mFormat->t_name;
ret += ", ";
ret += ", ";
ret += mObject.getFullText();
ret += "}";
return ret;
@@ -71,3 +71,4 @@ bool SerializedLedgerEntry::isEquivalent(const SerializedType& t) const
if (mObject != v->mObject) return false;
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<TaggedListItem> getIFieldTL(SOE_Field field) const { return mObject.getValueFieldTL(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 setIFieldU32(SOE_Field field, uint32 v) { return mObject.setValueFieldU32(field, v); }
void setIFieldU64(SOE_Field field, uint32 v) { return mObject.setValueFieldU64(field, v); }
@@ -74,3 +74,4 @@ public:
};
#endif
// vim:ts=4

View File

@@ -467,6 +467,16 @@ void STObject::setValueFieldH160(SOE_Field field, const uint160& 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)
{
SerializedType* rf = getPField(field);

View File

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

View File

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

View File

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

View File

@@ -5,6 +5,7 @@
#include "SerializedObject.h"
#include "TransactionFormats.h"
#include "NewcoinAddress.h"
#include "utils.h"
std::string SerializedType::getFullText() const
{
@@ -133,18 +134,14 @@ bool STHash256::isEquivalent(const SerializedType& t) const
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;
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);
value = st.getVL();
}
std::string STVariableLength::getText() const
{
return hex(value);
return strHex(value);
}
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 += ",";
ret += hex(it->second);
ret += strHex(it->second);
}
return ret;
}

View File

@@ -66,7 +66,7 @@ public:
STUInt8(unsigned char v=0) : 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; }
SerializedTypeID getSType() const { return STI_UINT8; }
@@ -91,7 +91,7 @@ public:
STUInt16(uint16 v=0) : 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; }
SerializedTypeID getSType() const { return STI_UINT16; }
@@ -116,7 +116,7 @@ public:
STUInt32(uint32 v=0) : 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; }
SerializedTypeID getSType() const { return STI_UINT32; }
@@ -141,7 +141,7 @@ public:
STUInt64(uint64 v=0) : 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; }
SerializedTypeID getSType() const { return STI_UINT64; }
@@ -247,10 +247,11 @@ protected:
public:
STHash128(const uint128& v=uint128()) : value(v) { ; }
STHash128(const char *n, const uint128& v=uint128()) : SerializedType(n), value(v) { ; }
STHash128(const uint128& v) : value(v) { ; }
STHash128(const char *n, const uint128& v) : SerializedType(n), value(v) { ; }
STHash128(const char *n) : SerializedType(n) { ; }
STHash128() { ; }
static STHash128* construct(SerializerIterator&, const char *name=NULL);
static STHash128* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 20; }
SerializedTypeID getSType() const { return STI_HASH128; }
@@ -273,10 +274,11 @@ protected:
public:
STHash160(const uint160& v=uint160()) : value(v) { ; }
STHash160(const char *n, const uint160& v=uint160()) : SerializedType(n), value(v) { ; }
STHash160(const uint160& v) : value(v) { ; }
STHash160(const char *n, const uint160& v) : SerializedType(n), value(v) { ; }
STHash160(const char *n) : SerializedType(n) { ; }
STHash160() { ; }
static STHash160* construct(SerializerIterator&, const char *name=NULL);
static STHash160* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 20; }
SerializedTypeID getSType() const { return STI_HASH160; }
@@ -300,9 +302,10 @@ protected:
public:
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() { ; }
static STHash256* construct(SerializerIterator&, const char *name=NULL);
static STHash256* construct(SerializerIterator&, const char *name = NULL);
int getLength() const { return 32; }
SerializedTypeID getSType() const { return STI_HASH256; }
@@ -328,8 +331,9 @@ public:
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) : SerializedType(n) { ; }
STVariableLength(SerializerIterator&, const char *name = NULL);
STVariableLength() { ; }
static STVariableLength* construct(SerializerIterator&, const char *name=NULL);
static STVariableLength* construct(SerializerIterator&, const char *name = NULL);
int getLength() const;
virtual SerializedTypeID getSType() const { return STI_VL; }
@@ -380,7 +384,7 @@ public:
STTaggedList(const char *n) : SerializedType(n) { ; }
STTaggedList(const std::vector<TaggedListItem>& v) : 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;
SerializedTypeID getSType() const { return STI_TL; }
@@ -406,3 +410,4 @@ public:
};
#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
{
if ((offset + 2) > mData.size()) return false;
o = mData.at(offset++);
o <<= 8; o |= mData.at(offset);
const unsigned char *ptr = &mData[offset];
o = *ptr++; o <<= 8; o |= *ptr;
return true;
}
bool Serializer::get32(uint32& o, int offset) const
{
if ((offset + 4) > mData.size()) return false;
o=mData.at(offset++);
o<<=8; o |= mData.at(offset++); o <<= 8; o |= mData.at(offset++);
o<<=8; o |= mData.at(offset);
const unsigned char *ptr = &mData[offset];
o = *ptr++;
o <<= 8; o |= *ptr++;
o <<= 8; o |= *ptr++;
o <<= 8; o |= *ptr;
return true;
}
bool Serializer::get64(uint64& o, int offset) const
{
if ((offset + 8) > mData.size()) return false;
o=mData.at(offset++);
o<<=8; o|= mData.at(offset++); o <<= 8; o |= mData.at(offset++);
o<<=8; o|= mData.at(offset++); o <<= 8; o |= mData.at(offset++);
o<<=8; o|= mData.at(offset++); o <<= 8; o |= mData.at(offset++);
o<<=8; o|= mData.at(offset);
const unsigned char *ptr = &mData[offset];
o = *ptr++;
o <<= 8; o |= *ptr++; o <<= 8; o |= *ptr++;
o <<= 8; o |= *ptr++; o <<= 8; o |= *ptr++;
o <<= 8; o |= *ptr++; o <<= 8; o |= *ptr++;
o <<= 8; o |= *ptr;
return true;
}
@@ -172,7 +175,7 @@ int Serializer::removeLastByte()
bool Serializer::getRaw(std::vector<unsigned char>& o, int offset, int length) const
{
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;
}
@@ -233,12 +236,12 @@ bool Serializer::checkSignature(int pubkeyOffset, int signatureOffset) const
CKey pubCKey;
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
{
return key.Verify(getSHA512Half(), signature);
return key.Verify(getSHA512Half(), signature);
}
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()));
addRaw(vector);
assert(mData.size() + (ret + vector.size() + encodeLengthLength(vector.size())));
assert(mData.size() == (ret + vector.size() + encodeLengthLength(vector.size())));
return ret;
}
@@ -362,12 +365,12 @@ bool Serializer::getVLLength(int& length, int offset) const
try
{
if (lenLen == 1)
length=decodeVLLength(b1);
length = decodeVLLength(b1);
else if (lenLen == 2)
{
int b2;
if (!get8(b2, offset++)) return false;
length=decodeVLLength(b1, b2);
length = decodeVLLength(b1, b2);
}
else if (lenLen == 3)
{
@@ -391,7 +394,7 @@ bool Serializer::getTaggedList(std::list<TaggedListItem>& list, int offset, int&
int startOffset = offset;
int numElem;
if (!get8(numElem, offset++)) return false;
for (int i = 0; i<numElem; i++)
for (int i = 0; i<numElem; ++i)
{
int tag, len;
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
{
list.clear();
int startOffset=offset;
int startOffset = offset;
int numElem;
if (!get8(numElem, offset++)) return false;
for (int i=0; i<numElem; i++)
for (int i = 0; i<numElem; ++i)
{
int tag, len;
std::vector<unsigned char> data;
@@ -502,7 +505,7 @@ unsigned char SerializerIterator::get8()
{
int val;
if (!mSerializer.get8(val, mPos)) throw std::runtime_error("invalid serializer get8");
mPos++;
++mPos;
return val;
}
@@ -510,7 +513,7 @@ uint16 SerializerIterator::get16()
{
uint16 val;
if (!mSerializer.get16(val, mPos)) throw std::runtime_error("invalid serializer get16");
mPos += 16/8;
mPos += 16 / 8;
return val;
}
@@ -518,7 +521,7 @@ uint32 SerializerIterator::get32()
{
uint32 val;
if (!mSerializer.get32(val, mPos)) throw std::runtime_error("invalid serializer get32");
mPos += 32/8;
mPos += 32 / 8;
return val;
}
@@ -526,7 +529,7 @@ uint64 SerializerIterator::get64()
{
uint64 val;
if (!mSerializer.get64(val, mPos)) throw std::runtime_error("invalid serializer get64");
mPos += 64/8;
mPos += 64 / 8;
return val;
}
@@ -534,7 +537,7 @@ uint128 SerializerIterator::get128()
{
uint128 val;
if (!mSerializer.get128(val, mPos)) throw std::runtime_error("invalid serializer get128");
mPos += 128/8;
mPos += 128 / 8;
return val;
}
@@ -542,7 +545,7 @@ uint160 SerializerIterator::get160()
{
uint160 val;
if (!mSerializer.get160(val, mPos)) throw std::runtime_error("invalid serializer get160");
mPos += 160/8;
mPos += 160 / 8;
return val;
}
@@ -550,7 +553,7 @@ uint256 SerializerIterator::get256()
{
uint256 val;
if (!mSerializer.get256(val, mPos)) throw std::runtime_error("invalid serializer get256");
mPos += 256/8;
mPos += 256 / 8;
return val;
}
@@ -571,3 +574,4 @@ std::vector<TaggedListItem> SerializerIterator::getTaggedList()
mPos += length;
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();
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());
assert(mTransaction->getSequence() != 0);
@@ -105,6 +112,7 @@ Transaction::Transaction(const std::vector<unsigned char>& raw, bool validate) :
mStatus = NEW;
}
#if 0
Transaction::Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toID,
CKey::pointer pubKey, uint64 amount, uint64 fee, uint32 fromSeq, uint32 fromLedger,
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->setSignature(signature);
mTransaction->setTransactionFee(fee);
mTransaction->setSigningPubKey(pubKey->GetPubKey());
mTransaction->setSigningPubKey(pubKey); // BROKEN
mTransaction->setSourceAccount(mAccountFrom); // BROKEN
mTransaction->setSequence(fromSeq);
if (fromLedger != 0)
{
@@ -129,6 +138,7 @@ Transaction::Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toI
mTransaction->setITFieldAccount(sfDestination, toID.getAccountID());
updateID();
}
#endif
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);
sql.append(rawTxn);
sql.append(");");
ScopedLock sl(theApp->getTxnDB()->getDBLock());
Database* db = theApp->getTxnDB()->getDB();
return db->executeSQL(sql.c_str());
return db->executeSQL(sql);
}
Transaction::pointer Transaction::transactionFromSQL(const std::string& sql)
@@ -237,12 +247,11 @@ Transaction::pointer Transaction::transactionFromSQL(const std::string& sql)
std::string status;
rawTxn.reserve(2048);
if(1)
{
ScopedLock sl(theApp->getTxnDB()->getDBLock());
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();
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);
TransStatus st(INVALID);
switch(status[0])
switch (status[0])
{
case 'N': st = NEW; break;
case 'A': st = INCLUDED; break;
@@ -340,7 +349,7 @@ static bool isHex(char j)
if ((j >= 'a') && (j <= 'f')) return true;
return false;
}
bool Transaction::isHexTxID(const std::string& txid)
{
if (txid.size() != 64) return false;
@@ -382,3 +391,4 @@ Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const
return ret;
}
// vim:ts=4

View File

@@ -6,21 +6,63 @@
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
TransactionEngineParams params)
{
TransactionEngineResult result = terSUCCESS;
uint256 txID = txn.getTransactionID();
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;
if (!acctKey.SetPubKey(txn.peekSigningPubKey())) return terINVALID;
// check signature
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();
if ( (params & tepNO_CHECK_FEE) != tepNONE)
{
// WRITEME: Check if fee is adequate
if (txnFee == 0) return terINSUF_FEE_P;
if (bPrepaid)
{
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
@@ -30,39 +72,59 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
boost::recursive_mutex::scoped_lock sl(mLedger->mLock);
// find source account
// If we are only verifying some transactions, this would be probablistic.
LedgerStateParms qry = lepNONE;
SerializedLedgerEntry::pointer src = mLedger->getAccountRoot(qry, srcAccount);
if (!src) return terNO_ACCOUNT;
// deduct the fee, so it's not available during the transaction
// we only write the account back if the transaction succeeds
uint64 balance = src->getIFieldU64(sfBalance);
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)
if (txnFee)
{
// 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;
uint64 balance = src->getIFieldU64(sfBalance);
if (balance < txnFee)
return terINSUF_FEE_B;
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;
accounts.push_back(std::make_pair(taaMODIFY, src));
TransactionEngineResult result = terUNKNOWN;
switch(txn.getTxnType())
{
case ttINVALID:
result = terINVALID;
break;
case ttCLAIM:
result = doClaim(txn, accounts);
break;
case ttMAKE_PAYMENT:
result = doPayment(txn, accounts);
break;
@@ -85,8 +147,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
// WRITEME: Special case code for changing transaction key
for(std::vector<AffectedAccount>::iterator it=accounts.begin(), end=accounts.end();
it != end; ++it)
{
if ( (it->first==taaMODIFY) || (it->first==taaCREATE) )
{ if (it->first == taaCREATE)
{
if (mLedger->writeBack(lepCREATE, it->second) & lepERROR)
assert(false);
}
else if (it->first==taaMODIFY)
{
if(mLedger->writeBack(lepNONE, it->second) & lepERROR)
assert(false);
@@ -106,6 +172,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
return result;
}
TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
return terUNKNOWN;
}
TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn,
std::vector<AffectedAccount>& accounts)
{
@@ -187,3 +259,4 @@ TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction&
{
return terUNKNOWN;
}
// vim:ts=4

View File

@@ -25,6 +25,7 @@ enum TransactionEngineResult
terUNFUNDED, // Source account had insufficient balance for transactin
terNO_PATH, // No path existed or met transaction/balance requirements
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
terPAST_LEDGER, // The transaction expired and can't be applied
};
@@ -51,13 +52,14 @@ class TransactionEngine
protected:
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 doOffer(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doTake(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doCancel(const SerializedTransaction&, std::vector<AffectedAccount>&);
TransactionEngineResult doPayment(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:
TransactionEngine() { ; }
@@ -80,3 +82,4 @@ inline TransactionEngineParams operator&(const TransactionEngineParams& l1, cons
}
#endif
// vim:ts=4

View File

@@ -13,7 +13,14 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 2 },
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 4 },
{ 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 } }
},
{ "Invoice", ttINVOICE, {
@@ -25,7 +32,7 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 4 },
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 8 },
{ 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 } }
},
{ "Offer", ttEXCHANGE_OFFER, {
@@ -39,7 +46,7 @@ TransactionFormat InnerTxnFormats[]=
{ S_FIELD(TargetLedger), STI_UINT32, SOE_IFFLAG, 32 },
{ S_FIELD(ExpireLedger), STI_UINT32, SOE_IFFLAG, 64 },
{ 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 } }
},
{ NULL, ttINVALID }
@@ -55,3 +62,4 @@ TransactionFormat* getTxnFormat(TransactionType t)
}
return NULL;
}
// vim:ts=4

View File

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

View File

@@ -22,3 +22,4 @@ public:
};
#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(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);
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);
string sql=strprintf("SELECT ValidationID,seqnum from Validations where LedgerIndex=%d and hanko=%s",
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())
{
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());
}
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);
}
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);
// TODO: ValidationCollection::getValidations(uint32 ledgerIndex)
}
@@ -203,7 +196,6 @@ bool ValidationCollection::getConsensusLedger(uint32 ledgerIndex, uint256& ourHa
bool ret=false;
if(mIndexGroups.count(ledgerIndex))
{
unsigned int maxVotes=theConfig.MIN_VOTES_FOR_CONSENSUS;
vector< Group >& groups=mIndexGroups[ledgerIndex];
Group empty;
@@ -228,6 +220,7 @@ bool ValidationCollection::getConsensusLedger(uint32 ledgerIndex, uint256& ourHa
}
}
}
return(ret);
}
// vim:ts=4

View File

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

View File

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

View File

@@ -10,7 +10,6 @@ enum MessageType {
mtGET_CONTACTS= 10;
mtCONTACT= 11;
// operations for 'small' nodes
mtSEARCH_TRANSACTION= 20;
mtGET_ACCOUNT= 21;
@@ -22,6 +21,7 @@ enum MessageType {
mtLEDGER= 32;
mtPROPOSE_LEDGER= 33;
mtCLOSE_LEDGER= 35;
mtSTATUS_CHANGE= 36;
// data replication and synchronization
mtGET_VALIDATIONS= 40;
@@ -41,7 +41,8 @@ message TMHello {
optional bytes nodePublic = 4; // node may opt to remain anonymous
optional bytes nodeProof = 5;
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;
}
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 {
required uint32 closingSeq = 1;
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);
strHex(strDer, strBuf);
strDer = strHex(strBuf);
}
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);
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);
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+1] = charHex(c & 15);
}
return strDst;
}
inline void strHex(std::string& strDst, const std::string& strSrc) {
strHex(strDst, strSrc.begin(), strSrc.size());
inline const std::string strHex(const std::string& strSrc) {
return strHex(strSrc.begin(), strSrc.size());
}
inline void strHex(std::string& strDst, const std::vector<unsigned char> vchData) {
strHex(strDst, vchData.begin(), vchData.size());
inline std::string strHex(const std::vector<unsigned char> vchData) {
return strHex(vchData.begin(), vchData.size());
}
int charUnHex(char cDigit);