Merge branch 'master' of github.com:jedmccaleb/NewCoin

This commit is contained in:
jed
2012-11-01 00:57:47 -07:00
41 changed files with 610 additions and 119 deletions

View File

@@ -136,8 +136,8 @@ UInt160.json_rewrite = function (j) {
// Return a new UInt160 from j.
UInt160.from_json = function (j) {
return 'string' === typeof j
? (new UInt160()).parse_json(j)
: j.clone();
? (new UInt160()).parse_json(j)
: j.clone();
};
UInt160.prototype.clone = function() {
@@ -232,8 +232,15 @@ var Currency = function () {
this.value = NaN;
}
// Given "USD" return the json.
Currency.json_rewrite = function(j) {
return Currency.from_json(j).to_json();
};
Currency.from_json = function (j) {
return (new Currency()).parse_json(j);
return 'string' === typeof j
? (new Currency()).parse_json(j)
: j.clone();
};
Currency.prototype.clone = function() {

View File

@@ -914,6 +914,17 @@ Transaction.prototype.submit = function () {
var self = this;
var transaction = this.transaction;
if ('string' !== typeof transaction.Account)
{
this.emit('error', {
'error' : 'invalidAccount',
'error_message' : 'Bad account.'
});
return;
}
// YYY Might check paths for invalid accounts.
if (undefined === transaction.Fee) {
if ('Payment' === transaction.TransactionType
&& transaction.Flags & Remote.flags.Payment.CreateAccount) {
@@ -980,6 +991,45 @@ Transaction.prototype.submit = function () {
// Set options for Transactions
//
Transaction._path_rewrite = function (path) {
var path_new = [];
for (var index in path) {
var node = path[index];
var node_new = {};
if ('account' in node)
node_new.account = UInt160.json_rewrite(node.account);
if ('issuer' in node)
node_new.issuer = UInt160.json_rewrite(node.issuer);
if ('currency' in node)
node_new.currency = Currency.json_rewrite(node.currency);
path_new.push(node_new);
}
return path_new;
}
Transaction.prototype.path_add = function (path) {
this.transaction.Paths = this.transaction.Paths || []
this.transaction.Paths.push(Transaction._path_rewrite(path));
return this;
}
// --> paths: undefined or array of path
// A path is an array of objects containing some combination of: account, currency, issuer
Transaction.prototype.paths = function (paths) {
for (var index in paths) {
this.path_add(paths[index]);
}
return this;
}
// If the secret is in the config object, it does not need to be provided.
Transaction.prototype.secret = function (secret) {
this.secret = secret;
@@ -987,7 +1037,7 @@ Transaction.prototype.secret = function (secret) {
Transaction.prototype.send_max = function (send_max) {
if (send_max)
this.transaction.SendMax = send_max.to_json();
this.transaction.SendMax = Amount.json_rewrite(send_max);
return this;
}
@@ -1105,6 +1155,13 @@ Transaction.prototype.password_set = function (src, authorized_key, generator, p
// --> src : UInt160 or String
// --> dst : UInt160 or String
// --> deliver_amount : Amount or String.
//
// Options:
// .paths()
// .path_add()
// .secret()
// .send_max()
// .set_flags()
Transaction.prototype.payment = function (src, dst, deliver_amount) {
this.secret = this._account_secret(src);
this.transaction.TransactionType = 'Payment';

View File

@@ -112,6 +112,7 @@
<ClCompile Include="src\HTTPRequest.cpp" />
<ClCompile Include="src\HttpsClient.cpp" />
<ClCompile Include="src\Interpreter.cpp" />
<ClCompile Include="src\InstanceCounter.cpp" />
<ClCompile Include="src\Ledger.cpp" />
<ClCompile Include="src\LedgerAcquire.cpp" />
<ClCompile Include="src\LedgerConsensus.cpp" />

View File

@@ -42,11 +42,13 @@ Application::Application() :
mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300),
mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL),
mHashNodeDB(NULL), mNetNodeDB(NULL),
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL)
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mSweepTimer(mAuxService)
{
RAND_bytes(mNonce256.begin(), mNonce256.size());
RAND_bytes(reinterpret_cast<unsigned char *>(&mNonceST), sizeof(mNonceST));
mJobQueue.setThreadCount();
mSweepTimer.expires_from_now(boost::posix_time::seconds(60));
mSweepTimer.async_wait(boost::bind(&Application::sweep, this));
}
extern const char *RpcDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[];
@@ -183,6 +185,16 @@ void Application::run()
std::cout << "Done." << std::endl;
}
void Application::sweep()
{
mMasterTransaction.sweep();
mHashedObjectStore.sweep();
mMasterLedger.sweep();
mTempNodeCache.sweep();
mSweepTimer.expires_from_now(boost::posix_time::seconds(60));
mSweepTimer.async_wait(boost::bind(&Application::sweep, this));
}
Application::~Application()
{
delete mTxnDB;

View File

@@ -66,6 +66,8 @@ class Application
uint256 mNonce256;
std::size_t mNonceST;
boost::asio::deadline_timer mSweepTimer;
std::map<std::string, Peer::pointer> mPeerMap;
boost::recursive_mutex mPeerMapLock;
@@ -93,8 +95,11 @@ public:
HashedObjectStore& getHashedObjectStore() { return mHashedObjectStore; }
ValidationCollection& getValidations() { return mValidations; }
JobQueue& getJobQueue() { return mJobQueue; }
SuppressionTable& getSuppression() { return mSuppressions; }
bool isNew(const uint256& s) { return mSuppressions.addSuppression(s); }
bool isNew(const uint160& s) { return mSuppressions.addSuppression(s); }
bool isNew(const uint256& s, uint64 p) { return mSuppressions.addSuppressionPeer(s, p); }
bool isNewFlag(const uint256& s, int f) { return mSuppressions.setFlag(s, f); }
bool running() { return mTxnDB != NULL; }
bool getSystemTimeOffset(int& offset) { return mSNTPClient.getOffset(offset); }
@@ -110,6 +115,7 @@ public:
void run();
void stop();
void sweep();
};
extern Application* theApp;

View File

@@ -29,6 +29,7 @@ void splitIpPort(const std::string& strIpPort, std::string& strIp, int& iPort)
}
ConnectionPool::ConnectionPool(boost::asio::io_service& io_service) :
mLastPeer(0),
mCtx(boost::asio::ssl::context::sslv23),
mScanTimer(io_service),
mPolicyTimer(io_service)
@@ -237,7 +238,7 @@ int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& m
BOOST_FOREACH(naPeer pair, mConnectedMap)
{
Peer::pointer peer = pair.second;
Peer::ref peer = pair.second;
if (!peer)
std::cerr << "CP::RM null peer in list" << std::endl;
else if ((!fromPeer || !(peer.get() == fromPeer)) && peer->isConnected())
@@ -250,6 +251,32 @@ int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& m
return sentTo;
}
void ConnectionPool::relayMessageBut(const std::set<uint64>& fromPeers, const PackedMessage::pointer& msg)
{ // Relay message to all but the specified peers
boost::mutex::scoped_lock sl(mPeerLock);
BOOST_FOREACH(naPeer pair, mConnectedMap)
{
Peer::ref peer = pair.second;
if (peer->isConnected() && (fromPeers.count(peer->getPeerId()) == 0))
peer->sendPacket(msg);
}
}
void ConnectionPool::relayMessageTo(const std::set<uint64>& fromPeers, const PackedMessage::pointer& msg)
{ // Relay message to the specified peers
boost::mutex::scoped_lock sl(mPeerLock);
BOOST_FOREACH(naPeer pair, mConnectedMap)
{
Peer::ref peer = pair.second;
if (peer->isConnected() && (fromPeers.count(peer->getPeerId()) > 0))
peer->sendPacket(msg);
}
}
// Schedule a connection via scanning.
//
// Add or modify into PeerIps as a manual entry for immediate scanning.
@@ -354,6 +381,12 @@ std::vector<Peer::pointer> ConnectionPool::getPeerVector()
return ret;
}
uint64 ConnectionPool::assignPeerId()
{
boost::mutex::scoped_lock sl(mPeerLock);
return ++mLastPeer;
}
// Now know peer's node public key. Determine if we want to stay connected.
// <-- bNew: false = redundant
bool ConnectionPool::peerConnected(Peer::ref peer, const RippleAddress& naPeer,

View File

@@ -1,6 +1,8 @@
#ifndef __CONNECTION_POOL__
#define __CONNECTION_POOL__
#include <set>
#include <boost/asio/ssl.hpp>
#include <boost/thread/mutex.hpp>
@@ -14,7 +16,8 @@
class ConnectionPool
{
private:
boost::mutex mPeerLock;
boost::mutex mPeerLock;
uint64 mLastPeer;
typedef std::pair<RippleAddress, Peer::pointer> naPeer;
typedef std::pair<ipPort, Peer::pointer> pipPeer;
@@ -59,6 +62,8 @@ public:
// Send message to network.
int relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg);
void relayMessageTo(const std::set<uint64>& fromPeers, const PackedMessage::pointer& msg);
void relayMessageBut(const std::set<uint64>& fromPeers, const PackedMessage::pointer& msg);
// Manual connection request.
// Queue for immediate scanning.
@@ -87,6 +92,9 @@ public:
Json::Value getPeersJson();
std::vector<Peer::pointer> getPeerVector();
// Peer 64-bit ID function
uint64 assignPeerId();
//
// Scanning
//

View File

@@ -9,6 +9,7 @@
#include "Log.h"
SETUP_LOG();
DECLARE_INSTANCE(HashedObject);
HashedObjectStore::HashedObjectStore(int cacheSize, int cacheAge) :
mCache(cacheSize, cacheAge), mWritePending(false)

View File

@@ -10,6 +10,9 @@
#include "uint256.h"
#include "ScopedLock.h"
#include "TaggedCache.h"
#include "InstanceCounter.h"
DEFINE_INSTANCE(HashedObject);
enum HashedObjectType
{
@@ -20,7 +23,7 @@ enum HashedObjectType
hotTRANSACTION_NODE = 4
};
class HashedObject
class HashedObject : private IS_INSTANCE(HashedObject)
{
public:
typedef boost::shared_ptr<HashedObject> pointer;
@@ -61,6 +64,7 @@ public:
void bulkWrite();
void waitWrite();
void sweep() { mCache.sweep(); }
};
#endif

15
src/InstanceCounter.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include "InstanceCounter.h"
InstanceType* InstanceType::sHeadInstance = NULL;
std::vector<InstanceType::InstanceCount> InstanceType::getInstanceCounts(int min)
{
std::vector<InstanceCount> ret;
for (InstanceType* i = sHeadInstance; i != NULL; i = i->mNextInstance)
{
int c = i->getCount();
if (c >= min)
ret.push_back(InstanceCount(i->getName(), c));
}
return ret;
}

80
src/InstanceCounter.h Normal file
View File

@@ -0,0 +1,80 @@
#ifndef INSTANCE_COUNTER__H
#define INSTANCE_COUNTER__H
#include <string>
#include <vector>
#include <boost/thread/mutex.hpp>
#define DEFINE_INSTANCE(x) \
extern InstanceType IT_##x; \
class Instance_##x : private Instance \
{ \
protected: \
Instance_##x() : Instance(IT_##x) { ; } \
Instance_##x(const Instance_##x &) : \
Instance(IT_##x) { ; } \
Instance_##x& operator=(const Instance_##x&) \
{ return *this; } \
}
#define DECLARE_INSTANCE(x) \
InstanceType IT_##x(#x);
#define IS_INSTANCE(x) Instance_##x
class InstanceType
{
protected:
int mInstances;
std::string mName;
boost::mutex mLock;
InstanceType* mNextInstance;
static InstanceType* sHeadInstance;
public:
typedef std::pair<std::string, int> InstanceCount;
InstanceType(const char *n) : mInstances(0), mName(n)
{
mNextInstance = sHeadInstance;
sHeadInstance = this;
}
void addInstance()
{
mLock.lock();
++mInstances;
mLock.unlock();
}
void decInstance()
{
mLock.lock();
--mInstances;
mLock.unlock();
}
int getCount()
{
boost::mutex::scoped_lock(mLock);
return mInstances;
}
const std::string& getName()
{
return mName;
}
static std::vector<InstanceCount> getInstanceCounts(int min = 1);
};
class Instance
{
protected:
InstanceType& mType;
public:
Instance(InstanceType& t) : mType(t) { mType.addInstance(); }
~Instance() { mType.decInstance(); }
};
#endif

View File

@@ -20,6 +20,7 @@
#include "Log.h"
SETUP_LOG();
DECLARE_INSTANCE(Ledger);
Ledger::Ledger(const RippleAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1),
mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0),
@@ -1072,7 +1073,7 @@ int Ledger::getPendingSaves()
void Ledger::pendSave(bool fromConsensus)
{
if (!fromConsensus && !theApp->isNew(getHash()))
if (!fromConsensus && !theApp->isNewFlag(getHash(), SF_SAVED))
return;
boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, shared_from_this(), fromConsensus));

View File

@@ -18,6 +18,7 @@
#include "types.h"
#include "BitcoinUtil.h"
#include "SHAMap.h"
#include "InstanceCounter.h"
enum LedgerStateParms
{
@@ -38,7 +39,9 @@ enum LedgerStateParms
#define LEDGER_JSON_DUMP_STATE 0x20000000
#define LEDGER_JSON_FULL 0x40000000
class Ledger : public boost::enable_shared_from_this<Ledger>
DEFINE_INSTANCE(Ledger);
class Ledger : public boost::enable_shared_from_this<Ledger>, public IS_INSTANCE(Ledger)
{ // The basic Ledger structure, can be opened, closed, or synching
friend class TransactionEngine;
public:

View File

@@ -845,7 +845,7 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec
txn->setVote(pit.first, cit->second->hasItem(txID));
}
if (!ourVote && theApp->isNew(txID))
if (!ourVote && theApp->isNewFlag(txID, SF_RELAYED))
{
ripple::TMTransaction msg;
msg.set_rawtransaction(&(tx.front()), tx.size());

View File

@@ -18,6 +18,7 @@ public:
Ledger::pointer getLedgerBySeq(uint32 index);
Ledger::pointer getLedgerByHash(const uint256& hash);
Ledger::pointer canonicalizeLedger(Ledger::pointer, bool cache);
void sweep() { mLedgersByHash.sweep(); }
};
#endif

View File

@@ -91,6 +91,8 @@ public:
void setLedgerRangePresent(uint32 minV, uint32 maxV) { mCompleteLedgers.setRange(minV, maxV); }
bool addHeldTransaction(const Transaction::pointer& trans);
void sweep(void) { mLedgerHistory.sweep(); }
};
#endif

View File

@@ -88,22 +88,31 @@ Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& t
tpTrans->getSTransaction()->add(s);
Transaction::pointer tpTransNew = Transaction::sharedTransaction(s.getData(), true);
assert(tpTransNew);
if(!tpTransNew->getSTransaction()->isEquivalent(*tpTrans->getSTransaction()))
if (!tpTransNew)
{
// Could not construct transaction.
nothing();
}
else if (tpTransNew->getSTransaction()->isEquivalent(*tpTrans->getSTransaction()))
{
(void) NetworkOPs::processTransaction(tpTransNew);
}
else
{
cLog(lsFATAL) << "Transaction reconstruction failure";
cLog(lsFATAL) << tpTransNew->getSTransaction()->getJson(0);
cLog(lsFATAL) << tpTrans->getSTransaction()->getJson(0);
assert(false);
}
(void) NetworkOPs::processTransaction(tpTransNew);
assert(false);
tpTransNew = Transaction::pointer();
}
return tpTransNew;
}
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source)
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans)
{
Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true);
if (dbtx) return dbtx;
@@ -151,27 +160,28 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
trans->setStatus(INCLUDED);
theApp->getMasterTransaction().canonicalize(trans, true);
// FIXME: Need code to get all accounts affected by a transaction and re-synch
// any of them that affect local accounts cached in memory. Or, we need to
// no cache the account balance information and always get it from the current ledger
// theApp->getWallet().applyTransaction(trans);
std::set<uint64> peers;
if (theApp->getSuppression().swapSet(trans->getID(), peers, SF_RELAYED))
{
ripple::TMTransaction tx;
Serializer s;
trans->getSTransaction()->add(s);
tx.set_rawtransaction(&s.getData().front(), s.getLength());
tx.set_status(ripple::tsCURRENT);
tx.set_receivetimestamp(getNetworkTimeNC());
ripple::TMTransaction tx;
Serializer s;
trans->getSTransaction()->add(s);
tx.set_rawtransaction(&s.getData().front(), s.getLength());
tx.set_status(ripple::tsCURRENT);
tx.set_receivetimestamp(getNetworkTimeNC());
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, ripple::mtTRANSACTION);
int sentTo = theApp->getConnectionPool().relayMessage(source, packet);
cLog(lsINFO) << "Transaction relayed to " << sentTo << " node(s)";
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, ripple::mtTRANSACTION);
theApp->getConnectionPool().relayMessageBut(peers, packet);
}
return trans;
}
cLog(lsDEBUG) << "Status other than success " << r;
if ((mMode != omFULL) && (mMode != omTRACKING) && (theApp->isNew(trans->getID())))
std::set<uint64> peers;
if ((mMode != omFULL) && (mMode != omTRACKING) &&
theApp->getSuppression().swapSet(trans->getID(), peers, SF_RELAYED))
{
ripple::TMTransaction tx;
Serializer s;
@@ -180,7 +190,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
tx.set_status(ripple::tsCURRENT);
tx.set_receivetimestamp(getNetworkTimeNC());
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, ripple::mtTRANSACTION);
theApp->getConnectionPool().relayMessage(source, packet);
theApp->getConnectionPool().relayMessageTo(peers, packet);
}
trans->setStatus(INVALID);
@@ -685,7 +695,7 @@ bool NetworkOPs::haveConsensusObject()
}
// <-- bool: true to relay
bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger,
bool NetworkOPs::recvPropose(uint64 peerId, uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger,
uint32 closeTime, const std::string& pubKey, const std::string& signature, const RippleAddress& nodePublic)
{
// JED: does mConsensus need to be locked?
@@ -701,7 +711,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons
s.add32(closeTime);
s.addRaw(pubKey);
s.addRaw(signature);
if (!theApp->isNew(s.getSHA512Half()))
if (!theApp->isNew(s.getSHA512Half(), peerId))
return false;
RippleAddress naPeerPublic = RippleAddress::createNodePublic(strCopy(pubKey));

View File

@@ -124,7 +124,7 @@ public:
//
Transaction::pointer submitTransaction(const Transaction::pointer& tpTrans);
Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source = NULL);
Transaction::pointer processTransaction(Transaction::pointer transaction);
Transaction::pointer findTransactionByID(const uint256& transactionID);
int findTransactionsBySource(const uint256& uLedger, std::list<Transaction::pointer>&, const RippleAddress& sourceAccount,
uint32 minSeq, uint32 maxSeq);
@@ -171,8 +171,8 @@ public:
const std::vector<unsigned char>& myNode, std::list< std::vector<unsigned char> >& newNodes);
// ledger proposal/close functions
bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, uint32 closeTime,
const std::string& pubKey, const std::string& signature, const RippleAddress& nodePublic);
bool recvPropose(uint64 peerId, uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger,
uint32 closeTime, const std::string& pubKey, const std::string& signature, const RippleAddress& nodePublic);
bool gotTXData(const boost::shared_ptr<Peer>& peer, const uint256& hash,
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
bool recvValidation(const SerializedValidation::pointer& val);

View File

@@ -16,6 +16,7 @@
#include "Log.h"
SETUP_LOG();
DECLARE_INSTANCE(Peer);
// Don't try to run past receiving nonsense from a peer
#define TRUST_NETWORK
@@ -29,7 +30,8 @@ Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx)
mSocketSsl(io_service, ctx),
mVerifyTimer(io_service)
{
// cLog(lsDEBUG) << "CREATING PEER: " << ADDRESS(this);
cLog(lsDEBUG) << "CREATING PEER: " << ADDRESS(this);
mPeerId = theApp->getConnectionPool().assignPeerId();
}
void Peer::handle_write(const boost::system::error_code& error, size_t bytes_transferred)
@@ -706,8 +708,12 @@ void Peer::recvTransaction(ripple::TMTransaction& packet)
SerializerIterator sit(s);
SerializedTransaction::pointer stx = boost::make_shared<SerializedTransaction>(boost::ref(sit));
if (!theApp->isNew(stx->getTransactionID(), mPeerId))
return;
tx = boost::make_shared<Transaction>(stx, true);
if (tx->getStatus() == INVALID) throw(0);
if (tx->getStatus() == INVALID)
throw(0);
#ifndef TRUST_NETWORK
}
catch (...)
@@ -721,7 +727,7 @@ void Peer::recvTransaction(ripple::TMTransaction& packet)
}
#endif
tx = theApp->getOPs().processTransaction(tx, this);
tx = theApp->getOPs().processTransaction(tx);
if(tx->getStatus() != INCLUDED)
{ // transaction wasn't accepted into ledger
@@ -746,7 +752,7 @@ void Peer::recvPropose(ripple::TMProposeSet& packet)
if ((packet.has_previousledger()) && (packet.previousledger().size() == 32))
memcpy(prevLedger.begin(), packet.previousledger().data(), 32);
if(theApp->getOPs().recvPropose(packet.proposeseq(), currentTxHash, prevLedger, packet.closetime(),
if(theApp->getOPs().recvPropose(mPeerId, packet.proposeseq(), currentTxHash, prevLedger, packet.closetime(),
packet.nodepubkey(), packet.signature(), mNodePublic))
{ // FIXME: Not all nodes will want proposals
PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, ripple::mtPROPOSE_LEDGER);
@@ -820,7 +826,7 @@ void Peer::recvValidation(const boost::shared_ptr<ripple::TMValidation>& packet)
SerializedValidation::pointer val = boost::make_shared<SerializedValidation>(boost::ref(sit), false);
uint256 signingHash = val->getSigningHash();
if (!theApp->isNew(signingHash))
if (!theApp->isNew(signingHash, mPeerId))
{
cLog(lsTRACE) << "Validation is duplicate";
return;

View File

@@ -11,6 +11,7 @@
#include "PackedMessage.h"
#include "Ledger.h"
#include "Transaction.h"
#include "InstanceCounter.h"
enum PeerPunish
{
@@ -21,7 +22,9 @@ enum PeerPunish
typedef std::pair<std::string,int> ipPort;
class Peer : public boost::enable_shared_from_this<Peer>
DEFINE_INSTANCE(Peer);
class Peer : public boost::enable_shared_from_this<Peer>, public IS_INSTANCE(Peer)
{
public:
typedef boost::shared_ptr<Peer> pointer;
@@ -43,6 +46,7 @@ private:
ipPort mIpPort;
ipPort mIpPortConnect;
uint256 mCookieHash;
uint64 mPeerId;
uint256 mClosedLedgerHash, mPreviousLedgerHash;
std::list<uint256> mRecentLedgers;
@@ -159,6 +163,8 @@ public:
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
bool hasLedger(const uint256& hash) const;
bool hasTxSet(const uint256& hash) const;
uint64 getPeerId() const { return mPeerId; }
RippleAddress getNodePublic() const { return mNodePublic; }
void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); }
};

View File

@@ -7,6 +7,7 @@
#include "RippleAddress.h"
#include "AccountState.h"
#include "NicknameState.h"
#include "InstanceCounter.h"
#include "Pathfinder.h"
#include <boost/foreach.hpp>
@@ -75,7 +76,7 @@ Json::Value RPCHandler::rpcError(int iError)
for (i=NUMBER(errorInfoA); i-- && errorInfoA[i].iError != iError;)
;
Json::Value jsonResult = Json::Value(Json::objectValue);
Json::Value jsonResult(Json::objectValue);
jsonResult["error"] = i >= 0 ? errorInfoA[i].pToken : lexical_cast_i(iError);
jsonResult["error_message"] = i >= 0 ? errorInfoA[i].pMessage : lexical_cast_i(iError);
@@ -2420,37 +2421,38 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
bool mAdminRequired;
unsigned int iOptions;
} commandsA[] = {
{ "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true },
{ "account_domain_set", &RPCHandler::doAccountDomainSet, 2, 3, false, optCurrent },
{ "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true },
{ "account_domain_set", &RPCHandler::doAccountDomainSet, 2, 3, false, optCurrent },
{ "account_email_set", &RPCHandler::doAccountEmailSet, 2, 3, false, optCurrent },
{ "account_info", &RPCHandler::doAccountInfo, 1, 2, false, optCurrent },
{ "account_message_set", &RPCHandler::doAccountMessageSet, 3, 3, false, optCurrent },
{ "account_publish_set", &RPCHandler::doAccountPublishSet, 4, 4, false, optCurrent },
{ "account_rate_set", &RPCHandler::doAccountRateSet, 3, 3, false, optCurrent },
{ "account_tx", &RPCHandler::doAccountTransactions, 2, 3, false, optNetwork },
{ "account_wallet_set", &RPCHandler::doAccountWalletSet, 2, 3, false, optCurrent },
{ "account_wallet_set", &RPCHandler::doAccountWalletSet, 2, 3, false, optCurrent },
{ "connect", &RPCHandler::doConnect, 1, 2, true },
{ "data_delete", &RPCHandler::doDataDelete, 1, 1, true },
{ "data_fetch", &RPCHandler::doDataFetch, 1, 1, true },
{ "data_store", &RPCHandler::doDataStore, 2, 2, true },
{ "get_counts", &RPCHandler::doGetCounts, 0, 1, true },
{ "ledger", &RPCHandler::doLedger, 0, 2, false, optNetwork },
{ "log_level", &RPCHandler::doLogLevel, 0, 2, true },
{ "log_level", &RPCHandler::doLogLevel, 0, 2, true },
{ "logrotate", &RPCHandler::doLogRotate, 0, 0, true },
{ "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, optCurrent },
{ "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, optCurrent },
{ "nickname_set", &RPCHandler::doNicknameSet, 2, 3, false, optCurrent },
{ "offer_create", &RPCHandler::doOfferCreate, 9, 10, false, optCurrent },
{ "offer_cancel", &RPCHandler::doOfferCancel, 3, 3, false, optCurrent },
{ "owner_info", &RPCHandler::doOwnerInfo, 1, 2, false, optCurrent },
{ "password_fund", &RPCHandler::doPasswordFund, 2, 3, false, optCurrent },
{ "password_fund", &RPCHandler::doPasswordFund, 2, 3, false, optCurrent },
{ "password_set", &RPCHandler::doPasswordSet, 2, 3, false, optNetwork },
{ "peers", &RPCHandler::doPeers, 0, 0, true },
{ "profile", &RPCHandler::doProfile, 1, 9, false, optCurrent },
{ "ripple", &RPCHandler::doRipple, 9, -1, false, optCurrent|optClosed },
{ "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, optCurrent },
{ "ripple_line_set", &RPCHandler::doRippleLineSet, 4, 7, false, optCurrent },
{ "send", &RPCHandler::doSend, 3, 9, false, optCurrent },
{ "send", &RPCHandler::doSend, 3, 9, false, optCurrent },
{ "server_info", &RPCHandler::doServerInfo, 0, 0, true },
{ "stop", &RPCHandler::doStop, 0, 0, true },
{ "stop", &RPCHandler::doStop, 0, 0, true },
{ "tx", &RPCHandler::doTx, 1, 1, true },
{ "tx_history", &RPCHandler::doTxHistory, 1, 1, false, },
@@ -2459,16 +2461,16 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
{ "unl_list", &RPCHandler::doUnlList, 0, 0, true },
{ "unl_load", &RPCHandler::doUnlLoad, 0, 0, true },
{ "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true },
{ "unl_reset", &RPCHandler::doUnlReset, 0, 0, true },
{ "unl_score", &RPCHandler::doUnlScore, 0, 0, true },
{ "unl_reset", &RPCHandler::doUnlReset, 0, 0, true },
{ "unl_score", &RPCHandler::doUnlScore, 0, 0, true },
{ "validation_create", &RPCHandler::doValidationCreate, 0, 1, false },
{ "validation_create", &RPCHandler::doValidationCreate, 0, 1, false },
{ "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false },
{ "wallet_accounts", &RPCHandler::doWalletAccounts, 1, 1, false, optCurrent },
{ "wallet_add", &RPCHandler::doWalletAdd, 3, 5, false, optCurrent },
{ "wallet_claim", &RPCHandler::doWalletClaim, 2, 4, false, optNetwork },
{ "wallet_create", &RPCHandler::doWalletCreate, 3, 4, false, optCurrent },
{ "wallet_create", &RPCHandler::doWalletCreate, 3, 4, false, optCurrent },
{ "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, },
{ "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, },
@@ -2603,6 +2605,20 @@ Json::Value RPCHandler::doLogin(const Json::Value& params)
}
}
Json::Value RPCHandler::doGetCounts(const Json::Value& params)
{
int minCount = 1;
if (params.size() > 0)
minCount = params[0u].asInt();
std::vector<InstanceType::InstanceCount> count = InstanceType::getInstanceCounts(minCount);
Json::Value ret(Json::objectValue);
BOOST_FOREACH(InstanceType::InstanceCount& it, count)
ret[it.first] = it.second;
return ret;
}
Json::Value RPCHandler::doLogLevel(const Json::Value& params)
{
if (params.size() == 0)

View File

@@ -1,3 +1,6 @@
#ifndef RPCHANDLER__H
#define RPCHANDLER__H
// used by the RPCServer or WSDoor to carry out these RPC commands
class NetworkOPs;
@@ -37,6 +40,7 @@ class RPCHandler
Json::Value doDataDelete(const Json::Value& params);
Json::Value doDataFetch(const Json::Value& params);
Json::Value doDataStore(const Json::Value& params);
Json::Value doGetCounts(const Json::Value& params);
Json::Value doLedger(const Json::Value& params);
Json::Value doLogRotate(const Json::Value& params);
Json::Value doNicknameInfo(const Json::Value& params);
@@ -156,4 +160,6 @@ public:
Json::Value doCommand(const std::string& command, Json::Value& params,int role);
Json::Value rpcError(int iError);
};
};
#endif

View File

@@ -1421,6 +1421,8 @@ bool PathState::lessPriority(PathState::ref lhs, PathState::ref rhs)
// Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID.
//
// If the unadded next node as specified by arguments would not work as is, then add the necessary nodes so it would work.
//
// Rules:
// - Currencies must be converted via an offer.
// - A node names it's output.
@@ -1449,13 +1451,14 @@ TER PathState::pushImply(
ACCOUNT_ONE, // Placeholder for offers.
uCurrencyID, // The offer's output is what is now wanted.
uIssuerID);
}
const PaymentNode& pnBck = vpnNodes.back();
// For ripple, non-stamps, ensure the issuer is on at least one side of the transaction.
if (tesSUCCESS == terResult
&& !!uCurrencyID // Not stamps.
&& (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs.
&& (pnBck.uAccountID != uIssuerID // Previous is not issuing own IOUs.
&& uAccountID != uIssuerID)) // Current is not receiving own IOUs.
{
// Need to ripple through uIssuerID's account.
@@ -1514,13 +1517,19 @@ TER PathState::pushNode(
pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID);
pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID);
if (!bFirst)
if (bFirst)
{
// The first node is always correct as is.
nothing();
}
else
{
// Add required intermediate nodes to deliver to current account.
terResult = pushImply(
pnCur.uAccountID, // Current account.
pnCur.uCurrencyID, // Wanted currency.
!!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer.
!!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as wanted issuer.
// Note: pnPrv may no longer be the immediately previous node.
}
@@ -1532,7 +1541,7 @@ TER PathState::pushNode(
if (bBckAccount)
{
SLE::pointer sleRippleState = mLedger->getSLE(Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID));
SLE::pointer sleRippleState = lesEntries.entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID));
if (!sleRippleState)
{
@@ -1541,7 +1550,7 @@ TER PathState::pushNode(
<< " and "
<< RippleAddress::createHumanAccountID(pnCur.uAccountID)
<< " for "
<< STAmount::createHumanCurrency(pnPrv.uCurrencyID)
<< STAmount::createHumanCurrency(pnCur.uCurrencyID)
<< "." ;
cLog(lsINFO) << getJson();
@@ -1555,12 +1564,12 @@ TER PathState::pushNode(
<< " and "
<< RippleAddress::createHumanAccountID(pnCur.uAccountID)
<< " for "
<< STAmount::createHumanCurrency(pnPrv.uCurrencyID)
<< STAmount::createHumanCurrency(pnCur.uCurrencyID)
<< "." ;
STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, uCurrencyID);
STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID);
if (!saOwed.isPositive() && *saOwed.negate() >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, uCurrencyID))
if (!saOwed.isPositive() && *saOwed.negate() >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID))
{
terResult = tepPATH_DRY;
}

View File

@@ -17,6 +17,10 @@
SETUP_LOG();
DECLARE_INSTANCE(SHAMap);
DECLARE_INSTANCE(SHAMapItem);
DECLARE_INSTANCE(SHAMapTreeNode);
std::size_t hash_value(const SHAMapNode& mn)
{
std::size_t seed = theApp->getNonceST();

View File

@@ -14,6 +14,11 @@
#include "ScopedLock.h"
#include "Serializer.h"
#include "HashedObject.h"
#include "InstanceCounter.h"
DEFINE_INSTANCE(SHAMap);
DEFINE_INSTANCE(SHAMapItem);
DEFINE_INSTANCE(SHAMapTreeNode);
class SHAMap;
@@ -31,7 +36,7 @@ private:
public:
static const int rootDepth=0;
static const int rootDepth = 0;
SHAMapNode() : mDepth(0) { ; }
SHAMapNode(int depth, const uint256& hash);
@@ -77,7 +82,7 @@ extern std::size_t hash_value(const SHAMapNode& mn);
inline std::ostream& operator<<(std::ostream& out, const SHAMapNode& node) { return out << node.getString(); }
class SHAMapItem
class SHAMapItem : public IS_INSTANCE(SHAMapItem)
{ // an item stored in a SHAMap
public:
typedef boost::shared_ptr<SHAMapItem> pointer;
@@ -135,7 +140,7 @@ enum SHAMapType
smtFREE =3, // A tree not part of a ledger
};
class SHAMapTreeNode : public SHAMapNode
class SHAMapTreeNode : public SHAMapNode, public IS_INSTANCE(SHAMapTreeNode)
{
friend class SHAMap;
@@ -276,7 +281,7 @@ public:
extern std::ostream& operator<<(std::ostream&, const SHAMapMissingNode&);
class SHAMap
class SHAMap : public IS_INSTANCE(SHAMap)
{
public:
typedef boost::shared_ptr<SHAMap> pointer;

View File

@@ -5,6 +5,8 @@
#include "Ledger.h"
#include "Log.h"
DECLARE_INSTANCE(SerializedLedgerEntry)
SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint256& index)
: STObject(sfLedgerEntry), mIndex(index)
{

View File

@@ -4,8 +4,11 @@
#include "SerializedObject.h"
#include "LedgerFormats.h"
#include "RippleAddress.h"
#include "InstanceCounter.h"
class SerializedLedgerEntry : public STObject
DEFINE_INSTANCE(SerializedLedgerEntry);
class SerializedLedgerEntry : public STObject, private IS_INSTANCE(SerializedLedgerEntry)
{
public:
typedef boost::shared_ptr<SerializedLedgerEntry> pointer;

View File

@@ -14,6 +14,8 @@
#include "SerializedTransaction.h"
SETUP_LOG();
DECLARE_INSTANCE(SerializedObject);
DECLARE_INSTANCE(SerializedArray);
std::auto_ptr<SerializedType> STObject::makeDefaultObject(SerializedTypeID id, SField::ref name)
{
@@ -1110,23 +1112,24 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
data.push_back(new STPathSet(field));
STPathSet* tail = dynamic_cast<STPathSet*>(&data.back());
assert(tail);
for (Json::UInt i = 0; !object.isValidIndex(i); ++i)
for (Json::UInt i = 0; value.isValidIndex(i); ++i)
{
STPath p;
if (!object[i].isArray())
if (!value[i].isArray())
throw std::runtime_error("Path must be array");
for (Json::UInt j = 0; !object[i].isValidIndex(j); ++j)
for (Json::UInt j = 0; value[i].isValidIndex(j); ++j)
{ // each element in this path has some combination of account, currency, or issuer
Json::Value pathEl = object[i][j];
Json::Value pathEl = value[i][j];
if (!pathEl.isObject())
throw std::runtime_error("Path elements must be objects");
const Json::Value& account = pathEl["account"];
const Json::Value& currency = pathEl["currency"];
const Json::Value& issuer = pathEl["issuer"];
const Json::Value& account = pathEl["account"];
const Json::Value& currency = pathEl["currency"];
const Json::Value& issuer = pathEl["issuer"];
bool hasCurrency = false;
uint160 uAccount, uCurrency, uIssuer;
bool hasCurrency;
if (!account.isNull())
{ // human account id
if (!account.isString())
@@ -1136,7 +1139,7 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
uAccount.SetHex(strValue);
{
RippleAddress a;
if (!a.setAccountPublic(strValue))
if (!a.setAccountID(strValue))
throw std::runtime_error("Account in path element invalid");
uAccount = a.getAccountID();
}
@@ -1160,7 +1163,7 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
else
{
RippleAddress a;
if (!a.setAccountPublic(issuer.asString()))
if (!a.setAccountID(issuer.asString()))
throw std::runtime_error("path element issuer invalid");
uIssuer = a.getAccountID();
}

View File

@@ -8,6 +8,10 @@
#include "../json/value.h"
#include "SerializedTypes.h"
#include "InstanceCounter.h"
DEFINE_INSTANCE(SerializedObject);
DEFINE_INSTANCE(SerializedArray);
// Serializable object/array types
@@ -22,7 +26,7 @@ public:
SOElement(SField::ref fi, SOE_Flags fl) : e_field(fi), flags(fl) { ; }
};
class STObject : public SerializedType
class STObject : public SerializedType, private IS_INSTANCE(SerializedObject)
{
protected:
boost::ptr_vector<SerializedType> mData;
@@ -175,7 +179,7 @@ namespace boost
class STArray : public SerializedType
class STArray : public SerializedType, private IS_INSTANCE(SerializedArray)
{
public:
typedef std::vector<STObject> vector;

View File

@@ -8,6 +8,8 @@
#include "Log.h"
#include "HashPrefixes.h"
DECLARE_INSTANCE(SerializedTransaction);
SerializedTransaction::SerializedTransaction(TransactionType type) : STObject(sfTransaction), mType(type)
{
mFormat = TransactionFormat::getTxnFormat(type);

View File

@@ -9,6 +9,7 @@
#include "SerializedObject.h"
#include "TransactionFormats.h"
#include "RippleAddress.h"
#include "InstanceCounter.h"
#define TXN_SQL_NEW 'N'
#define TXN_SQL_CONFLICT 'C'
@@ -17,7 +18,9 @@
#define TXN_SQL_INCLUDED 'I'
#define TXN_SQL_UNKNOWN 'U'
class SerializedTransaction : public STObject
DEFINE_INSTANCE(SerializedTransaction);
class SerializedTransaction : public STObject, private IS_INSTANCE(SerializedTransaction)
{
public:
typedef boost::shared_ptr<SerializedTransaction> pointer;

View File

@@ -14,6 +14,7 @@
#include "TransactionErr.h"
SETUP_LOG();
DECLARE_INSTANCE(SerializedValue);
STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0);
STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1);
@@ -539,7 +540,6 @@ void STPathSet::add(Serializer& s) const
if (!bFirst)
{
s.add8(STPathElement::typeBoundary);
bFirst = false;
}
BOOST_FOREACH(const STPathElement& speElement, spPath)
@@ -557,6 +557,8 @@ void STPathSet::add(Serializer& s) const
if (iType & STPathElement::typeIssuer)
s.add160(speElement.getIssuerID());
}
bFirst = false;
}
s.add8(STPathElement::typeEnd);
}

View File

@@ -9,7 +9,7 @@
#include "uint256.h"
#include "Serializer.h"
#include "FieldNames.h"
#include "InstanceCounter.h"
enum PathFlags
{
@@ -30,7 +30,9 @@ enum PathFlags
#define ACCOUNT_XNS uint160(0)
#define ACCOUNT_ONE uint160(1) // Used as a place holder
class SerializedType
DEFINE_INSTANCE(SerializedValue);
class SerializedType : private IS_INSTANCE(SerializedValue)
{
protected:
SField::ptr fName;

View File

@@ -1,39 +1,100 @@
#include "Suppression.h"
#include <boost/foreach.hpp>
bool SuppressionTable::addSuppression(const uint160& suppression)
{
boost::mutex::scoped_lock sl(mSuppressionMutex);
DECLARE_INSTANCE(Suppression);
if (mSuppressionMap.find(suppression) != mSuppressionMap.end())
return false;
Suppression& SuppressionTable::findCreateEntry(const uint256& index, bool& created)
{
boost::unordered_map<uint256, Suppression>::iterator fit = mSuppressionMap.find(index);
if (fit != mSuppressionMap.end())
{
created = false;
return fit->second;
}
created = true;
time_t now = time(NULL);
time_t expireTime = now - mHoldTime;
boost::unordered_map< time_t, std::list<uint160> >::iterator
it = mSuppressionTimes.begin(), end = mSuppressionTimes.end();
while (it != end)
// See if any supressions need to be expired
std::map< time_t, std::list<uint256> >::iterator it = mSuppressionTimes.begin();
if ((it != mSuppressionTimes.end()) && (it->first <= expireTime))
{
if (it->first <= expireTime)
{
BOOST_FOREACH(const uint160& lit, it->second)
mSuppressionMap.erase(lit);
it = mSuppressionTimes.erase(it);
}
else ++it;
BOOST_FOREACH(const uint256& lit, it->second)
mSuppressionMap.erase(lit);
mSuppressionTimes.erase(it);
}
mSuppressionMap[suppression] = now;
mSuppressionTimes[now].push_back(suppression);
mSuppressionTimes[now].push_back(index);
return mSuppressionMap.insert(std::make_pair(index, Suppression())).first->second;
}
bool SuppressionTable::addSuppression(const uint256& index)
{
boost::mutex::scoped_lock sl(mSuppressionMutex);
bool created;
findCreateEntry(index, created);
return created;
}
Suppression SuppressionTable::getEntry(const uint256& index)
{
boost::mutex::scoped_lock sl(mSuppressionMutex);
bool created;
return findCreateEntry(index, created);
}
bool SuppressionTable::addSuppressionPeer(const uint256& index, uint64 peer)
{
boost::mutex::scoped_lock sl(mSuppressionMutex);
bool created;
findCreateEntry(index, created).addPeer(peer);
return created;
}
bool SuppressionTable::addSuppressionFlags(const uint256& index, int flag)
{
boost::mutex::scoped_lock sl(mSuppressionMutex);
bool created;
findCreateEntry(index, created).setFlag(flag);
return created;
}
bool SuppressionTable::setFlag(const uint256& index, int flag)
{ // return: true = changed, false = unchanged
assert(flag != 0);
boost::mutex::scoped_lock sl(mSuppressionMutex);
bool created;
Suppression &s = findCreateEntry(index, created);
if ((s.getFlags() & flag) == flag)
return false;
s.setFlag(flag);
return true;
}
bool SuppressionTable::addSuppression(const uint256& suppression)
bool SuppressionTable::swapSet(const uint256& index, std::set<uint64>& peers, int flag)
{
uint160 u;
memcpy(u.begin(), suppression.begin() + (suppression.size() - u.size()), u.size());
return addSuppression(u);
}
boost::mutex::scoped_lock sl(mSuppressionMutex);
bool created;
Suppression &s = findCreateEntry(index, created);
if ((s.getFlags() & flag) == flag)
return false;
s.swapSet(peers);
s.setFlag(flag);
return true;
}

View File

@@ -1,14 +1,43 @@
#ifndef __SUPPRESSION__
#define __SUPPRESSION__
#include <set>
#include <map>
#include <list>
#include <boost/unordered_map.hpp>
#include <boost/thread/mutex.hpp>
#include "uint256.h"
#include "types.h"
#include "InstanceCounter.h"
extern std::size_t hash_value(const uint160& u);
DEFINE_INSTANCE(Suppression);
#define SF_RELAYED 0x01
#define SF_SIGBAD 0x02
#define SF_SIGGOOD 0x04
#define SF_SAVED 0x08
class Suppression : private IS_INSTANCE(Suppression)
{
protected:
int mFlags;
std::set<uint64> mPeers;
public:
Suppression() : mFlags(0) { ; }
const std::set<uint64>& peekPeers() { return mPeers; }
void addPeer(uint64 peer) { mPeers.insert(peer); }
bool hasPeer(uint64 peer) { return mPeers.count(peer) > 0; }
int getFlags(void) { return mFlags; }
bool hasFlag(int f) { return (mFlags & f) != 0; }
void setFlag(int f) { mFlags |= f; }
void clearFlag(int f) { mFlags &= ~f; }
void swapSet(std::set<uint64>& s) { mPeers.swap(s); }
};
class SuppressionTable
{
@@ -17,18 +46,27 @@ protected:
boost::mutex mSuppressionMutex;
// Stores all suppressed hashes and their expiration time
boost::unordered_map<uint160, time_t> mSuppressionMap;
boost::unordered_map<uint256, Suppression> mSuppressionMap;
// Stores all expiration times and the hashes indexed for them
boost::unordered_map< time_t, std::list<uint160> > mSuppressionTimes;
std::map< time_t, std::list<uint256> > mSuppressionTimes;
int mHoldTime;
Suppression& findCreateEntry(const uint256&, bool& created);
public:
SuppressionTable(int holdTime = 120) : mHoldTime(holdTime) { ; }
bool addSuppression(const uint256& suppression);
bool addSuppression(const uint160& suppression);
bool addSuppression(const uint256& index);
bool addSuppressionPeer(const uint256& index, uint64 peer);
bool addSuppressionFlags(const uint256& index, int flag);
bool setFlag(const uint256& index, int flag);
Suppression getEntry(const uint256&);
bool swapSet(const uint256& index, std::set<uint64>& peers, int flag);
};
#endif

View File

@@ -44,6 +44,7 @@ public:
int getTargetAge() const;
int getCacheSize();
int getTrackSize();
int getSweepAge();
void setTargetSize(int size);
@@ -78,6 +79,12 @@ template<typename c_Key, typename c_Data> int TaggedCache<c_Key, c_Data>::getCac
return mCache.size();
}
template<typename c_Key, typename c_Data> int TaggedCache<c_Key, c_Data>::getTrackSize()
{
boost::recursive_mutex::scoped_lock sl(mLock);
return mMap.size();
}
template<typename c_Key, typename c_Data> void TaggedCache<c_Key, c_Data>::sweep()
{
boost::recursive_mutex::scoped_lock sl(mLock);
@@ -96,7 +103,7 @@ template<typename c_Key, typename c_Data> void TaggedCache<c_Key, c_Data>::sweep
typename boost::unordered_map<key_type, cache_entry>::iterator cit = mCache.begin();
while (cit != mCache.end())
{
if (cit->second->second.first < target)
if (cit->second.first < target)
mCache.erase(cit++);
else
++cit;
@@ -106,7 +113,7 @@ template<typename c_Key, typename c_Data> void TaggedCache<c_Key, c_Data>::sweep
typename boost::unordered_map<key_type, weak_data_ptr>::iterator mit = mMap.begin();
while (mit != mMap.end())
{
if (mit->second->expired())
if (mit->second.expired())
mMap.erase(mit++);
else
++mit;

View File

@@ -13,6 +13,8 @@
#include "SerializedTransaction.h"
#include "Log.h"
DECLARE_INSTANCE(Transaction);
Transaction::Transaction(SerializedTransaction::ref sit, bool bValidate)
: mInLedger(0), mStatus(INVALID), mResult(temUNCERTAIN), mTransaction(sit)
{

View File

@@ -21,6 +21,7 @@
#include "SHAMap.h"
#include "SerializedTransaction.h"
#include "TransactionErr.h"
#include "InstanceCounter.h"
class Database;
@@ -37,8 +38,10 @@ enum TransStatus
INCOMPLETE = 8 // needs more signatures
};
DEFINE_INSTANCE(Transaction);
// This class is for constructing and examining transactions. Transactions are static so manipulation functions are unnecessary.
class Transaction : public boost::enable_shared_from_this<Transaction>
class Transaction : public boost::enable_shared_from_this<Transaction>, private IS_INSTANCE(Transaction)
{
public:
typedef boost::shared_ptr<Transaction> pointer;

View File

@@ -20,6 +20,7 @@ public:
// return value: true = we had the transaction already
bool canonicalize(Transaction::pointer& txn, bool maybeNew);
void sweep(void) { mCache.sweep(); }
};
#endif

View File

@@ -1074,6 +1074,12 @@ void WSConnection::doSubmit(Json::Value& jvResult, const Json::Value& jvRequest)
try
{
tpTrans = mNetwork.submitTransaction(tpTrans);
if (!tpTrans) {
jvResult["error"] = "invalidTransaction";
jvResult["error_exception"] = "Unable to sterilize transaction.";
return;
}
}
catch (std::exception& e)
{

View File

@@ -523,6 +523,65 @@ buster.testCase("Indirect ripple", {
});
},
"indirect ripple with path" :
function (done) {
var self = this;
async.waterfall([
function (callback) {
self.what = "Create accounts.";
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
},
function (callback) {
self.what = "Set alice's limit.";
testutils.credit_limit(self.remote, "alice", "600/USD/mtgox", callback);
},
function (callback) {
self.what = "Set bob's limit.";
testutils.credit_limit(self.remote, "bob", "700/USD/mtgox", callback);
},
function (callback) {
self.what = "Give alice some mtgox.";
testutils.payment(self.remote, "mtgox", "alice", "70/USD/mtgox", callback);
},
function (callback) {
self.what = "Give bob some mtgox.";
testutils.payment(self.remote, "mtgox", "bob", "50/USD/mtgox", callback);
},
function (callback) {
self.what = "Alice sends via a path";
self.remote.transaction()
.payment("alice", "bob", "5/USD/mtgox")
.path_add( [ { account: "mtgox" } ])
.on('proposed', function (m) {
// console.log("proposed: %s", JSON.stringify(m));
callback(m.result != 'tesSUCCESS');
})
.submit();
},
function (callback) {
self.what = "Verify alice balance with mtgox.";
testutils.verify_balance(self.remote, "alice", "65/USD/mtgox", callback);
},
function (callback) {
self.what = "Verify bob balance with mtgox.";
testutils.verify_balance(self.remote, "bob", "55/USD/mtgox", callback);
},
], function (error) {
buster.refute(error, self.what);
done();
});
},
// Direct ripple without no liqudity.
// Ripple without credit path.
// Ripple with one-way credit path.