diff --git a/js/events.js b/js/events.js
new file mode 100644
index 0000000000..7a2098f98a
--- /dev/null
+++ b/js/events.js
@@ -0,0 +1,57 @@
+var EventEmitter = function () {
+ this._events = {};
+};
+
+EventEmitter.prototype.on = function (e, f) {
+ console.log('on', e, f)
+ if (e in this._events) {
+ if (this._events[e].indexOf(f) < 0) {
+ this._events[e].push(f);
+ }
+ } else {
+ this._events[e] = [f];
+ }
+ return this;
+};
+
+EventEmitter.prototype.off = function (e, f) {
+ if (f) {
+ function eq(x) { return function (y) { return x === y; } }
+ this._events[e] = this.listeners(e).filter(eq(f));
+ } else {
+ delete this._events[e];
+ }
+};
+
+EventEmitter.prototype.removeListener = function (e, f) {
+ this.off(e, f);
+};
+
+EventEmitter.prototype.removeAllListeners = function (e) {
+ this.off(e);
+};
+
+EventEmitter.prototype.emit = function (e) {
+ var args = Array.prototype.slice.call(arguments, 1),
+ fs = this.listeners(e);
+ console.log('emit', e, args)
+
+ for (var i = 0; i < fs.length; i++) {
+ fs[i].apply(e, args);
+ }
+};
+
+EventEmitter.prototype.listeners = function (e) {
+ return this._events[e] || [];
+};
+
+EventEmitter.prototype.once = function (e, f) {
+ var that = this;
+ this.on(e, function g() {
+ f.apply(e, arguments);
+ that.off(e, g);
+ });
+ return this;
+};
+
+exports.EventEmitter = EventEmitter;
\ No newline at end of file
diff --git a/newcoin.vcxproj b/newcoin.vcxproj
index 3109a074aa..3a318d339c 100644
--- a/newcoin.vcxproj
+++ b/newcoin.vcxproj
@@ -171,6 +171,7 @@
+
@@ -205,15 +206,20 @@
+
+
+
+
+
@@ -233,8 +239,12 @@
+
+
+
+
@@ -250,19 +260,29 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters
index 8aa2cf9ad0..090e299712 100644
--- a/newcoin.vcxproj.filters
+++ b/newcoin.vcxproj.filters
@@ -309,6 +309,15 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
@@ -566,6 +575,63 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
diff --git a/src/Amount.cpp b/src/Amount.cpp
index bedc61b71f..8f22491711 100644
--- a/src/Amount.cpp
+++ b/src/Amount.cpp
@@ -16,7 +16,7 @@ SETUP_LOG();
uint64 STAmount::uRateOne = STAmount::getRate(STAmount(1), STAmount(1));
-// --> sCurrency: "", "XNS", or three letter ISO code.
+// --> sCurrency: "", "XRP", or three letter ISO code.
bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCurrency)
{
bool bSuccess = true;
@@ -1365,19 +1365,19 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test )
if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
- if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60")
+ if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), uint160(), ACCOUNT_XRP).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::multiply(STAmount(20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
- if (STAmount::multiply(STAmount(20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60")
+ if (STAmount::multiply(STAmount(20), STAmount(3), uint160(), ACCOUNT_XRP).getText() != "60")
BOOST_FAIL("STAmount multiply fail");
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
BOOST_FAIL("STAmount divide fail");
- if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "20")
+ if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), uint160(), ACCOUNT_XRP).getText() != "20")
BOOST_FAIL("STAmount divide fail");
if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20")
BOOST_FAIL("STAmount divide fail");
- if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), uint160(), ACCOUNT_XNS).getText() != "20")
+ if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), uint160(), ACCOUNT_XRP).getText() != "20")
BOOST_FAIL("STAmount divide fail");
STAmount a1(CURRENCY_ONE, ACCOUNT_ONE, 60), a2 (CURRENCY_ONE, ACCOUNT_ONE, 10, -1);
diff --git a/src/Application.cpp b/src/Application.cpp
index 37f497827a..aa15bc6539 100644
--- a/src/Application.cpp
+++ b/src/Application.cpp
@@ -42,7 +42,7 @@ Application::Application() :
mNetOps(mIOService, &mMasterLedger), mTempNodeCache("NodeCache", 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), mSweepTimer(mAuxService)
+ mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mSweepTimer(mAuxService), mRPCHandler(&mNetOps)
{
RAND_bytes(mNonce256.begin(), mNonce256.size());
RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST));
diff --git a/src/Application.h b/src/Application.h
index aeca10973f..da956fae28 100644
--- a/src/Application.h
+++ b/src/Application.h
@@ -19,7 +19,7 @@
#include "SNTPClient.h"
#include "../database/database.h"
#include "JobQueue.h"
-
+#include "RPCHandler.h"
class RPCDoor;
class PeerDoor;
@@ -55,6 +55,7 @@ class Application
HashedObjectStore mHashedObjectStore;
SNTPClient mSNTPClient;
JobQueue mJobQueue;
+ RPCHandler mRPCHandler;
DatabaseCon *mRpcDB, *mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB;
@@ -96,9 +97,12 @@ public:
ValidationCollection& getValidations() { return mValidations; }
JobQueue& getJobQueue() { return mJobQueue; }
SuppressionTable& getSuppression() { return mSuppressions; }
+ RPCHandler& getRPCHandler() { return mRPCHandler; }
+
bool isNew(const uint256& s) { return mSuppressions.addSuppression(s); }
bool isNew(const uint256& s, uint64 p) { return mSuppressions.addSuppressionPeer(s, p); }
+ bool isNew(const uint256& s, uint64 p, int& f) { return mSuppressions.addSuppressionPeer(s, p, f); }
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); }
diff --git a/src/CanonicalTXSet.h b/src/CanonicalTXSet.h
index c75fb6b1b1..fead540db7 100644
--- a/src/CanonicalTXSet.h
+++ b/src/CanonicalTXSet.h
@@ -39,6 +39,13 @@ public:
CanonicalTXSet(const uint256& lclHash) : mSetHash(lclHash) { ; }
void push_back(SerializedTransaction::ref txn);
+
+ void reset(const uint256& newLCL)
+ {
+ mSetHash = newLCL;
+ mMap.clear();
+ }
+
iterator erase(const iterator& it);
iterator begin() { return mMap.begin(); }
diff --git a/src/Config.cpp b/src/Config.cpp
index 2faed71d30..f69e58446b 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -35,7 +35,7 @@
#define SECTION_VALIDATORS "validators"
#define SECTION_VALIDATORS_SITE "validators_site"
-// Fees are in XNS.
+// Fees are in XRP.
#define DEFAULT_FEE_DEFAULT 10
#define DEFAULT_FEE_ACCOUNT_CREATE 1000*SYSTEM_CURRENCY_PARTS
#define DEFAULT_FEE_NICKNAME_CREATE 1000
@@ -165,6 +165,8 @@ void Config::setup(const std::string& strConf)
void Config::load()
{
+ std::cout << "Loading: " << CONFIG_FILE << std::endl;
+
std::ifstream ifsConfig(CONFIG_FILE.c_str(), std::ios::in);
if (!ifsConfig)
diff --git a/src/Config.h b/src/Config.h
index 2bc0662e5f..cb17b46ed6 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -10,9 +10,9 @@
#include
#define SYSTEM_NAME "ripple"
-#define SYSTEM_CURRENCY_CODE "XNS"
+#define SYSTEM_CURRENCY_CODE "XRP"
#define SYSTEM_CURRENCY_PRECISION 6
-#define SYSTEM_CURRENCY_CODE_RIPPLE "XNR"
+#define SYSTEM_CURRENCY_CODE_RIPPLE "XRR"
#define SYSTEM_CURRENCY_GIFT 1000ull
#define SYSTEM_CURRENCY_USERS 100000000ull
diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp
index 9fc95a825d..ee992abdb2 100644
--- a/src/HashedObject.cpp
+++ b/src/HashedObject.cpp
@@ -21,7 +21,6 @@ HashedObjectStore::HashedObjectStore(int cacheSize, int cacheAge) :
bool HashedObjectStore::store(HashedObjectType type, uint32 index,
const std::vector& data, const uint256& hash)
{ // return: false = already in cache, true = added to cache
- assert(hash == Serializer::getSHA512Half(data));
if (!theApp->getHashNodeDB())
{
cLog(lsTRACE) << "HOS: no db";
@@ -32,6 +31,7 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index,
cLog(lsTRACE) << "HOS: " << hash << " store: incache";
return false;
}
+ assert(hash == Serializer::getSHA512Half(data));
HashedObject::pointer object = boost::make_shared(type, index, data, hash);
if (!mCache.canonicalize(hash, object))
diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp
index dabbb692d1..6fce0827b6 100644
--- a/src/Interpreter.cpp
+++ b/src/Interpreter.cpp
@@ -46,7 +46,7 @@ Interpreter::Interpreter()
mFunctionTable[CANCEL_OP]=new SubOp();
mFunctionTable[BLOCK_OP]=new SubOp();
mFunctionTable[BLOCK_END_OP]=new SubOp();
- mFunctionTable[SEND_XNS_OP]=new SendXNSOp();
+ mFunctionTable[SEND_XRP_OP]=new SendXRPOp();
/*
mFunctionTable[SEND_OP]=new SendOp();
mFunctionTable[REMOVE_CONTRACT_OP]=new SubOp();
@@ -63,7 +63,7 @@ Interpreter::Interpreter()
mFunctionTable[GET_LEDGER_TIME_OP]=new SubOp();
mFunctionTable[GET_LEDGER_NUM_OP]=new SubOp();
mFunctionTable[GET_RAND_FLOAT_OP]=new SubOp();
- mFunctionTable[GET_XNS_ESCROWED_OP]=new SubOp();
+ mFunctionTable[GET_XRP_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_CURRENCY_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_ISSUER]=new GetRippleEscrowedIssuerOp();
diff --git a/src/Interpreter.h b/src/Interpreter.h
index ad7d2cb855..5b43017bf5 100644
--- a/src/Interpreter.h
+++ b/src/Interpreter.h
@@ -39,12 +39,12 @@ public:
STOP_OP, CANCEL_OP,
BLOCK_OP, BLOCK_END_OP,
- SEND_XNS_OP,SEND_OP,REMOVE_CONTRACT_OP,FEE_OP,CHANGE_CONTRACT_OWNER_OP,
+ SEND_XRP_OP,SEND_OP,REMOVE_CONTRACT_OP,FEE_OP,CHANGE_CONTRACT_OWNER_OP,
STOP_REMOVE_OP,
SET_DATA_OP,GET_DATA_OP, GET_NUM_DATA_OP,
SET_REGISTER_OP,GET_REGISTER_OP,
GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP,
- GET_XNS_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER,
+ GET_XRP_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER,
GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP,
NUM_OF_OPS };
diff --git a/src/Ledger.cpp b/src/Ledger.cpp
index f05e1245a5..632ced3728 100644
--- a/src/Ledger.cpp
+++ b/src/Ledger.cpp
@@ -563,7 +563,7 @@ Json::Value Ledger::getJson(int options)
}
else
ledger["closed"] = false;
- if (mTransactionMap && (full || ((options & LEDGER_JSON_DUMP_TXNS) != 0)))
+ if (mTransactionMap && (full || ((options & LEDGER_JSON_DUMP_TXRP) != 0)))
{
Json::Value txns(Json::arrayValue);
SHAMapTreeNode::TNType type;
diff --git a/src/Ledger.h b/src/Ledger.h
index c033c59c4d..d89fcbba42 100644
--- a/src/Ledger.h
+++ b/src/Ledger.h
@@ -35,7 +35,7 @@ enum LedgerStateParms
lepERROR = 32, // error
};
-#define LEDGER_JSON_DUMP_TXNS 0x10000000
+#define LEDGER_JSON_DUMP_TXRP 0x10000000
#define LEDGER_JSON_DUMP_STATE 0x20000000
#define LEDGER_JSON_FULL 0x40000000
diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp
index f9d9f1bef9..50497b3cda 100644
--- a/src/LedgerAcquire.cpp
+++ b/src/LedgerAcquire.cpp
@@ -170,7 +170,7 @@ void LedgerAcquire::addPeers()
if (!found)
{
BOOST_FOREACH(Peer::ref peer, peerList)
- peerHas(peer);
+ peerHas(peer);
}
}
diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp
index 876a14cc6e..48939b5cde 100644
--- a/src/LedgerConsensus.cpp
+++ b/src/LedgerConsensus.cpp
@@ -35,16 +35,43 @@ void TransactionAcquire::done()
{
if (mFailed)
{
- cLog(lsWARNING) << "Failed to acquire TXs " << mHash;
+ cLog(lsWARNING) << "Failed to acquire TX set " << mHash;
theApp->getOPs().mapComplete(mHash, SHAMap::pointer());
}
else
{
+ cLog(lsINFO) << "Acquired TX set " << mHash;
mMap->setImmutable();
theApp->getOPs().mapComplete(mHash, mMap);
}
}
+void TransactionAcquire::onTimer()
+{
+ if (!getPeerCount())
+ { // out of peers
+ cLog(lsWARNING) << "Out of peers for TX set " << getHash();
+
+ bool found = false;
+ std::vector peerList = theApp->getConnectionPool().getPeerVector();
+ BOOST_FOREACH(Peer::ref peer, peerList)
+ {
+ if (peer->hasTxSet(getHash()))
+ {
+ found = true;
+ peerHas(peer);
+ }
+ }
+ if (!found)
+ {
+ BOOST_FOREACH(Peer::ref peer, peerList)
+ peerHas(peer);
+ }
+ }
+ else
+ trigger(Peer::pointer(), true);
+}
+
boost::weak_ptr TransactionAcquire::pmDowncast()
{
return boost::shared_polymorphic_downcast(shared_from_this());
@@ -59,6 +86,7 @@ void TransactionAcquire::trigger(Peer::ref peer, bool timer)
}
if (!mHaveRoot)
{
+ cLog(lsTRACE) << "TransactionAcquire::trigger " << (peer ? "havePeer" : "noPeer") << " no root";
ripple::TMGetLedger tmGL;
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
tmGL.set_itype(ripple::liTS_CANDIDATE);
@@ -98,9 +126,15 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs,
const std::list< std::vector >& data, Peer::ref peer)
{
if (mComplete)
+ {
+ cLog(lsTRACE) << "TX set complete";
return true;
+ }
if (mFailed)
+ {
+ cLog(lsTRACE) << "TX set failed";
return false;
+ }
try
{
std::list::const_iterator nodeIDit = nodeIDs.begin();
@@ -116,12 +150,18 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs,
return false;
}
if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE, NULL))
+ {
+ cLog(lsWARNING) << "TX acquire got bad root node";
return false;
+ }
else
mHaveRoot = true;
}
else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf))
+ {
+ cLog(lsWARNING) << "TX acquire got bad non-root node";
return false;
+ }
++nodeIDit;
++nodeDatait;
}
@@ -323,7 +363,6 @@ void LedgerConsensus::handleLCL(const uint256& lclHash)
mProposing = false;
mValidating = false;
mPeerPositions.clear();
- mPeerData.clear();
mDisputes.clear();
mCloseTimes.clear();
mDeadNodes.clear();
@@ -537,7 +576,7 @@ void LedgerConsensus::closeLedger()
mCloseTime = theApp->getOPs().getCloseTimeNC();
theApp->getOPs().setLastCloseTime(mCloseTime);
statusChange(ripple::neCLOSING_LEDGER, *mPreviousLedger);
- takeInitialPosition(*theApp->getMasterLedger().closeLedger());
+ takeInitialPosition(*theApp->getMasterLedger().closeLedger(true));
}
void LedgerConsensus::stateEstablish()
@@ -842,7 +881,7 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec
{
boost::unordered_map::const_iterator cit =
mAcquired.find(pit.second->getCurrentHash());
- if (cit != mAcquired.end() && cit->second)
+ if ((cit != mAcquired.end()) && cit->second)
txn->setVote(pit.first, cit->second->hasItem(txID));
}
@@ -927,7 +966,10 @@ bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash,
{
boost::unordered_map::iterator acq = mAcquiring.find(setHash);
if (acq == mAcquiring.end())
+ {
+ cLog(lsINFO) << "Got TX data for set not acquiring: " << setHash;
return false;
+ }
TransactionAcquire::pointer set = acq->second; // We must keep the set around during the function
return set->takeNodes(nodeIDs, nodeData, peer);
}
@@ -956,6 +998,7 @@ void LedgerConsensus::playbackProposals()
for (boost::unordered_map< uint160, std::list >::iterator
it = storedProposals.begin(), end = storedProposals.end(); it != end; ++it)
{
+ bool relay = false;
BOOST_FOREACH(const LedgerProposal::pointer& proposal, it->second)
{
if (proposal->hasSignature())
@@ -964,11 +1007,33 @@ void LedgerConsensus::playbackProposals()
if (proposal->checkSign())
{
cLog(lsINFO) << "Applying stored proposal";
- peerPosition(proposal);
+ relay = peerPosition(proposal);
}
}
else if (proposal->isPrevLedger(mPrevLedgerHash))
- peerPosition(proposal);
+ relay = peerPosition(proposal);
+
+ if (relay)
+ {
+ cLog(lsWARNING) << "We should do delayed relay of this proposal, but we cannot";
+ }
+#if 0 // FIXME: We can't do delayed relay because we don't have the signature
+ std::set peers
+ if (relay && theApp->getSuppression().swapSet(proposal.getSuppress(), set, SF_RELAYED))
+ {
+ cLog(lsDEBUG) << "Stored proposal delayed relay";
+ ripple::TMProposeSet set;
+ set.set_proposeseq
+ set.set_currenttxhash(, 256 / 8);
+ previousledger
+ closetime
+ nodepubkey
+ signature
+ PackedMessage::pointer message = boost::make_shared(set, ripple::mtPROPOSE_LEDGER);
+ theApp->getConnectionPool().relayMessageBut(peers, message);
+ }
+#endif
+
}
}
}
@@ -1117,7 +1182,7 @@ void LedgerConsensus::accept(SHAMap::ref set)
{
Log(lsTRACE) << "newLCL";
Json::Value p;
- newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
+ newLCL->addJson(p, LEDGER_JSON_DUMP_TXRP | LEDGER_JSON_DUMP_STATE);
Log(lsTRACE) << p;
}
diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h
index 6eae257506..8ac72634a1 100644
--- a/src/LedgerConsensus.h
+++ b/src/LedgerConsensus.h
@@ -30,7 +30,7 @@ protected:
SHAMap::pointer mMap;
bool mHaveRoot;
- void onTimer() { trigger(Peer::pointer(), true); }
+ void onTimer();
void newPeer(Peer::ref peer) { trigger(peer, false); }
void done();
diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp
index 60ee99a1c0..3b3017b744 100644
--- a/src/LedgerEntrySet.cpp
+++ b/src/LedgerEntrySet.cpp
@@ -447,9 +447,8 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
it != end; ++it)
entryModify(it->second);
- cLog(lsTRACE) << "Metadata:" << mSet.getJson(0);
-
mSet.addRaw(s, result);
+ cLog(lsTRACE) << "Metadata:" << mSet.getJson(0);
}
// <-- uNodeDir: For deletion, present to make dirDelete efficient.
diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp
index cd477b21cc..6c3a2ebc97 100644
--- a/src/LedgerMaster.cpp
+++ b/src/LedgerMaster.cpp
@@ -14,10 +14,10 @@ uint32 LedgerMaster::getCurrentLedgerIndex()
return mCurrentLedger->getLedgerSeq();
}
-bool LedgerMaster::addHeldTransaction(const Transaction::pointer& transaction)
+void LedgerMaster::addHeldTransaction(const Transaction::pointer& transaction)
{ // returns true if transaction was added
boost::recursive_mutex::scoped_lock ml(mLock);
- return mHeldTransactionsByID.insert(std::make_pair(transaction->getID(), transaction)).second;
+ mHeldTransactions.push_back(transaction->getSTransaction());
}
void LedgerMaster::pushLedger(Ledger::ref newLedger)
@@ -79,19 +79,41 @@ void LedgerMaster::storeLedger(Ledger::ref ledger)
}
-Ledger::pointer LedgerMaster::closeLedger()
+Ledger::pointer LedgerMaster::closeLedger(bool recover)
{
boost::recursive_mutex::scoped_lock sl(mLock);
Ledger::pointer closingLedger = mCurrentLedger;
+
+ if (recover)
+ {
+ int recovers = 0;
+ for (CanonicalTXSet::iterator it = mHeldTransactions.begin(), end = mHeldTransactions.end(); it != end; ++it)
+ {
+ try
+ {
+ TER result = mEngine.applyTransaction(*it->second, tapOPEN_LEDGER);
+ if (isTepSuccess(result))
+ ++recovers;
+ }
+ catch (...)
+ {
+ cLog(lsWARNING) << "Held transaction throws";
+ }
+ }
+ tLog(recovers != 0, lsINFO) << "Recovered " << recovers << " held transactions";
+ mHeldTransactions.reset(closingLedger->getHash());
+ }
+
mCurrentLedger = boost::make_shared(boost::ref(*closingLedger), true);
mEngine.setLedger(mCurrentLedger);
+
return closingLedger;
}
TER LedgerMaster::doTransaction(const SerializedTransaction& txn, TransactionEngineParams params)
{
TER result = mEngine.applyTransaction(txn, params);
- theApp->getOPs().pubTransaction(mEngine.getLedger(), txn, result);
+ theApp->getOPs().pubProposedTransaction(mEngine.getLedger(), txn, result);
return result;
}
diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h
index e3270710e5..152952b50b 100644
--- a/src/LedgerMaster.h
+++ b/src/LedgerMaster.h
@@ -9,6 +9,7 @@
#include "Transaction.h"
#include "TransactionEngine.h"
#include "RangeSet.h"
+#include "CanonicalTXSet.h"
// Tracks the current ledger and any ledgers in the process of closing
// Tracks ledger history
@@ -25,7 +26,7 @@ class LedgerMaster
LedgerHistory mLedgerHistory;
- std::map mHeldTransactionsByID;
+ CanonicalTXSet mHeldTransactions;
RangeSet mCompleteLedgers;
LedgerAcquire::pointer mMissingLedger;
@@ -40,7 +41,7 @@ class LedgerMaster
public:
- LedgerMaster() : mMissingSeq(0) { ; }
+ LedgerMaster() : mHeldTransactions(uint256()), mMissingSeq(0) { ; }
uint32 getCurrentLedgerIndex();
@@ -64,7 +65,7 @@ public:
std::string getCompleteLedgers() { return mCompleteLedgers.toString(); }
- Ledger::pointer closeLedger();
+ Ledger::pointer closeLedger(bool recoverHeldTransactions);
Ledger::pointer getLedgerBySeq(uint32 index)
{
@@ -90,7 +91,7 @@ public:
void setLedgerRangePresent(uint32 minV, uint32 maxV) { mCompleteLedgers.setRange(minV, maxV); }
- bool addHeldTransaction(const Transaction::pointer& trans);
+ void addHeldTransaction(const Transaction::pointer& trans);
void sweep(void) { mLedgerHistory.sweep(); }
};
diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp
index 75e286e9e0..5f5f058735 100644
--- a/src/LedgerProposal.cpp
+++ b/src/LedgerProposal.cpp
@@ -10,8 +10,9 @@
DECLARE_INSTANCE(LedgerProposal);
LedgerProposal::LedgerProposal(const uint256& pLgr, uint32 seq, const uint256& tx, uint32 closeTime,
- const RippleAddress& naPeerPublic) :
- mPreviousLedger(pLgr), mCurrentHash(tx), mCloseTime(closeTime), mProposeSeq(seq), mPublicKey(naPeerPublic)
+ const RippleAddress& naPeerPublic, const uint256& suppression) :
+ mPreviousLedger(pLgr), mCurrentHash(tx), mSuppression(suppression), mCloseTime(closeTime),
+ mProposeSeq(seq), mPublicKey(naPeerPublic)
{
// XXX Validate key.
// if (!mKey->SetPubKey(pubKey))
@@ -26,7 +27,7 @@ LedgerProposal::LedgerProposal(const RippleAddress& naPub, const RippleAddress&
const uint256& prevLgr, const uint256& position, uint32 closeTime) :
mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0),
mPublicKey(naPub), mPrivateKey(naPriv)
-{ // OPTIMIZEME: This is expensive. We create both the public and private keys separately each time
+{
mPeerID = mPublicKey.getNodeID();
mTime = boost::posix_time::second_clock::universal_time();
}
diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h
index a531de214c..b5176c7c90 100644
--- a/src/LedgerProposal.h
+++ b/src/LedgerProposal.h
@@ -18,7 +18,7 @@ class LedgerProposal : private IS_INSTANCE(LedgerProposal)
{
protected:
- uint256 mPreviousLedger, mCurrentHash;
+ uint256 mPreviousLedger, mCurrentHash, mSuppression;
uint32 mCloseTime, mProposeSeq;
uint160 mPeerID;
@@ -35,7 +35,7 @@ public:
// proposal from peer
LedgerProposal(const uint256& prevLgr, uint32 proposeSeq, const uint256& propose,
- uint32 closeTime, const RippleAddress& naPeerPublic);
+ uint32 closeTime, const RippleAddress& naPeerPublic, const uint256& suppress);
// our first proposal
LedgerProposal(const RippleAddress& pubKey, const RippleAddress& privKey,
@@ -52,6 +52,7 @@ public:
const uint160& getPeerID() const { return mPeerID; }
const uint256& getCurrentHash() const { return mCurrentHash; }
const uint256& getPrevLedger() const { return mPreviousLedger; }
+ const uint256& getSuppression() const { return mSuppression; }
uint32 getProposeSeq() const { return mProposeSeq; }
uint32 getCloseTime() const { return mCloseTime; }
const RippleAddress& peekPublic() const { return mPublicKey; }
diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp
index ce52fde7b3..21ce906666 100644
--- a/src/NetworkOPs.cpp
+++ b/src/NetworkOPs.cpp
@@ -115,19 +115,36 @@ Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& t
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans)
{
Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true);
- if (dbtx) return dbtx;
+ if (dbtx)
+ return dbtx;
- if (!trans->checkSign())
- {
- cLog(lsINFO) << "Transaction has bad signature";
+ int newFlags = theApp->getSuppression().getFlags(trans->getID());
+ if ((newFlags & SF_BAD) != 0)
+ { // cached bad
trans->setStatus(INVALID);
return trans;
}
- TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER);
+ if ((newFlags & SF_SIGGOOD) == 0)
+ { // signature not checked
+ if (!trans->checkSign())
+ {
+ cLog(lsINFO) << "Transaction has bad signature";
+ trans->setStatus(INVALID);
+ theApp->isNewFlag(trans->getID(), SF_BAD);
+ return trans;
+ }
+ theApp->isNewFlag(trans->getID(), SF_SIGGOOD);
+ }
+ TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER | tapNO_CHECK_SIGN);
trans->setResult(r);
+ if (isTemMalformed(r)) // malformed, cache bad
+ theApp->isNewFlag(trans->getID(), SF_BAD);
+ else if(isTelLocal(r) || isTerRetry(r)) // can be retried
+ theApp->isNewFlag(trans->getID(), SF_RETRY);
+
#ifdef DEBUG
if (r != tesSUCCESS)
{
@@ -139,9 +156,9 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans)
if (r == tefFAILURE)
throw Fault(IO_ERROR);
- if (r == terPRE_SEQ)
+ if (isTerRetry(r))
{ // transaction should be held
- cLog(lsDEBUG) << "Transaction should be held";
+ cLog(lsDEBUG) << "Transaction should be held: " << r;
trans->setStatus(HELD);
theApp->getMasterTransaction().canonicalize(trans, true);
mLedgerMaster->addHeldTransaction(trans);
@@ -154,12 +171,24 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans)
return trans;
}
+ bool relay = true;
+
if (r == tesSUCCESS)
{
- cLog(lsINFO) << "Transaction is now included";
+ cLog(lsINFO) << "Transaction is now included in open ledger";
trans->setStatus(INCLUDED);
theApp->getMasterTransaction().canonicalize(trans, true);
+ }
+ else
+ {
+ cLog(lsDEBUG) << "Status other than success " << r;
+ if (mMode == omFULL)
+ relay = false;
+ trans->setStatus(INVALID);
+ }
+ if (relay)
+ {
std::set peers;
if (theApp->getSuppression().swapSet(trans->getID(), peers, SF_RELAYED))
{
@@ -168,32 +197,13 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans)
trans->getSTransaction()->add(s);
tx.set_rawtransaction(&s.getData().front(), s.getLength());
tx.set_status(ripple::tsCURRENT);
- tx.set_receivetimestamp(getNetworkTimeNC());
+ tx.set_receivetimestamp(getNetworkTimeNC()); // FIXME: This should be when we received it
PackedMessage::pointer packet = boost::make_shared(tx, ripple::mtTRANSACTION);
theApp->getConnectionPool().relayMessageBut(peers, packet);
}
-
- return trans;
}
- cLog(lsDEBUG) << "Status other than success " << r;
- std::set peers;
-
- if ((mMode != omFULL) && (mMode != omTRACKING) &&
- 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());
- PackedMessage::pointer packet = boost::make_shared(tx, ripple::mtTRANSACTION);
- theApp->getConnectionPool().relayMessageTo(peers, packet);
- }
-
- trans->setStatus(INVALID);
return trans;
}
@@ -694,60 +704,55 @@ bool NetworkOPs::haveConsensusObject()
return mConsensus;
}
-// <-- bool: true to relay
-bool NetworkOPs::recvPropose(const uint256& suppression, uint32 proposeSeq, const uint256& proposeHash,
- const uint256& prevLedger, uint32 closeTime, const std::string& signature,
- const RippleAddress& nodePublic)
+uint256 NetworkOPs::getConsensusLCL()
{
- // JED: does mConsensus need to be locked?
+ if (!haveConsensusObject())
+ return uint256();
+ return mConsensus->getLCL();
+}
- // XXX Validate key.
- // XXX Take a vuc for pubkey.
+void NetworkOPs::processTrustedProposal(LedgerProposal::pointer proposal,
+ boost::shared_ptr set, RippleAddress nodePublic, uint256 checkLedger, bool sigGood)
+{
+ bool relay = true;
if (!haveConsensusObject())
{
cLog(lsINFO) << "Received proposal outside consensus window";
- return mMode != omFULL;
+ if (mMode == omFULL)
+ relay = false;
}
-
- if (mConsensus->isOurPubKey(nodePublic))
+ else
{
- cLog(lsTRACE) << "Received our own validation";
- return false;
- }
+ storeProposal(proposal, nodePublic);
- // Is this node on our UNL?
- if (!theApp->getUNL().nodeInUNL(nodePublic))
- {
- cLog(lsINFO) << "Untrusted proposal: " << nodePublic.humanNodePublic() << " " << proposeHash;
- return true;
- }
+ uint256 consensusLCL = mConsensus->getLCL();
- if (prevLedger.isNonZero())
- { // proposal includes a previous ledger
- LedgerProposal::pointer proposal =
- boost::make_shared(prevLedger, proposeSeq, proposeHash, closeTime, nodePublic);
- if (!proposal->checkSign(signature))
+ if (!set->has_previousledger() && (checkLedger != consensusLCL))
{
- cLog(lsWARNING) << "New-style ledger proposal fails signature check";
- return false;
+ cLog(lsWARNING) << "Have to re-check proposal signature due to consensus view change";
+ assert(proposal->hasSignature());
+ proposal->setPrevLedger(consensusLCL);
+ if (proposal->checkSign())
+ sigGood = true;
+ }
+
+ if (sigGood && (consensusLCL == proposal->getPrevLedger()))
+ {
+ relay = mConsensus->peerPosition(proposal);
+ cLog(lsTRACE) << "Proposal processing finished, relay=" << relay;
}
- if (prevLedger == mConsensus->getLCL())
- return mConsensus->peerPosition(proposal);
- storeProposal(proposal, nodePublic);
- return false;
}
- LedgerProposal::pointer proposal =
- boost::make_shared(mConsensus->getLCL(), proposeSeq, proposeHash, closeTime, nodePublic);
- if (!proposal->checkSign(signature))
- { // Note that if the LCL is different, the signature check will fail
- cLog(lsWARNING) << "Ledger proposal fails signature check";
- proposal->setSignature(signature);
- storeProposal(proposal, nodePublic);
- return false;
+ if (relay)
+ {
+ std::set peers;
+ theApp->getSuppression().swapSet(proposal->getSuppression(), peers, SF_RELAYED);
+ PackedMessage::pointer message = boost::make_shared(*set, ripple::mtPROPOSE_LEDGER);
+ theApp->getConnectionPool().relayMessageBut(peers, message);
}
- return mConsensus->peerPosition(proposal);
+ else
+ cLog(lsINFO) << "Not relaying trusted proposal";
}
SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash)
@@ -761,7 +766,10 @@ bool NetworkOPs::gotTXData(const boost::shared_ptr& peer, const uint256& h
const std::list& nodeIDs, const std::list< std::vector >& nodeData)
{
if (!haveConsensusObject())
+ {
+ cLog(lsWARNING) << "Got TX data with no consensus object";
return false;
+ }
return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData);
}
@@ -777,7 +785,7 @@ bool NetworkOPs::hasTXSet(const boost::shared_ptr& peer, const uint256& se
void NetworkOPs::mapComplete(const uint256& hash, SHAMap::ref map)
{
- if (!haveConsensusObject())
+ if (haveConsensusObject())
mConsensus->mapComplete(hash, map, true);
}
@@ -919,30 +927,25 @@ Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const Ri
return jvObj;
}
-void NetworkOPs::pubAccountInfo(const RippleAddress& naAccountID, const Json::Value& jvObj)
+void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult)
{
- boost::interprocess::sharable_lock sl(mMonitorLock);
-
- subInfoMapType::iterator simIterator = mSubAccountInfo.find(naAccountID.getAccountID());
-
- if (simIterator == mSubAccountInfo.end())
+ Json::Value jvObj = transJson(stTxn, terResult, false, lpCurrent, "transaction");
+
{
- // Address not found do nothing.
- nothing();
- }
- else
- {
- // Found it.
- BOOST_FOREACH(InfoSub* ispListener, simIterator->second)
+ boost::interprocess::sharable_lock sl(mMonitorLock);
+ BOOST_FOREACH(InfoSub* ispListener, mSubRTTransactions)
{
ispListener->send(jvObj);
}
}
+
+ pubAccountTransaction(lpCurrent,stTxn,terResult,false);
}
void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
{
// Don't publish to clients ledgers we don't trust.
+ // TODO: we need to publish old transactions when we get reconnected to the network otherwise clients can miss transactions
if (NetworkOPs::omDISCONNECTED == getOperatingMode())
return;
@@ -964,39 +967,10 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
}
}
}
-
+
{
- boost::interprocess::sharable_lock sl(mMonitorLock);
- if (!mSubAccountTransaction.empty())
- {
- Json::Value jvAccounts(Json::arrayValue);
-
- BOOST_FOREACH(const RippleAddress& naAccountID, getLedgerAffectedAccounts(lpAccepted->getLedgerSeq()))
- {
- jvAccounts.append(Json::Value(naAccountID.humanAccountID()));
- }
-
- Json::Value jvObj(Json::objectValue);
-
- jvObj["type"] = "ledgerClosedAccounts";
- jvObj["ledger_closed_index"] = lpAccepted->getLedgerSeq();
- jvObj["ledger_closed"] = lpAccepted->getHash().ToString();
- jvObj["ledger_closed_time"] = Json::Value::UInt(utFromSeconds(lpAccepted->getCloseTimeNC()));
- jvObj["accounts"] = jvAccounts;
-
- BOOST_FOREACH(InfoSub* ispListener, mSubLedgerAccounts)
- {
- ispListener->send(jvObj);
- }
- }
- }
-
- {
- boost::interprocess::sharable_lock sl(mMonitorLock);
- bool bAll = !mSubTransaction.empty();
- bool bAccounts = !mSubAccountTransaction.empty();
-
- if (bAll || bAccounts)
+ // we don't lock since pubAcceptedTransaction is locking
+ if (!mSubTransactions.empty() || !mSubRTTransactions.empty() || !mSubAccount.empty() || !mSubRTAccount.empty() || !mSubmitMap.empty() )
{
SHAMap& txSet = *lpAccepted->peekTransactionMap();
@@ -1007,36 +981,13 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted)
// XXX Need to give failures too.
TER terResult = tesSUCCESS;
- if (bAll)
- {
- pubTransactionAll(lpAccepted, *stTxn, terResult, true);
- }
-
- if (bAccounts)
- {
- pubTransactionAccounts(lpAccepted, *stTxn, terResult, true);
- }
+ pubAcceptedTransaction(lpAccepted, *stTxn, terResult);
}
+ // TODO: remove old entries from the submit map
}
}
- // Publish bootstrap information for accounts.
- {
- boost::interprocess::scoped_lock sl(mMonitorLock);
- BOOST_FOREACH(const subInfoMapType::iterator::value_type& it, mBootAccountInfo)
- {
- Json::Value jvObj = pubBootstrapAccountInfo(lpAccepted, RippleAddress::createAccountID(it.first));
-
- BOOST_FOREACH(InfoSub* ispListener, it.second)
- {
- ispListener->send(jvObj);
- }
- }
- mBootAccountInfo.clear();
- }
-
- // XXX Publish delta information for accounts.
}
Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terResult, bool bAccepted, Ledger::ref lpCurrent, const std::string& strType)
@@ -1065,103 +1016,100 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terRes
return jvObj;
}
-void NetworkOPs::pubTransactionAll(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, bool bAccepted)
+void NetworkOPs::pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult)
{
- Json::Value jvObj = transJson(stTxn, terResult, bAccepted, lpCurrent, "transaction");
+ Json::Value jvObj = transJson(stTxn, terResult, true, lpCurrent, "transaction");
- BOOST_FOREACH(InfoSub* ispListener, mSubTransaction)
{
- ispListener->send(jvObj);
+ boost::interprocess::sharable_lock sl(mMonitorLock);
+ BOOST_FOREACH(InfoSub* ispListener, mSubTransactions)
+ {
+ ispListener->send(jvObj);
+ }
+
+ BOOST_FOREACH(InfoSub* ispListener, mSubRTTransactions)
+ {
+ ispListener->send(jvObj);
+ }
}
+
+ pubAccountTransaction(lpCurrent,stTxn,terResult,true);
}
-void NetworkOPs::pubTransactionAccounts(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, bool bAccepted)
+
+// TODO: tell the mSubmitMap people
+void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, bool bAccepted)
{
- boost::unordered_set usisNotify;
+ boost::unordered_set notify;
{
boost::interprocess::sharable_lock sl(mMonitorLock);
- if (!mSubAccountTransaction.empty())
+ if(!bAccepted && mSubRTAccount.empty()) return;
+
+ if (!mSubAccount.empty() || (!mSubRTAccount.empty()) )
{
BOOST_FOREACH(const RippleAddress& naAccountPublic, stTxn.getAffectedAccounts())
{
- subInfoMapIterator simiIt = mSubAccountTransaction.find(naAccountPublic.getAccountID());
+ subInfoMapIterator simiIt = mSubRTAccount.find(naAccountPublic.getAccountID());
- if (simiIt != mSubAccountTransaction.end())
+ if (simiIt != mSubRTAccount.end())
{
BOOST_FOREACH(InfoSub* ispListener, simiIt->second)
{
- usisNotify.insert(ispListener);
+ notify.insert(ispListener);
+ }
+ }
+ if(bAccepted)
+ {
+ simiIt = mSubAccount.find(naAccountPublic.getAccountID());
+
+ if (simiIt != mSubAccount.end())
+ {
+ BOOST_FOREACH(InfoSub* ispListener, simiIt->second)
+ {
+ notify.insert(ispListener);
+ }
}
}
}
}
}
- if (!usisNotify.empty())
+ if (!notify.empty())
{
Json::Value jvObj = transJson(stTxn, terResult, bAccepted, lpCurrent, "account");
- BOOST_FOREACH(InfoSub* ispListener, usisNotify)
+ BOOST_FOREACH(InfoSub* ispListener, notify)
{
ispListener->send(jvObj);
}
}
}
-void NetworkOPs::pubTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult)
-{
- boost::interprocess::sharable_lock sl(mMonitorLock);
-
- if (!mSubTransaction.empty())
- {
- pubTransactionAll(lpCurrent, stTxn, terResult, false);
- }
-
- if (!mSubAccountTransaction.empty())
- {
- pubTransactionAccounts(lpCurrent, stTxn, terResult, false);
- }
-}
-
//
// Monitoring
//
-void NetworkOPs::subAccountInfo(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs)
+
+
+void NetworkOPs::subAccount(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs,bool rt)
{
+ subInfoMapType& subMap=mSubAccount;
+ if(rt) subMap=mSubRTAccount;
+
boost::interprocess::scoped_lock sl(mMonitorLock);
BOOST_FOREACH(const RippleAddress& naAccountID, vnaAccountIDs)
{
- // Register for bootstrap info.
- subInfoMapType::iterator simIterator;
-
- simIterator = mBootAccountInfo.find(naAccountID.getAccountID());
- if (simIterator == mBootAccountInfo.end())
+ subInfoMapType::iterator simIterator = subMap.find(naAccountID.getAccountID());
+ if (simIterator == subMap.end())
{
// Not found
boost::unordered_set usisElement;
usisElement.insert(ispListener);
- mBootAccountInfo.insert(simIterator, make_pair(naAccountID.getAccountID(), usisElement));
- }
- else
- {
- // Found
- simIterator->second.insert(ispListener);
- }
-
- // Register for messages.
- simIterator = mSubAccountInfo.find(naAccountID.getAccountID());
- if (simIterator == mSubAccountInfo.end())
- {
- // Not found
- boost::unordered_set usisElement;
-
- usisElement.insert(ispListener);
- mSubAccountInfo.insert(simIterator, make_pair(naAccountID.getAccountID(), usisElement));
+ mSubAccount.insert(simIterator, make_pair(naAccountID.getAccountID(), usisElement));
}
else
{
@@ -1171,14 +1119,16 @@ void NetworkOPs::subAccountInfo(InfoSub* ispListener, const boost::unordered_set
}
}
-void NetworkOPs::unsubAccountInfo(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs)
+void NetworkOPs::unsubAccount(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs,bool rt)
{
+ subInfoMapType& subMap= rt ? mSubRTAccount : mSubAccount;
+
boost::interprocess::scoped_lock sl(mMonitorLock);
BOOST_FOREACH(const RippleAddress& naAccountID, vnaAccountIDs)
{
- subInfoMapType::iterator simIterator = mSubAccountInfo.find(naAccountID.getAccountID());
- if (simIterator == mSubAccountInfo.end())
+ subInfoMapType::iterator simIterator = subMap.find(naAccountID.getAccountID());
+ if (simIterator == mSubAccount.end())
{
// Not found. Done.
nothing();
@@ -1191,56 +1141,7 @@ void NetworkOPs::unsubAccountInfo(InfoSub* ispListener, const boost::unordered_s
if (simIterator->second.empty())
{
// Don't need hash entry.
- mSubAccountInfo.erase(simIterator);
- }
- }
- }
-}
-
-void NetworkOPs::subAccountTransaction(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs)
-{
- boost::interprocess::scoped_lock sl(mMonitorLock);
-
- BOOST_FOREACH(const RippleAddress& naAccountID, vnaAccountIDs)
- {
- subInfoMapType::iterator simIterator = mSubAccountTransaction.find(naAccountID.getAccountID());
- if (simIterator == mSubAccountTransaction.end())
- {
- // Not found
- boost::unordered_set usisElement;
-
- usisElement.insert(ispListener);
- mSubAccountTransaction.insert(simIterator, make_pair(naAccountID.getAccountID(), usisElement));
- }
- else
- {
- // Found
- simIterator->second.insert(ispListener);
- }
- }
-}
-
-void NetworkOPs::unsubAccountTransaction(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs)
-{
- boost::interprocess::scoped_lock sl(mMonitorLock);
-
- BOOST_FOREACH(const RippleAddress& naAccountID, vnaAccountIDs)
- {
- subInfoMapType::iterator simIterator = mSubAccountTransaction.find(naAccountID.getAccountID());
- if (simIterator == mSubAccountTransaction.end())
- {
- // Not found. Done.
- nothing();
- }
- else
- {
- // Found
- simIterator->second.erase(ispListener);
-
- if (simIterator->second.empty())
- {
- // Don't need hash entry.
- mSubAccountTransaction.erase(simIterator);
+ subMap.erase(simIterator);
}
}
}
@@ -1292,27 +1193,39 @@ bool NetworkOPs::unsubLedger(InfoSub* ispListener)
}
// <-- bool: true=added, false=already there
-bool NetworkOPs::subLedgerAccounts(InfoSub* ispListener)
+bool NetworkOPs::subServer(InfoSub* ispListener)
{
- return mSubLedgerAccounts.insert(ispListener).second;
+ return mSubServer.insert(ispListener).second;
}
// <-- bool: true=erased, false=was not there
-bool NetworkOPs::unsubLedgerAccounts(InfoSub* ispListener)
+bool NetworkOPs::unsubServer(InfoSub* ispListener)
{
- return !!mSubLedgerAccounts.erase(ispListener);
+ return !!mSubServer.erase(ispListener);
}
// <-- bool: true=added, false=already there
-bool NetworkOPs::subTransaction(InfoSub* ispListener)
+bool NetworkOPs::subTransactions(InfoSub* ispListener)
{
- return mSubTransaction.insert(ispListener).second;
+ return mSubTransactions.insert(ispListener).second;
}
// <-- bool: true=erased, false=was not there
-bool NetworkOPs::unsubTransaction(InfoSub* ispListener)
+bool NetworkOPs::unsubTransactions(InfoSub* ispListener)
{
- return !!mSubTransaction.erase(ispListener);
+ return !!mSubTransactions.erase(ispListener);
+}
+
+// <-- bool: true=added, false=already there
+bool NetworkOPs::subRTTransactions(InfoSub* ispListener)
+{
+ return mSubTransactions.insert(ispListener).second;
+}
+
+// <-- bool: true=erased, false=was not there
+bool NetworkOPs::unsubRTTransactions(InfoSub* ispListener)
+{
+ return !!mSubTransactions.erase(ispListener);
}
// vim:ts=4
diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h
index cd5243b262..b14b06e09a 100644
--- a/src/NetworkOPs.h
+++ b/src/NetworkOPs.h
@@ -51,6 +51,8 @@ protected:
typedef boost::unordered_map >::value_type subInfoMapValue;
typedef boost::unordered_map >::iterator subInfoMapIterator;
+ typedef boost::unordered_map > subSubmitMapType;
+
OperatingMode mMode;
bool mNeedNetworkLedger;
boost::posix_time::ptime mConnectTime;
@@ -72,24 +74,26 @@ protected:
// XXX Split into more locks.
boost::interprocess::interprocess_upgradable_mutex mMonitorLock;
- subInfoMapType mBootAccountInfo;
- subInfoMapType mSubAccountInfo;
- subInfoMapType mSubAccountTransaction;
- boost::unordered_set mSubLedger; // ledger accepteds
- boost::unordered_set mSubLedgerAccounts; // ledger accepteds + affected accounts
- boost::unordered_set mSubTransaction; // all transactions
- boost::unordered_set mSubTxMeta; // all transaction meta
-// subInfoMapType mSubTransactionAccounts;
+ subInfoMapType mSubAccount;
+ subInfoMapType mSubRTAccount;
+ subSubmitMapType mSubmitMap;
+
+ boost::unordered_set mSubLedger; // accepted ledgers
+ boost::unordered_set mSubServer; // when server changes connectivity state
+ boost::unordered_set mSubTransactions; // all accepted transactions
+ boost::unordered_set mSubRTTransactions; // all proposed and accepted transactions
+
void setMode(OperatingMode);
Json::Value transJson(const SerializedTransaction& stTxn, TER terResult, bool bAccepted, Ledger::ref lpCurrent, const std::string& strType);
- void pubTransactionAll(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, bool bAccepted);
- void pubTransactionAccounts(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, bool bAccepted);
bool haveConsensusObject();
Json::Value pubBootstrapAccountInfo(Ledger::ref lpAccepted, const RippleAddress& naAccountID);
+ void pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult);
+ void pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult,bool accepted);
+
public:
NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster);
@@ -168,8 +172,8 @@ public:
const std::vector& myNode, std::list< std::vector >& newNodes);
// ledger proposal/close functions
- bool recvPropose(const uint256& suppression, uint32 proposeSeq, const uint256& proposeHash,
- const uint256& prevLedger, uint32 closeTime, const std::string& signature, const RippleAddress& nodePublic);
+ void processTrustedProposal(LedgerProposal::pointer proposal, boost::shared_ptr set,
+ RippleAddress nodePublic, uint256 checkLedger, bool sigGood);
bool gotTXData(const boost::shared_ptr& peer, const uint256& hash,
const std::list& nodeIDs, const std::list< std::vector >& nodeData);
bool recvValidation(const SerializedValidation::pointer& val);
@@ -199,6 +203,7 @@ public:
boost::unordered_map >& peekStoredProposals() { return mStoredProposals; }
void storeProposal(const LedgerProposal::pointer& proposal, const RippleAddress& peerPublic);
+ uint256 getConsensusLCL();
// client information retrieval functions
std::vector< std::pair >
@@ -209,33 +214,27 @@ public:
//
// Monitoring: publisher side
//
-
- void pubAccountInfo(const RippleAddress& naAccountID, const Json::Value& jvObj);
void pubLedger(Ledger::ref lpAccepted);
- void pubTransaction(Ledger::ref lpLedger, const SerializedTransaction& stTxn, TER terResult);
+ void pubProposedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult);
+
//
// Monitoring: subscriber side
//
-
- // --> vnaAddress: empty = all
- void subAccountInfo(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs);
- void unsubAccountInfo(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs);
-
- void subAccountTransaction(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs);
- void unsubAccountTransaction(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs);
-
- // void subAccountChanges(InfoSub* ispListener, const uint256 uLedgerHash);
- // void unsubAccountChanges(InfoSub* ispListener);
+ void subAccount(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs,bool rt);
+ void unsubAccount(InfoSub* ispListener, const boost::unordered_set& vnaAccountIDs,bool rt);
bool subLedger(InfoSub* ispListener);
bool unsubLedger(InfoSub* ispListener);
- bool subLedgerAccounts(InfoSub* ispListener);
- bool unsubLedgerAccounts(InfoSub* ispListener);
+ bool subServer(InfoSub* ispListener);
+ bool unsubServer(InfoSub* ispListener);
- bool subTransaction(InfoSub* ispListener);
- bool unsubTransaction(InfoSub* ispListener);
+ bool subTransactions(InfoSub* ispListener);
+ bool unsubTransactions(InfoSub* ispListener);
+
+ bool subRTTransactions(InfoSub* ispListener);
+ bool unsubRTTransactions(InfoSub* ispListener);
};
#endif
diff --git a/src/Operation.h b/src/Operation.h
index b2946f2945..5c0c6b8d1a 100644
--- a/src/Operation.h
+++ b/src/Operation.h
@@ -276,7 +276,7 @@ public:
}
};
-class SendXNSOp : public Operation
+class SendXRPOp : public Operation
{
public:
bool work(Interpreter* interpreter)
diff --git a/src/OrderBookDB.cpp b/src/OrderBookDB.cpp
index 4f49f01338..ca06acd9b5 100644
--- a/src/OrderBookDB.cpp
+++ b/src/OrderBookDB.cpp
@@ -20,8 +20,8 @@ OrderBookDB::OrderBookDB(Ledger::pointer ledger)
mKnownMap[book->getBookBase()]=true;
if(!book->getCurrencyIn())
- { // XNS
- mXNSOrders.push_back(book);
+ { // XRP
+ mXRPOrders.push_back(book);
}else
{
mIssuerMap[book->getIssuerIn()].push_back(book);
diff --git a/src/OrderBookDB.h b/src/OrderBookDB.h
index c8e598d186..206898dadc 100644
--- a/src/OrderBookDB.h
+++ b/src/OrderBookDB.h
@@ -9,7 +9,7 @@ But for now it is probably faster to just generate it each time
class OrderBookDB
{
std::vector mEmptyVector;
- std::vector mXNSOrders;
+ std::vector mXRPOrders;
std::map > mIssuerMap;
std::map mKnownMap;
@@ -17,8 +17,8 @@ class OrderBookDB
public:
OrderBookDB(Ledger::pointer ledger);
- // return list of all orderbooks that want XNS
- std::vector& getXNSInBooks(){ return mXNSOrders; }
+ // return list of all orderbooks that want XRP
+ std::vector& getXRPInBooks(){ return mXRPOrders; }
// return list of all orderbooks that want IssuerID
std::vector& getBooks(const uint160& issuerID);
// return list of all orderbooks that want this issuerID and currencyID
diff --git a/src/Pathfinder.cpp b/src/Pathfinder.cpp
index 407d2f894f..318d763719 100644
--- a/src/Pathfinder.cpp
+++ b/src/Pathfinder.cpp
@@ -21,18 +21,18 @@ TODO: what is a good way to come up with multiple paths?
OrderDB:
- getXNSOffers();
+ getXRPOffers();
- // return list of all orderbooks that want XNS
+ // return list of all orderbooks that want XRP
// return list of all orderbooks that want IssuerID
// return list of all orderbooks that want this issuerID and currencyID
*/
/*
-Test sending to XNS
-Test XNS to XNS
+Test sending to XRP
+Test XRP to XRP
Test offer in middle
-Test XNS to USD
+Test XRP to USD
Test USD to EUR
*/
@@ -113,7 +113,7 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet
// found the destination
if (!ele.mCurrencyID) {
- BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXNSInBooks())
+ BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXRPInBooks())
{
//if (!path.hasSeen(line->getAccountIDPeer().getAccountID()))
{
@@ -188,8 +188,8 @@ bool Pathfinder::checkComplete(STPathSet& retPathSet)
// get all the options from this accountID
-// if source is XNS
-// every offer that wants XNS
+// if source is XRP
+// every offer that wants XRP
// else
// every ripple line that starts with the source currency
// every offer that we can take that wants the source currency
@@ -197,8 +197,8 @@ bool Pathfinder::checkComplete(STPathSet& retPathSet)
void Pathfinder::addOptions(PathOption::pointer tail)
{
if(!tail->mCurrencyID)
- { // source XNS
- BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXNSInBooks())
+ { // source XRP
+ BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXRPInBooks())
{
PathOption::pointer pathOption(new PathOption(tail));
diff --git a/src/Peer.cpp b/src/Peer.cpp
index c9c6df5dbf..5e4b121288 100644
--- a/src/Peer.cpp
+++ b/src/Peer.cpp
@@ -500,8 +500,8 @@ void Peer::processReadBuffer()
case ripple::mtPROPOSE_LEDGER:
{
- ripple::TMProposeSet msg;
- if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
+ boost::shared_ptr msg = boost::make_shared();
+ if (msg->ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
recvPropose(msg);
else
cLog(lsWARNING) << "parse error: " << type;
@@ -694,6 +694,42 @@ void Peer::recvHello(ripple::TMHello& packet)
}
}
+static void checkTransaction(Job&, int flags, SerializedTransaction::pointer stx, boost::weak_ptr peer)
+{
+
+#ifndef TRUST_NETWORK
+ try
+ {
+#endif
+ Transaction::pointer tx;
+
+ if ((flags & SF_SIGGOOD) != 0)
+ {
+ tx = boost::make_shared(stx, true);
+ if (tx->getStatus() == INVALID)
+ {
+ theApp->getSuppression().setFlag(stx->getTransactionID(), SF_BAD);
+ Peer::punishPeer(peer, PP_BAD_SIGNATURE);
+ return;
+ }
+ else
+ theApp->getSuppression().setFlag(stx->getTransactionID(), SF_SIGGOOD);
+ }
+ else
+ tx = boost::make_shared(stx, false);
+
+ theApp->getIOService().post(boost::bind(&NetworkOPs::processTransaction, &theApp->getOPs(), tx));
+
+#ifndef TRUST_NETWORK
+ }
+ catch (...)
+ {
+ theApp->getSuppression().setFlags(stx->getTransactionID(), SF_BAD);
+ punishPeer(peer, PP_INVALID_REQUEST);
+ }
+#endif
+}
+
void Peer::recvTransaction(ripple::TMTransaction& packet)
{
cLog(lsDEBUG) << "Got transaction from peer";
@@ -708,12 +744,22 @@ void Peer::recvTransaction(ripple::TMTransaction& packet)
SerializerIterator sit(s);
SerializedTransaction::pointer stx = boost::make_shared(boost::ref(sit));
- if (!theApp->isNew(stx->getTransactionID(), mPeerId))
- return;
+ int flags;
+ if (!theApp->isNew(stx->getTransactionID(), mPeerId, flags))
+ { // we have seen this transaction recently
+ if ((flags & SF_BAD) != 0)
+ {
+ punishPeer(PP_BAD_SIGNATURE);
+ return;
+ }
+
+ if ((flags & SF_RETRY) == 0)
+ return;
+ }
+
+ theApp->getJobQueue().addJob(jtTRANSACTION,
+ boost::bind(&checkTransaction, _1, flags, stx, boost::weak_ptr(shared_from_this())));
- tx = boost::make_shared(stx, true);
- if (tx->getStatus() == INVALID)
- throw(0);
#ifndef TRUST_NETWORK
}
catch (...)
@@ -727,52 +773,122 @@ void Peer::recvTransaction(ripple::TMTransaction& packet)
}
#endif
- tx = theApp->getOPs().processTransaction(tx);
-
- if(tx->getStatus() != INCLUDED)
- { // transaction wasn't accepted into ledger
-#ifdef DEBUG
- std::cerr << "Transaction from peer won't go in ledger" << std::endl;
-#endif
- }
}
-void Peer::recvPropose(ripple::TMProposeSet& packet)
+static void checkPropose(Job& job, boost::shared_ptr packet,
+ LedgerProposal::pointer proposal, uint256 consensusLCL, RippleAddress nodePublic, boost::weak_ptr peer)
{
- if ((packet.currenttxhash().size() != 32) || (packet.nodepubkey().size() < 28) ||
- (packet.signature().size() < 56) || (packet.nodepubkey().size() > 128) || (packet.signature().size() > 128))
+ bool sigGood = false;
+ bool isTrusted = (job.getType() == jtPROPOSAL_t);
+
+ cLog(lsTRACE) << "Checking " << (isTrusted ? "trusted" : "UNtrusted") << " proposal";
+
+ assert(packet);
+ ripple::TMProposeSet& set = *packet;
+
+ uint256 prevLedger;
+ if (set.has_previousledger())
+ { // proposal includes a previous ledger
+ cLog(lsTRACE) << "proposal with previous ledger";
+ memcpy(prevLedger.begin(), set.previousledger().data(), 256 / 8);
+ if (!proposal->checkSign(set.signature()))
+ {
+ cLog(lsWARNING) << "proposal with previous ledger fails signature check";
+ Peer::punishPeer(peer, PP_BAD_SIGNATURE);
+ return;
+ }
+ else
+ sigGood = true;
+ }
+ else
+ {
+ if (consensusLCL.isNonZero() && proposal->checkSign(set.signature()))
+ {
+ prevLedger = consensusLCL;
+ sigGood = true;
+ }
+ else
+ {
+ cLog(lsWARNING) << "Ledger proposal fails signature check";
+ proposal->setSignature(set.signature());
+ }
+ }
+
+ if (isTrusted)
+ {
+ theApp->getIOService().post(boost::bind(&NetworkOPs::processTrustedProposal, &theApp->getOPs(),
+ proposal, packet, nodePublic, prevLedger, sigGood));
+ }
+ else if (sigGood && (prevLedger == consensusLCL))
+ { // relay untrusted proposal
+ cLog(lsTRACE) << "relaying untrusted proposal";
+ std::set peers;
+ theApp->getSuppression().swapSet(proposal->getSuppression(), peers, SF_RELAYED);
+ PackedMessage::pointer message = boost::make_shared(set, ripple::mtPROPOSE_LEDGER);
+ theApp->getConnectionPool().relayMessageBut(peers, message);
+ }
+ else
+ cLog(lsDEBUG) << "Not relaying untrusted proposal";
+}
+
+void Peer::recvPropose(const boost::shared_ptr& packet)
+{
+ assert(packet);
+ ripple::TMProposeSet& set = *packet;
+
+ if ((set.currenttxhash().size() != 32) || (set.nodepubkey().size() < 28) ||
+ (set.signature().size() < 56) || (set.nodepubkey().size() > 128) || (set.signature().size() > 128))
{
cLog(lsWARNING) << "Received proposal is malformed";
+ punishPeer(PP_INVALID_REQUEST);
return;
}
- uint256 currentTxHash, prevLedger;
- memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32);
+ if (set.has_previousledger() && (set.previousledger().size() != 32))
+ {
+ cLog(lsWARNING) << "Received proposal is malformed";
+ punishPeer(PP_INVALID_REQUEST);
+ return;
+ }
- if ((packet.has_previousledger()) && (packet.previousledger().size() == 32))
- memcpy(prevLedger.begin(), packet.previousledger().data(), 32);
+ uint256 proposeHash, prevLedger;
+ memcpy(proposeHash.begin(), set.currenttxhash().data(), 32);
+ if (set.has_previousledger())
+ memcpy(prevLedger.begin(), set.previousledger().data(), 32);
Serializer s(512);
- s.add256(currentTxHash);
- s.add256(prevLedger);
- s.add32(packet.proposeseq());
- s.add32(packet.closetime());
- s.addVL(packet.nodepubkey());
- s.addVL(packet.signature());
+ s.add256(proposeHash);
+ s.add32(set.proposeseq());
+ s.add32(set.closetime());
+ s.addVL(set.nodepubkey());
+ s.addVL(set.signature());
+ if (set.has_previousledger())
+ s.add256(prevLedger);
uint256 suppression = s.getSHA512Half();
if (!theApp->isNew(suppression, mPeerId))
+ {
+ cLog(lsTRACE) << "Received duplicate proposal from peer " << mPeerId;
return;
-
- RippleAddress nodePublic = RippleAddress::createNodePublic(strCopy(packet.nodepubkey()));
-// bool isTrusted = theApp->getUNL().nodeInUNL(nodePublic);
-
- if(theApp->getOPs().recvPropose(suppression, packet.proposeseq(), currentTxHash, prevLedger, packet.closetime(),
- packet.signature(), nodePublic))
- { // FIXME: Not all nodes will want proposals
- PackedMessage::pointer message = boost::make_shared(packet, ripple::mtPROPOSE_LEDGER);
- theApp->getConnectionPool().relayMessage(this, message);
}
+
+ RippleAddress signerPublic = RippleAddress::createNodePublic(strCopy(set.nodepubkey()));
+ if (signerPublic == theConfig.VALIDATION_PUB)
+ {
+ cLog(lsTRACE) << "Received our own proposal from peer " << mPeerId;
+ return;
+ }
+ bool isTrusted = theApp->getUNL().nodeInUNL(signerPublic);
+ cLog(lsTRACE) << "Received " << (isTrusted ? "trusted" : "UNtrusted") << " proposal from " << mPeerId;
+
+ uint256 consensusLCL = theApp->getOPs().getConsensusLCL();
+ LedgerProposal::pointer proposal = boost::make_shared(
+ prevLedger.isNonZero() ? prevLedger : consensusLCL,
+ set.proposeseq(), proposeHash, set.closetime(), signerPublic, suppression);
+
+ theApp->getJobQueue().addJob(isTrusted ? jtPROPOSAL_t : jtPROPOSAL_ut,
+ boost::bind(&checkPropose, _1, packet, proposal, consensusLCL,
+ mNodePublic, boost::weak_ptr(shared_from_this())));
}
void Peer::recvHaveTxSet(ripple::TMHaveTransactionSet& packet)
@@ -1043,11 +1159,12 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
reply.set_requestcookie(packet.requestcookie());
if (packet.itype() == ripple::liTS_CANDIDATE)
- { // Request is for a transaction candidate set
+ { // Request is for a transaction candidate set
cLog(lsINFO) << "Received request for TX candidate set data " << getIP();
if ((!packet.has_ledgerhash() || packet.ledgerhash().size() != 32))
{
punishPeer(PP_INVALID_REQUEST);
+ cLog(lsWARNING) << "invalid request";
return;
}
uint256 txHash;
@@ -1171,6 +1288,7 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
SHAMapNode mn(packet.nodeids(i).data(), packet.nodeids(i).size());
if(!mn.isValid())
{
+ cLog(lsWARNING) << "Request for invalid node";
punishPeer(PP_INVALID_REQUEST);
return;
}
@@ -1178,6 +1296,8 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
std::list< std::vector > rawNodes;
if(map->getNodeFat(mn, nodeIDs, rawNodes, fatRoot, fatLeaves))
{
+ assert(nodeIDs.size() == rawNodes.size());
+ cLog(lsDEBUG) << "getNodeFat got " << rawNodes.size() << " nodes";
std::vector::iterator nodeIDIterator;
std::list< std::vector >::iterator rawNodeIterator;
for(nodeIDIterator = nodeIDs.begin(), rawNodeIterator = rawNodes.begin();
@@ -1190,6 +1310,8 @@ void Peer::recvGetLedger(ripple::TMGetLedger& packet)
node->set_nodedata(&rawNodeIterator->front(), rawNodeIterator->size());
}
}
+ else
+ cLog(lsWARNING) << "getNodeFat returns false";
}
PackedMessage::pointer oPacket = boost::make_shared(reply, ripple::mtLEDGER_DATA);
sendPacket(oPacket);
@@ -1199,7 +1321,7 @@ void Peer::recvLedger(ripple::TMLedgerData& packet)
{
if (packet.nodes().size() <= 0)
{
- cLog(lsWARNING) << "Ledger data with no nodes";
+ cLog(lsWARNING) << "Ledger/TXset data with no nodes";
punishPeer(PP_INVALID_REQUEST);
return;
}
@@ -1209,6 +1331,7 @@ void Peer::recvLedger(ripple::TMLedgerData& packet)
uint256 hash;
if(packet.ledgerhash().size() != 32)
{
+ cLog(lsWARNING) << "TX candidate reply with invalid hash size";
punishPeer(PP_INVALID_REQUEST);
return;
}
@@ -1368,7 +1491,7 @@ Json::Value Peer::getJson()
if (mHello.has_protoversion() &&
(mHello.protoversion() != MAKE_VERSION_INT(PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR)))
- ret["protocol"] = boost::lexical_cast(GET_VERSION_MAJOR(mHello.protoversion())) + "." +
+ ret["protocol"] = boost::lexical_cast(GET_VERSION_MAJOR(mHello.protoversion())) + "." +
boost::lexical_cast(GET_VERSION_MINOR(mHello.protoversion()));
if (!!mClosedLedgerHash)
diff --git a/src/Peer.h b/src/Peer.h
index 256319c831..e70d702fb0 100644
--- a/src/Peer.h
+++ b/src/Peer.h
@@ -19,6 +19,7 @@ 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_BAD_SIGNATURE = 4, // Object had bad signature
};
typedef std::pair ipPort;
@@ -116,7 +117,7 @@ protected:
void recvGetLedger(ripple::TMGetLedger& packet);
void recvLedger(ripple::TMLedgerData& packet);
void recvStatus(ripple::TMStatusChange& packet);
- void recvPropose(ripple::TMProposeSet& packet);
+ void recvPropose(const boost::shared_ptr& packet);
void recvHaveTxSet(ripple::TMHaveTransactionSet& packet);
void getSessionCookie(std::string& strDst);
diff --git a/src/RPCDoor.cpp b/src/RPCDoor.cpp
index 5fb00a3ffc..9d98a24624 100644
--- a/src/RPCDoor.cpp
+++ b/src/RPCDoor.cpp
@@ -14,6 +14,10 @@ RPCDoor::RPCDoor(boost::asio::io_service& io_service) :
Log(lsINFO) << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
startListening();
}
+RPCDoor::~RPCDoor()
+{
+ Log(lsINFO) << "RPC port: " << theConfig.RPC_IP << " " << theConfig.RPC_PORT << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
+}
void RPCDoor::startListening()
{
diff --git a/src/RPCDoor.h b/src/RPCDoor.h
index f91f864855..ab60539c67 100644
--- a/src/RPCDoor.h
+++ b/src/RPCDoor.h
@@ -15,4 +15,5 @@ class RPCDoor
bool isClientAllowed(const std::string& ip);
public:
RPCDoor(boost::asio::io_service& io_service);
+ ~RPCDoor();
};
diff --git a/src/RPCHandler.cpp b/src/RPCHandler.cpp
index a609e3567a..fe98e650cd 100644
--- a/src/RPCHandler.cpp
+++ b/src/RPCHandler.cpp
@@ -248,7 +248,7 @@ Json::Value RPCHandler::authorize(const uint256& uLedger,
if (saSrcBalance < saFee)
{
- cLog(lsINFO) << "authorize: Insufficent funds for fees: fee=" << saFee.getText() << " balance=" << saSrcBalance.getText();
+ cLog(lsINFO) << "authorize: Insufficient funds for fees: fee=" << saFee.getText() << " balance=" << saSrcBalance.getText();
return rpcError(rpcINSUF_FUNDS);
}
@@ -326,125 +326,7 @@ Json::Value RPCHandler::doAcceptLedger(const Json::Value ¶ms)
return obj;
}
-// account_domain_set []
-Json::Value RPCHandler::doAccountDomainSet(const Json::Value ¶ms)
-{
- RippleAddress naSrcAccountID;
- RippleAddress naSeed;
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
-
- RippleAddress naVerifyGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
-
- if (!obj.empty())
- return obj;
-
- Transaction::pointer trans = Transaction::sharedAccountSet(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- false,
- uint128(),
- false,
- 0,
- 0,
- RippleAddress(),
- true,
- strCopy(params[2u].asString()),
- false,
- 0);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return Json::Value(Json::objectValue);
-}
-
-// account_email_set []
-Json::Value RPCHandler::doAccountEmailSet(const Json::Value ¶ms)
-{
- RippleAddress naSrcAccountID;
- RippleAddress naSeed;
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
-
- RippleAddress naVerifyGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
-
- if (!obj.empty())
- return obj;
-
- // Hash as per: http://en.gravatar.com/site/implement/hash/
- std::string strEmail = 3 == params.size() ? params[2u].asString() : "";
- boost::trim(strEmail);
- boost::to_lower(strEmail);
-
- std::vector vucMD5(128/8, 0);
- MD5(reinterpret_cast(strEmail.data()), strEmail.size(), &vucMD5.front());
-
- uint128 uEmailHash(vucMD5);
- std::vector vucDomain;
-
- Transaction::pointer trans = Transaction::sharedAccountSet(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- true,
- strEmail.empty() ? uint128() : uEmailHash,
- false,
- uint256(),
- 0,
- RippleAddress(),
- false,
- vucDomain,
- false,
- 0);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- if (!strEmail.empty())
- {
- obj["Email"] = strEmail;
- obj["EmailHash"] = strHex(vucMD5);
- obj["UrlGravatar"] = AccountState::createGravatarUrl(uEmailHash);
- }
-
- return obj;
-}
// account_info ||
// account_info || []
@@ -498,177 +380,6 @@ Json::Value RPCHandler::doAccountInfo(const Json::Value ¶ms)
-// account_message_set
-Json::Value RPCHandler::doAccountMessageSet(const Json::Value& params) {
- RippleAddress naSrcAccountID;
- RippleAddress naSeed;
- RippleAddress naMessagePubKey;
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
- else if (!naMessagePubKey.setAccountPublic(params[2u].asString()))
- {
- return rpcError(rpcPUBLIC_MALFORMED);
- }
-
- RippleAddress naVerifyGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
- std::vector vucDomain;
-
- if (!obj.empty())
- return obj;
-
- Transaction::pointer trans = Transaction::sharedAccountSet(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- false,
- uint128(),
- false,
- uint256(),
- 0,
- naMessagePubKey,
- false,
- vucDomain,
- false,
- 0);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
- obj["MessageKey"] = naMessagePubKey.humanAccountPublic();
-
- return obj;
-}
-
-// account_rate_set
-Json::Value RPCHandler::doAccountRateSet(const Json::Value ¶ms)
-{
- RippleAddress naSrcAccountID;
- RippleAddress naSeed;
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
-
- RippleAddress naVerifyGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator);
-
- if (!obj.empty())
- return obj;
-
- uint32 uRate = lexical_cast_s(params[2u].asString());
- std::vector vucDomain;
-
- Transaction::pointer trans = Transaction::sharedAccountSet(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- false,
- uint128(),
- false,
- 0,
- 0,
- RippleAddress(),
- false,
- vucDomain,
- true,
- uRate);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return Json::Value(Json::objectValue);
-}
-
-// account_wallet_set []
-Json::Value RPCHandler::doAccountWalletSet(const Json::Value& params) {
- RippleAddress naSrcAccountID;
- RippleAddress naSeed;
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
-
- RippleAddress naMasterGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
- std::vector vucDomain;
-
- if (!obj.empty())
- return obj;
-
- std::string strWalletLocator = params.size() == 3 ? params[2u].asString() : "";
- uint256 uWalletLocator;
- uint32 uWalletSize = 0; // XXX Broken should be an argument.
-
- if (!strWalletLocator.empty())
- uWalletLocator.SetHex(strWalletLocator);
-
- Transaction::pointer trans = Transaction::sharedAccountSet(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- false,
- uint128(),
- true,
- uWalletLocator,
- uWalletSize,
- RippleAddress(),
- false,
- vucDomain,
- false,
- 0);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- if (!strWalletLocator.empty())
- obj["WalletLocator"] = uWalletLocator.GetHex();
-
- return obj;
-}
Json::Value RPCHandler::doConnect(const Json::Value& params)
{
@@ -782,192 +493,6 @@ Json::Value RPCHandler::doNicknameInfo(const Json::Value& params)
return ret;
}
-// nickname_set [] []
-Json::Value RPCHandler::doNicknameSet(const Json::Value& params)
-{
- RippleAddress naSrcAccountID;
- RippleAddress naSeed;
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
-
- STAmount saMinimumOffer;
- bool bSetOffer = params.size() >= 4;
- std::string strOfferCurrency;
- std::string strNickname = params[2u].asString();
- boost::trim(strNickname);
-
- if (strNickname.empty())
- {
- return rpcError(rpcNICKNAME_MALFORMED);
- }
- else if (params.size() >= 4 && !saMinimumOffer.setFullValue(params[3u].asString(), strOfferCurrency))
- {
- return rpcError(rpcDST_AMT_MALFORMED);
- }
-
- STAmount saFee;
- NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname);
-
- if (!nsSrc)
- {
- // Creating nickname.
- saFee = theConfig.FEE_NICKNAME_CREATE;
- }
- else if (naSrcAccountID != nsSrc->getAccountID())
- {
- // We don't own the nickname.
- return rpcError(rpcNICKNAME_PERM);
- }
- else
- {
- // Setting the minimum offer.
- saFee = theConfig.FEE_DEFAULT;
- }
-
- RippleAddress naMasterGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, saFee, asSrc, naMasterGenerator);
-
- if (!obj.empty())
- return obj;
-
- // YYY Could verify nickname does not exist or points to paying account.
- // XXX Adjust fee for nickname create.
-
- Transaction::pointer trans = Transaction::sharedNicknameSet(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- saFee,
- 0, // YYY No source tag
- Ledger::getNicknameHash(strNickname),
- bSetOffer,
- saMinimumOffer);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return obj;
-}
-
-// offer_create [passive]
-// *offering* for *wants*
-Json::Value RPCHandler::doOfferCreate(const Json::Value ¶ms)
-{
- RippleAddress naSeed;
- RippleAddress naSrcAccountID;
- STAmount saTakerPays;
- STAmount saTakerGets;
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
- else if (!saTakerGets.setFullValue(params[2u].asString(), params[3u].asString(), params[4u].asString()))
- {
- return rpcError(rpcGETS_AMT_MALFORMED);
- }
- else if (!saTakerPays.setFullValue(params[5u].asString(), params[6u].asString(), params[7u].asString()))
- {
- return rpcError(rpcPAYS_AMT_MALFORMED);
- }
- else if (params.size() == 10 && params[9u].asString() != "passive")
- {
- return rpcError(rpcINVALID_PARAMS);
- }
-
- uint32 uExpiration = lexical_cast_s(params[8u].asString());
- bool bPassive = params.size() == 10;
-
- RippleAddress naMasterGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
-
- if (!obj.empty())
- return obj;
-
- Transaction::pointer trans = Transaction::sharedOfferCreate(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- bPassive,
- saTakerPays,
- saTakerGets,
- uExpiration);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return obj;
-}
-
-// offer_cancel
-Json::Value RPCHandler::doOfferCancel(const Json::Value ¶ms)
-{
- RippleAddress naSeed;
- RippleAddress naSrcAccountID;
- uint32 uSequence = lexical_cast_s(params[2u].asString());
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
-
- RippleAddress naMasterGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
-
- if (!obj.empty())
- return obj;
-
- Transaction::pointer trans = Transaction::sharedOfferCancel(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- uSequence);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return obj;
-}
// owner_info ||
// owner_info || []
@@ -993,150 +518,7 @@ Json::Value RPCHandler::doOwnerInfo(const Json::Value& params)
return ret;
}
-// password_fund []
-// YYY Make making account default to first account for seed.
-Json::Value RPCHandler::doPasswordFund(const Json::Value ¶ms)
-{
- RippleAddress naSrcAccountID;
- RippleAddress naDstAccountID;
- RippleAddress naSeed;
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
- else if (!naDstAccountID.setAccountID(params[params.size() == 3 ? 2u : 1u].asString()))
- {
- return rpcError(rpcDST_ACT_MALFORMED);
- }
-
- RippleAddress naMasterGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
-
- if (!obj.empty())
- return obj;
-
- // YYY Could verify dst exists and isn't already funded.
-
- Transaction::pointer trans = Transaction::sharedPasswordFund(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- naDstAccountID);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return obj;
-}
-
-// password_set []
-Json::Value RPCHandler::doPasswordSet(const Json::Value& params)
-{
- RippleAddress naMasterSeed;
- RippleAddress naRegularSeed;
- RippleAddress naAccountID;
-
- if (!naMasterSeed.setSeedGeneric(params[0u].asString()))
- {
- // Should also not allow account id's as seeds.
- return rpcError(rpcBAD_SEED);
- }
- else if (!naRegularSeed.setSeedGeneric(params[1u].asString()))
- {
- // Should also not allow account id's as seeds.
- return rpcError(rpcBAD_SEED);
- }
- // YYY Might use account from string to be more flexible.
- else if (params.size() >= 3 && !naAccountID.setAccountID(params[2u].asString()))
- {
- return rpcError(rpcACT_MALFORMED);
- }
- else
- {
- RippleAddress naMasterGenerator = RippleAddress::createGeneratorPublic(naMasterSeed);
- RippleAddress naRegularGenerator = RippleAddress::createGeneratorPublic(naRegularSeed);
- RippleAddress naRegular0Public;
- RippleAddress naRegular0Private;
-
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
-
- naAccountPublic.setAccountPublic(naMasterGenerator, 0);
- naAccountPrivate.setAccountPrivate(naMasterGenerator, naMasterSeed, 0);
-
- naRegular0Public.setAccountPublic(naRegularGenerator, 0);
- naRegular0Private.setAccountPrivate(naRegularGenerator, naRegularSeed, 0);
-
- // Hash of regular account #0 public key.
- // uint160 uGeneratorID = naRegular0Public.getAccountID();
- std::vector vucGeneratorCipher = naRegular0Private.accountPrivateEncrypt(naRegular0Public, naMasterGenerator.getGenerator());
- std::vector vucGeneratorSig;
-
- // Prove that we have the corresponding private key to the generator id. So, we can get the generator id.
- // XXX Check result.
- naRegular0Private.accountPrivateSign(Serializer::getSHA512Half(vucGeneratorCipher), vucGeneratorSig);
-
- RippleAddress naMasterXPublic;
- RippleAddress naRegularXPublic;
- unsigned int iIndex = -1; // Compensate for initial increment.
- int iMax = theConfig.ACCOUNT_PROBE_MAX;
-
- // YYY Could probe periodically to see if accounts exists.
- // YYY Max could be set randomly.
- // Don't look at ledger entries to determine if the account exists. Don't want to leak to thin server that these accounts are
- // related.
- do {
- ++iIndex;
- naMasterXPublic.setAccountPublic(naMasterGenerator, iIndex);
- naRegularXPublic.setAccountPublic(naRegularGenerator, iIndex);
-
- std::cerr << iIndex << ": " << naRegularXPublic.humanAccountID() << std::endl;
-
- } while (naAccountID.getAccountID() != naMasterXPublic.getAccountID() && --iMax);
-
- if (!iMax)
- {
- return rpcError(rpcACT_NOT_FOUND);
- }
-
- Transaction::pointer trans = Transaction::sharedPasswordSet(
- naAccountPublic, naAccountPrivate,
- 0,
- naRegularXPublic,
- vucGeneratorCipher,
- naRegular0Public.getAccountPublic(),
- vucGeneratorSig);
-
- trans = mNetOps->submitTransaction(trans);
-
- Json::Value obj(Json::objectValue);
-
- // We "echo" the seeds so they can be checked.
- obj["master_seed"] = naMasterSeed.humanSeed();
- obj["master_key"] = naMasterSeed.humanSeed1751();
- obj["regular_seed"] = naRegularSeed.humanSeed();
- obj["regular_key"] = naRegularSeed.humanSeed1751();
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return obj;
- }
-}
Json::Value RPCHandler::doPeers(const Json::Value& params)
{
@@ -1236,310 +618,6 @@ Json::Value RPCHandler::doProfile(const Json::Value ¶ms)
return obj;
}
-// ripple
-// []
-// +
-// full|partial limit|average []
-//
-// path:
-// path +
-//
-// path_element:
-// account [] []
-// offer []
-Json::Value RPCHandler::doRipple(const Json::Value ¶ms)
-{
- RippleAddress naSeed;
- STAmount saSrcAmountMax;
- uint160 uSrcCurrencyID;
- RippleAddress naSrcAccountID;
- RippleAddress naSrcIssuerID;
- bool bPartial;
- bool bFull;
- bool bLimit;
- bool bAverage;
- RippleAddress naDstAccountID;
- STAmount saDstAmount;
- uint160 uDstCurrencyID;
-
- STPathSet spsPaths;
-
- naSrcIssuerID.setAccountID(params[4u].asString()); //
-
- if (!naSeed.setSeedGeneric(params[0u].asString())) //
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString())) //
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
- // []
- else if (!saSrcAmountMax.setFullValue(params[2u].asString(), params[3u].asString(), params[naSrcIssuerID.isValid() ? 4u : 1u].asString()))
- {
- // Log(lsINFO) << "naSrcIssuerID.isValid(): " << naSrcIssuerID.isValid();
- // Log(lsINFO) << "source_max: " << params[2u].asString();
- // Log(lsINFO) << "source_currency: " << params[3u].asString();
- // Log(lsINFO) << "source_issuer: " << params[naSrcIssuerID.isValid() ? 4u : 2u].asString();
-
- return rpcError(rpcSRC_AMT_MALFORMED);
- }
-
- int iArg = 4 + naSrcIssuerID.isValid();
-
- // XXX bSrcRedeem & bSrcIssue not used.
- STPath spPath;
-
- while (params.size() != iArg && params[iArg].asString() == "path") // path
- {
- Log(lsINFO) << "Path>";
- ++iArg;
-
- while (params.size() != iArg
- && (params[iArg].asString() == "offer" || params[iArg].asString() == "account"))
- {
- if (params.size() >= iArg + 3 && params[iArg].asString() == "offer") // offer
- {
- Log(lsINFO) << "Offer>";
- uint160 uCurrencyID;
- RippleAddress naIssuerID;
-
- ++iArg;
-
- if (!STAmount::currencyFromString(uCurrencyID, params[iArg++].asString())) //
- {
- return rpcError(rpcINVALID_PARAMS);
- }
- else if (naIssuerID.setAccountID(params[iArg].asString())) // []
- {
- ++iArg;
- }
-
- spPath.addElement(STPathElement(
- uint160(0),
- uCurrencyID,
- naIssuerID.isValid() ? naIssuerID.getAccountID() : uint160(0)));
- }
- else if (params.size() >= iArg + 2 && params[iArg].asString() == "account") // account
- {
- Log(lsINFO) << "Account>";
- RippleAddress naAccountID;
- uint160 uCurrencyID;
- RippleAddress naIssuerID;
-
- ++iArg;
-
- if (!naAccountID.setAccountID(params[iArg++].asString())) //
- {
- return rpcError(rpcINVALID_PARAMS);
- }
-
- if (params.size() != iArg && STAmount::currencyFromString(uCurrencyID, params[iArg].asString())) // []
- {
- ++iArg;
- }
-
- if (params.size() != iArg && naIssuerID.setAccountID(params[iArg].asString())) // []
- {
- ++iArg;
- }
-
- spPath.addElement(STPathElement(
- naAccountID.getAccountID(),
- uCurrencyID,
- naIssuerID.isValid() ? naIssuerID.getAccountID() : uint160(0)));
- }
- else
- {
- return rpcError(rpcINVALID_PARAMS);
- }
- }
-
- if (spPath.isEmpty())
- {
- return rpcError(rpcINVALID_PARAMS);
- }
- else
- {
- spsPaths.addPath(spPath);
- spPath.clear();
- }
- }
-
- // full|partial
- bPartial = params.size() != iArg ? params[iArg].asString() == "partial" : false;
- bFull = params.size() != iArg ? params[iArg].asString() == "full" : false;
-
- if (!bPartial && !bFull)
- {
- return rpcError(rpcINVALID_PARAMS);
- }
- else
- {
- ++iArg;
- }
-
- // limit|average
- bLimit = params.size() != iArg ? params[iArg].asString() == "limit" : false;
- bAverage = params.size() != iArg ? params[iArg].asString() == "average" : false;
-
- if (!bLimit && !bAverage)
- {
- return rpcError(rpcINVALID_PARAMS);
- }
- else
- {
- ++iArg;
- }
-
- if (params.size() != iArg && !naDstAccountID.setAccountID(params[iArg++].asString())) //
- {
- return rpcError(rpcDST_ACT_MALFORMED);
- }
-
- const unsigned int uDstIssuer = params.size() == iArg + 3 ? iArg+2 : iArg-1;
-
- //
- if (params.size() != iArg + 2 && params.size() != iArg + 3)
- {
- // Log(lsINFO) << "params.size(): " << params.size();
-
- return rpcError(rpcDST_AMT_MALFORMED);
- }
- else if (!saDstAmount.setFullValue(params[iArg].asString(), params[iArg+1].asString(), params[uDstIssuer].asString()))
- {
- // Log(lsINFO) << " Amount: " << params[iArg].asString();
- // Log(lsINFO) << "Currency: " << params[iArg+1].asString();
- // Log(lsINFO) << " Issuer: " << params[uDstIssuer].asString();
-
- return rpcError(rpcDST_AMT_MALFORMED);
- }
-
- AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID);
- STAmount saFee = theConfig.FEE_DEFAULT;
-
- RippleAddress naVerifyGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, saFee, asSrc, naVerifyGenerator);
-
- if (!obj.empty())
- return obj;
-
- // YYY Could do some checking: source has funds or credit, dst exists and has sufficent credit limit.
- // YYY Currency from same source or loops not allowed.
- // YYY Limit paths length and count.
- if (!asDst)
- {
- Log(lsINFO) << "naDstAccountID: " << naDstAccountID.humanAccountID();
-
- return rpcError(rpcDST_ACT_MISSING);
- }
-
- Transaction::pointer trans = Transaction::sharedPayment(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- saFee,
- 0, // YYY No source tag
- naDstAccountID,
- saDstAmount,
- saSrcAmountMax,
- spsPaths,
- bPartial,
- bLimit);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
- obj["seed"] = naSeed.humanSeed();
- obj["fee"] = saFee.getText();
- obj["srcAccountID"] = naSrcAccountID.humanAccountID();
- obj["dstAccountID"] = naDstAccountID.humanAccountID();
- obj["srcAmountMax"] = saSrcAmountMax.getText();
- obj["srcISO"] = saSrcAmountMax.getHumanCurrency();
- obj["dstAmount"] = saDstAmount.getText();
- obj["dstISO"] = saDstAmount.getHumanCurrency();
- obj["paths"] = spsPaths.getText();
-
- return obj;
-}
-
-// ripple_line_set [] [] []
-Json::Value RPCHandler::doRippleLineSet(const Json::Value& params)
-{
- RippleAddress naSeed;
- RippleAddress naSrcAccountID;
- RippleAddress naDstAccountID;
- STAmount saLimitAmount;
- bool bQualityIn = params.size() >= 6;
- bool bQualityOut = params.size() >= 7;
- uint32 uQualityIn = 0;
- uint32 uQualityOut = 0;
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
- else if (!naDstAccountID.setAccountID(params[2u].asString()))
- {
- return rpcError(rpcDST_ACT_MALFORMED);
- }
- else if (!saLimitAmount.setFullValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "", params[2u].asString()))
- {
- return rpcError(rpcSRC_AMT_MALFORMED);
- }
- else if (bQualityIn && !parseQuality(params[5u].asString(), uQualityIn))
- {
- return rpcError(rpcQUALITY_MALFORMED);
- }
- else if (bQualityOut && !parseQuality(params[6u].asString(), uQualityOut))
- {
- return rpcError(rpcQUALITY_MALFORMED);
- }
- else
- {
- RippleAddress naMasterGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator);
-
- if (!obj.empty())
- return obj;
-
- Transaction::pointer trans = Transaction::sharedCreditSet(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_DEFAULT,
- 0, // YYY No source tag
- saLimitAmount,
- bQualityIn, uQualityIn,
- bQualityOut, uQualityOut);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
- obj["seed"] = naSeed.humanSeed();
- obj["srcAccountID"] = naSrcAccountID.humanAccountID();
- obj["dstAccountID"] = naDstAccountID.humanAccountID();
-
- return obj;
- }
-}
-
// ripple_lines_get || []
Json::Value RPCHandler::doRippleLinesGet(const Json::Value ¶ms)
{
@@ -1609,162 +687,251 @@ Json::Value RPCHandler::doRippleLinesGet(const Json::Value ¶ms)
}
// submit any transaction to the network
+// submit private_key json
Json::Value RPCHandler::doSubmit(const Json::Value& params)
{
- // TODO
+ Json::Value txJSON;
+ Json::Reader reader;
+ if(reader.parse(params[1u].asString(),txJSON))
+ {
+ return handleJSONSubmit(params[0u].asString(), txJSON );
+ }
+
return rpcError(rpcSRC_ACT_MALFORMED);
}
-// send regular_seed paying_account account_id amount [currency] [issuer] [send_max] [send_currency] [send_issuer]
-Json::Value RPCHandler::doSend(const Json::Value& params)
+
+Json::Value RPCHandler::handleJSONSubmit(std::string& key, Json::Value& txJSON)
{
+ Json::Value jvResult;
RippleAddress naSeed;
- RippleAddress naSrcAccountID;
- RippleAddress naDstAccountID;
- STAmount saSrcAmountMax;
- STAmount saDstAmount;
- std::string sSrcCurrency;
- std::string sDstCurrency;
- std::string sSrcIssuer;
- std::string sDstIssuer;
+ RippleAddress srcAddress;
- if (params.size() >= 5)
- sDstCurrency = params[4u].asString();
-
- if (params.size() >= 6)
- sDstIssuer = params[5u].asString();
-
- if (params.size() >= 8)
- sSrcCurrency = params[7u].asString();
-
- if (params.size() >= 9)
- sSrcIssuer = params[8u].asString();
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
+ if (!naSeed.setSeedGeneric(key))
{
return rpcError(rpcBAD_SEED);
}
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
+ if (!txJSON.isMember("Account"))
+ {
+ return rpcError(rpcSRC_ACT_MISSING);
+ }
+ if (!srcAddress.setAccountID(txJSON["Account"].asString()))
{
return rpcError(rpcSRC_ACT_MALFORMED);
}
- else if (!naDstAccountID.setAccountID(params[2u].asString()))
- {
- return rpcError(rpcDST_ACT_MALFORMED);
- }
- else if (!saDstAmount.setFullValue(params[3u].asString(), sDstCurrency, sDstIssuer))
- {
- return rpcError(rpcDST_AMT_MALFORMED);
- }
- else if (params.size() >= 7 && !saSrcAmountMax.setFullValue(params[6u].asString(), sSrcCurrency, sSrcIssuer))
- {
- return rpcError(rpcSRC_AMT_MALFORMED);
- }
- else
- {
- AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID);
- bool bCreate = !asDst;
- STAmount saFee = bCreate ? theConfig.FEE_ACCOUNT_CREATE : theConfig.FEE_DEFAULT;
- RippleAddress naVerifyGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, saFee, asSrc, naVerifyGenerator);
+ AccountState::pointer asSrc = mNetOps->getAccountState(uint256(0), srcAddress);
- // Log(lsINFO) << boost::str(boost::format("doSend: sSrcIssuer=%s sDstIssuer=%s saSrcAmountMax=%s saDstAmount=%s")
- // % sSrcIssuer
- // % sDstIssuer
- // % saSrcAmountMax.getFullText()
- // % saDstAmount.getFullText());
+ if( txJSON["type"]=="Payment")
+ {
+ txJSON["TransactionType"]=0;
- if (!obj.empty())
- return obj;
-
- if (params.size() < 7)
- saSrcAmountMax = saDstAmount;
-
- // Do a few simple checks.
- if (!saSrcAmountMax.isNative())
+ RippleAddress dstAccountID;
+ if (!dstAccountID.setAccountID(txJSON["Destination"].asString()))
{
- Log(lsINFO) << "doSend: Ripple";
-
- nothing();
+ return rpcError(rpcDST_ACT_MALFORMED);
}
- else if (!saSrcBalance.isPositive())
+
+ if(!txJSON.isMember("Fee"))
{
- // No native currency to send.
- Log(lsINFO) << "doSend: No native currency to send: " << saSrcBalance.getText();
-
- return rpcError(rpcINSUF_FUNDS);
+ if(mNetOps->getAccountState(uint256(0), dstAccountID))
+ txJSON["Fee"]=(int)theConfig.FEE_DEFAULT;
+ else txJSON["Fee"]=(int)theConfig.FEE_ACCOUNT_CREATE;
}
- else if (saDstAmount.isNative() && saSrcAmountMax < saDstAmount)
+ if(!txJSON.isMember("Paths"))
{
- // Not enough native currency.
+ if(txJSON["Amount"].isObject() || txJSON.isMember("SendMax") )
+ { // we need a ripple path
+ STPathSet spsPaths;
+ uint160 srcCurrencyID;
+ if(txJSON.isMember("SendMax") && txJSON["SendMax"].isMember("currency"))
+ {
+ STAmount::currencyFromString(srcCurrencyID, "XRP");
+ }else STAmount::currencyFromString(srcCurrencyID, txJSON["SendMax"]["currency"].asString());
- Log(lsINFO) << "doSend: Insufficient funds: src=" << saSrcAmountMax.getText() << " dst=" << saDstAmount.getText();
+ STAmount dstAmount;
+ if(txJSON["Amount"].isObject())
+ {
+ std::string issuerStr;
+ if( txJSON["Amount"].isMember("issuer")) issuerStr=txJSON["Amount"]["issuer"].asString();
+ if( !txJSON["Amount"].isMember("value") || !txJSON["Amount"].isMember("currency")) return rpcError(rpcDST_AMT_MALFORMED);
+ if (!dstAmount.setFullValue(txJSON["Amount"]["value"].asString(), txJSON["Amount"]["currency"].asString(), issuerStr))
+ {
+ return rpcError(rpcDST_AMT_MALFORMED);
+ }
+ }else if (!dstAmount.setFullValue(txJSON["Amount"].asString()))
+ {
+ return rpcError(rpcDST_AMT_MALFORMED);
+ }
- return rpcError(rpcINSUF_FUNDS);
- }
- // XXX Don't allow send to self of same currency.
-
- Transaction::pointer trans;
- if (asDst) {
- // Destination exists, ordinary send.
-
- STPathSet spsPaths;
- uint160 srcCurrencyID;
-
- if (!saSrcAmountMax.isNative() || !saDstAmount.isNative())
- {
- STAmount::currencyFromString(srcCurrencyID, sSrcCurrency);
- Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount);
+ Pathfinder pf(srcAddress, dstAccountID, srcCurrencyID, dstAmount);
pf.findPaths(5, 1, spsPaths);
+ txJSON["Paths"]=spsPaths.getJson(0);
+ if(txJSON.isMember("Flags")) txJSON["Flags"]=txJSON["Flags"].asUInt() | 2;
+ else txJSON["Flags"]=2;
}
-
- trans = Transaction::sharedPayment(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- saFee,
- 0, // YYY No source tag
- naDstAccountID,
- saDstAmount,
- saSrcAmountMax,
- spsPaths);
}
- else
- {
- // Create destination and send.
-
- trans = Transaction::sharedCreate(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- saFee,
- 0, // YYY No source tag
- naDstAccountID,
- saDstAmount); // Initial funds in XNS.
- }
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
- obj["seed"] = naSeed.humanSeed();
- obj["fee"] = saFee.getText();
- obj["create"] = bCreate;
- obj["srcAccountID"] = naSrcAccountID.humanAccountID();
- obj["dstAccountID"] = naDstAccountID.humanAccountID();
- obj["srcAmountMax"] = saSrcAmountMax.getText();
- obj["srcISO"] = saSrcAmountMax.getHumanCurrency();
- obj["dstAmount"] = saDstAmount.getText();
- obj["dstISO"] = saDstAmount.getHumanCurrency();
-
- return obj;
+
+ }else if( txJSON["type"]=="OfferCreate" )
+ {
+ txJSON["TransactionType"]=7;
+ if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT;
+ }else if( txJSON["type"]=="TrustSet")
+ {
+ txJSON["TransactionType"]=20;
+ if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT;
+ }else if( txJSON["type"]=="OfferCancel")
+ {
+ txJSON["TransactionType"]=8;
+ if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT;
}
+
+ txJSON.removeMember("type");
+
+ if(!txJSON.isMember("Sequence")) txJSON["Sequence"]=asSrc->getSeq();
+ if(!txJSON.isMember("Flags")) txJSON["Flags"]=0;
+
+ Ledger::pointer lpCurrent = mNetOps->getCurrentLedger();
+ SLE::pointer sleAccountRoot = mNetOps->getSLE(lpCurrent, Ledger::getAccountRootIndex(srcAddress.getAccountID()));
+
+ if (!sleAccountRoot)
+ {
+ // XXX Ignore transactions for accounts not created.
+ return rpcError(rpcSRC_ACT_MISSING);
+ }
+
+ bool bHaveAuthKey = false;
+ RippleAddress naAuthorizedPublic;
+
+
+ RippleAddress naSecret = RippleAddress::createSeedGeneric(key);
+ RippleAddress naMasterGenerator = RippleAddress::createGeneratorPublic(naSecret);
+
+ // Find the index of Account from the master generator, so we can generate the public and private keys.
+ RippleAddress naMasterAccountPublic;
+ unsigned int iIndex = 0;
+ bool bFound = false;
+
+ // Don't look at ledger entries to determine if the account exists. Don't want to leak to thin server that these accounts are
+ // related.
+ while (!bFound && iIndex != theConfig.ACCOUNT_PROBE_MAX)
+ {
+ naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex);
+
+ Log(lsWARNING) << "authorize: " << iIndex << " : " << naMasterAccountPublic.humanAccountID() << " : " << srcAddress.humanAccountID();
+
+ bFound = srcAddress.getAccountID() == naMasterAccountPublic.getAccountID();
+ if (!bFound)
+ ++iIndex;
+ }
+
+ if (!bFound)
+ {
+ return rpcError(rpcSRC_ACT_MISSING);
+ }
+
+ // Use the generator to determine the associated public and private keys.
+ RippleAddress naGenerator = RippleAddress::createGeneratorPublic(naSecret);
+ RippleAddress naAccountPublic = RippleAddress::createAccountPublic(naGenerator, iIndex);
+ RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate(naGenerator, naSecret, iIndex);
+
+ if (bHaveAuthKey
+ // The generated pair must match authorized...
+ && naAuthorizedPublic.getAccountID() != naAccountPublic.getAccountID()
+ // ... or the master key must have been used.
+ && srcAddress.getAccountID() != naAccountPublic.getAccountID())
+ {
+ // std::cerr << "iIndex: " << iIndex << std::endl;
+ // std::cerr << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey().getAccountID()) << std::endl;
+ // std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl;
+
+ return rpcError(rpcSRC_ACT_MISSING);
+ }
+
+ std::auto_ptr sopTrans;
+
+ try
+ {
+ sopTrans = STObject::parseJson(txJSON);
+ }
+ catch (std::exception& e)
+ {
+ jvResult["error"] = "malformedTransaction";
+ jvResult["error_exception"] = e.what();
+ return(jvResult);
+ }
+
+ sopTrans->setFieldVL(sfSigningPubKey, naAccountPublic.getAccountPublic());
+
+ SerializedTransaction::pointer stpTrans;
+
+ try
+ {
+ stpTrans = boost::make_shared(*sopTrans);
+ }
+ catch (std::exception& e)
+ {
+ jvResult["error"] = "invalidTransaction";
+ jvResult["error_exception"] = e.what();
+ return jvResult;
+ }
+
+ stpTrans->sign(naAccountPrivate);
+
+ Transaction::pointer tpTrans;
+
+ try
+ {
+ tpTrans = boost::make_shared(stpTrans, false);
+ }
+ catch (std::exception& e)
+ {
+ jvResult["error"] = "internalTransaction";
+ jvResult["error_exception"] = e.what();
+ return(jvResult);
+ }
+
+ try
+ {
+ tpTrans = mNetOps->submitTransaction(tpTrans);
+
+ if (!tpTrans) {
+ jvResult["error"] = "invalidTransaction";
+ jvResult["error_exception"] = "Unable to sterilize transaction.";
+ return(jvResult);
+ }
+ }
+ catch (std::exception& e)
+ {
+ jvResult["error"] = "internalSubmit";
+ jvResult["error_exception"] = e.what();
+ return(jvResult);
+ }
+
+ try
+ {
+ jvResult["transaction"] = tpTrans->getJson(0);
+
+ if (temUNCERTAIN != tpTrans->getResult())
+ {
+ std::string sToken;
+ std::string sHuman;
+
+ transResultInfo(tpTrans->getResult(), sToken, sHuman);
+
+ jvResult["engine_result"] = sToken;
+ jvResult["engine_result_code"] = tpTrans->getResult();
+ jvResult["engine_result_message"] = sHuman;
+ }
+ return(jvResult);
+ }
+ catch (std::exception& e)
+ {
+ jvResult["error"] = "internalJson";
+ jvResult["error_exception"] = e.what();
+ return(jvResult);
+ }
+
}
Json::Value RPCHandler::doServerInfo(const Json::Value& params)
@@ -1835,6 +1002,24 @@ Json::Value RPCHandler::doTx(const Json::Value& params)
return rpcError(rpcNOT_IMPL);
}
+Json::Value RPCHandler::doLedgerClosed(const Json::Value& params)
+{
+ Json::Value jvResult;
+ uint256 uLedger = mNetOps->getClosedLedger();
+
+ jvResult["ledger_closed_index"] = mNetOps->getLedgerID(uLedger);
+ jvResult["ledger_closed"] = uLedger.ToString();
+ //jvResult["ledger_closed_time"] = uLedger.
+ return jvResult;
+}
+
+Json::Value RPCHandler::doLedgerCurrent(const Json::Value& params)
+{
+ Json::Value jvResult;
+ jvResult["ledger_current_index"] = mNetOps->getCurrentLedgerID();
+ return jvResult;
+}
+
// ledger [id|current|lastclosed] [full]
Json::Value RPCHandler::doLedger(const Json::Value& params)
{
@@ -2088,255 +1273,6 @@ Json::Value RPCHandler::doWalletAccounts(const Json::Value& params)
}
}
-// wallet_add [] []
-Json::Value RPCHandler::doWalletAdd(const Json::Value& params)
-{
- RippleAddress naMasterSeed;
- RippleAddress naRegularSeed;
- RippleAddress naSrcAccountID;
- STAmount saAmount;
- std::string sDstCurrency;
-
- if (!naRegularSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
- else if (!naMasterSeed.setSeedGeneric(params[2u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (params.size() >= 4 && !saAmount.setFullValue(params[3u].asString(), sDstCurrency))
- {
- return rpcError(rpcDST_AMT_MALFORMED);
- }
- else
- {
- RippleAddress naMasterGenerator = RippleAddress::createGeneratorPublic(naMasterSeed);
- RippleAddress naRegularGenerator = RippleAddress::createGeneratorPublic(naRegularSeed);
-
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator);
-
- if (!obj.empty())
- return obj;
-
- if (saSrcBalance < saAmount)
- {
- return rpcError(rpcINSUF_FUNDS);
- }
- else
- {
- RippleAddress naNewAccountPublic;
- RippleAddress naNewAccountPrivate;
- RippleAddress naAuthKeyID;
- uint160 uAuthKeyID;
- AccountState::pointer asNew;
- std::vector vucSignature;
- bool bAgain = true;
- int iIndex = -1;
-
- // Find an unmade account.
- do {
- ++iIndex;
- naNewAccountPublic.setAccountPublic(naMasterGenerator, iIndex);
-
- asNew = mNetOps->getAccountState(uint256(0), naNewAccountPublic);
- if (!asNew)
- bAgain = false;
- } while (bAgain);
-
- // XXX Have a maximum number of accounts per wallet?
-
- // Determine corrisponding master private key.
- naNewAccountPrivate.setAccountPrivate(naMasterGenerator, naMasterSeed, iIndex);
-
- // Determine new accounts authorized regular key.
- naAuthKeyID.setAccountPublic(naRegularGenerator, iIndex);
-
- uAuthKeyID = naAuthKeyID.getAccountID();
-
- // Sign anything (naAuthKeyID) to prove we know new master private key.
- naNewAccountPrivate.accountPrivateSign(Serializer::getSHA512Half(uAuthKeyID.begin(), uAuthKeyID.size()), vucSignature);
-
- Transaction::pointer trans = Transaction::sharedWalletAdd(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_ACCOUNT_CREATE,
- 0, // YYY No source tag
- saAmount,
- naAuthKeyID,
- naNewAccountPublic,
- vucSignature);
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
- obj["srcAccountID"] = naSrcAccountID.humanAccountID();
- obj["newAccountID"] = naNewAccountPublic.humanAccountID();
- obj["amount"] = saAmount.getText();
-
- return obj;
- }
- }
-}
-
-// wallet_claim [] []
-//
-// To provide an example to client writers, we do everything we expect a client to do here.
-Json::Value RPCHandler::doWalletClaim(const Json::Value& params)
-{
- RippleAddress naMasterSeed;
- RippleAddress naRegularSeed;
-
- if (!naMasterSeed.setSeedGeneric(params[0u].asString()))
- {
- // Should also not allow account id's as seeds.
- return rpcError(rpcBAD_SEED);
- }
- else if (!naRegularSeed.setSeedGeneric(params[1u].asString()))
- {
- // Should also not allow account id's as seeds.
- return rpcError(rpcBAD_SEED);
- }
- else
- {
- // Building:
- // peer_wallet_claim
- // []
- //
- //
- // Which has no confidential information.
-
- // XXX Need better parsing.
- uint32 uSourceTag = (params.size() == 2) ? 0 : lexical_cast_s(params[2u].asString());
- // XXX Annotation is ignored.
- std::string strAnnotation = (params.size() == 3) ? "" : params[3u].asString();
-
- RippleAddress naMasterGenerator = RippleAddress::createGeneratorPublic(naMasterSeed);
- RippleAddress naRegularGenerator = RippleAddress::createGeneratorPublic(naRegularSeed);
- RippleAddress naRegular0Public;
- RippleAddress naRegular0Private;
-
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
-
- naAccountPublic.setAccountPublic(naMasterGenerator, 0);
- naAccountPrivate.setAccountPrivate(naMasterGenerator, naMasterSeed, 0);
-
- naRegular0Public.setAccountPublic(naRegularGenerator, 0);
- naRegular0Private.setAccountPrivate(naRegularGenerator, naRegularSeed, 0);
-
- // Hash of regular account #0 public key.
- uint160 uGeneratorID = naRegular0Public.getAccountID();
- std::vector vucGeneratorCipher = naRegular0Private.accountPrivateEncrypt(naRegular0Public, naMasterGenerator.getGenerator());
- std::vector vucGeneratorSig;
-
- // Prove that we have the corresponding private key to the generator id. So, we can get the generator id.
- // XXX Check result.
- naRegular0Private.accountPrivateSign(Serializer::getSHA512Half(vucGeneratorCipher), vucGeneratorSig);
-
- Transaction::pointer trans = Transaction::sharedClaim(
- naAccountPublic, naAccountPrivate,
- uSourceTag,
- vucGeneratorCipher,
- naRegular0Public.getAccountPublic(),
- vucGeneratorSig);
-
- trans = mNetOps->submitTransaction(trans);
-
- Json::Value obj(Json::objectValue);
-
- // We "echo" the seeds so they can be checked.
- obj["master_seed"] = naMasterSeed.humanSeed();
- obj["master_key"] = naMasterSeed.humanSeed1751();
- obj["regular_seed"] = naRegularSeed.humanSeed();
- obj["regular_key"] = naRegularSeed.humanSeed1751();
-
- obj["account_id"] = naAccountPublic.humanAccountID();
- obj["generator_id"] = strHex(uGeneratorID);
- obj["generator"] = strHex(vucGeneratorCipher);
- obj["annotation"] = strAnnotation;
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return obj;
- }
-}
-
-// wallet_create regular_seed paying_account account_id [initial_funds]
-// We don't allow creating an account_id by default here because we want to make sure the person has a chance to write down the
-// master seed of the account to be created.
-// YYY Need annotation and source tag
-Json::Value RPCHandler::doWalletCreate(const Json::Value& params)
-{
- RippleAddress naSrcAccountID;
- RippleAddress naDstAccountID;
- RippleAddress naSeed;
-
- if (!naSeed.setSeedGeneric(params[0u].asString()))
- {
- return rpcError(rpcBAD_SEED);
- }
- else if (!naSrcAccountID.setAccountID(params[1u].asString()))
- {
- return rpcError(rpcSRC_ACT_MALFORMED);
- }
- else if (!naDstAccountID.setAccountID(params[2u].asString()))
- {
- return rpcError(rpcDST_ACT_MALFORMED);
- }
- else if (mNetOps->getAccountState(uint256(0), naDstAccountID))
- {
- return rpcError(rpcACT_EXISTS);
- }
-
- // Trying to build:
- // peer_wallet_create [] []
-
- RippleAddress naMasterGenerator;
- RippleAddress naAccountPublic;
- RippleAddress naAccountPrivate;
- AccountState::pointer asSrc;
- STAmount saSrcBalance;
- Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate,
- saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator);
-
- if (!obj.empty())
- return obj;
-
- STAmount saInitialFunds = (params.size() < 4) ? 0 : lexical_cast_s(params[3u].asString());
-
- if (saSrcBalance < saInitialFunds)
- return rpcError(rpcINSUF_FUNDS);
-
- Transaction::pointer trans = Transaction::sharedCreate(
- naAccountPublic, naAccountPrivate,
- naSrcAccountID,
- asSrc->getSeq(),
- theConfig.FEE_ACCOUNT_CREATE,
- 0, // YYY No source tag
- naDstAccountID,
- saInitialFunds); // Initial funds in XNC.
-
- trans = mNetOps->submitTransaction(trans);
-
- obj["transaction"] = trans->getSTransaction()->getJson(0);
- obj["status"] = trans->getStatus();
-
- return obj;
-}
-
Json::Value RPCHandler::doLogRotate(const Json::Value& params)
{
@@ -2356,13 +1292,8 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
unsigned int iOptions;
} commandsA[] = {
{ "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_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 },
{ "connect", &RPCHandler::doConnect, 1, 2, true },
{ "data_delete", &RPCHandler::doDataDelete, 1, 1, true },
{ "data_fetch", &RPCHandler::doDataFetch, 1, 1, true },
@@ -2372,18 +1303,11 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
{ "log_level", &RPCHandler::doLogLevel, 0, 2, true },
{ "logrotate", &RPCHandler::doLogRotate, 0, 0, true },
{ "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_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 },
+ { "submit", &RPCHandler::doSubmit, 2, 2, false, optCurrent },
{ "server_info", &RPCHandler::doServerInfo, 0, 0, true },
{ "stop", &RPCHandler::doStop, 0, 0, true },
{ "tx", &RPCHandler::doTx, 1, 1, true },
@@ -2401,9 +1325,6 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param
{ "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_propose", &RPCHandler::doWalletPropose, 0, 1, false, },
{ "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, },
@@ -2666,4 +1587,328 @@ Json::Value RPCHandler::doUnlLoad(const Json::Value& params)
return "loading";
}
+Json::Value RPCHandler::doLedgerAccept(const Json::Value& )
+{
+ Json::Value jvResult;
+ if (!theConfig.RUN_STANDALONE)
+ {
+ jvResult["error"] = "notStandAlone";
+ }
+ else
+ {
+ mNetOps->acceptLedger();
+
+ jvResult["ledger_current_index"] = mNetOps->getCurrentLedgerID();
+ }
+ return(jvResult);
+}
+
+
+Json::Value RPCHandler::doTransactionEntry(const Json::Value& params)
+{
+ Json::Value jvResult;
+ Json::Value jvRequest;
+ Json::Reader reader;
+ if(!reader.parse(params[0u].asString(),jvRequest))
+ return rpcError(rpcINVALID_PARAMS);
+
+ if (!jvRequest.isMember("tx_hash"))
+ {
+ jvResult["error"] = "fieldNotFoundTransaction";
+ }
+ if (!jvRequest.isMember("ledger_hash"))
+ {
+ jvResult["error"] = "notYetImplemented"; // XXX We don't support any transaction yet.
+ }
+ else
+ {
+ uint256 uTransID;
+ // XXX Relying on trusted WSS client. Would be better to have a strict routine, returning success or failure.
+ uTransID.SetHex(jvRequest["tx_hash"].asString());
+
+ uint256 uLedgerID;
+ // XXX Relying on trusted WSS client. Would be better to have a strict routine, returning success or failure.
+ uLedgerID.SetHex(jvRequest["ledger_hash"].asString());
+
+ Ledger::pointer lpLedger = theApp->getMasterLedger().getLedgerByHash(uLedgerID);
+
+ if (!lpLedger) {
+ jvResult["error"] = "ledgerNotFound";
+ }
+ else
+ {
+ Transaction::pointer tpTrans;
+ TransactionMetaSet::pointer tmTrans;
+
+ if (!lpLedger-> getTransaction(uTransID, tpTrans, tmTrans))
+ {
+ jvResult["error"] = "transactionNotFound";
+ }
+ else
+ {
+ jvResult["transaction"] = tpTrans->getJson(0);
+ jvResult["metadata"] = tmTrans->getJson(0);
+ // 'accounts'
+ // 'engine_...'
+ // 'ledger_...'
+ }
+ }
+ }
+
+ return jvResult;
+}
+
+
+
+Json::Value RPCHandler::doLedgerEntry(const Json::Value& params)
+{
+ Json::Value jvResult;
+ Json::Value jvRequest;
+ Json::Reader reader;
+ if(!reader.parse(params[0u].asString(),jvRequest))
+ return rpcError(rpcINVALID_PARAMS);
+
+
+ uint256 uLedger = jvRequest.isMember("ledger_closed") ? uint256(jvRequest["ledger_closed"].asString()) : 0;
+ uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0;
+
+ Ledger::pointer lpLedger;
+
+ if (!!uLedger)
+ {
+ // Ledger directly specified.
+ lpLedger = mNetOps->getLedgerByHash(uLedger);
+
+ if (!lpLedger)
+ {
+ jvResult["error"] = "ledgerNotFound";
+ return jvResult;
+ }
+
+ uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index, override if needed.
+ }
+ else if (!!uLedgerIndex)
+ {
+ lpLedger = mNetOps->getLedgerBySeq(uLedgerIndex);
+
+ if (!lpLedger)
+ {
+ jvResult["error"] = "ledgerNotFound"; // ledger_index from future?
+ return jvResult;
+ }
+ }
+ else
+ {
+ // Default to current ledger.
+ lpLedger = mNetOps->getCurrentLedger();
+ uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index.
+ }
+
+ if (lpLedger->isClosed())
+ {
+ if (!!uLedger)
+ jvResult["ledger_closed"] = uLedger.ToString();
+
+ jvResult["ledger_closed_index"] = uLedgerIndex;
+ }
+ else
+ {
+ jvResult["ledger_current_index"] = uLedgerIndex;
+ }
+
+ uint256 uNodeIndex;
+ bool bNodeBinary = false;
+
+ if (jvRequest.isMember("index"))
+ {
+ // XXX Needs to provide proof.
+ uNodeIndex.SetHex(jvRequest["index"].asString());
+ bNodeBinary = true;
+ }
+ else if (jvRequest.isMember("account_root"))
+ {
+ RippleAddress naAccount;
+
+ if (!naAccount.setAccountID(jvRequest["account_root"].asString())
+ || !naAccount.getAccountID())
+ {
+ jvResult["error"] = "malformedAddress";
+ }
+ else
+ {
+ uNodeIndex = Ledger::getAccountRootIndex(naAccount.getAccountID());
+ }
+ }
+ else if (jvRequest.isMember("directory"))
+ {
+
+ if (!jvRequest.isObject())
+ {
+ uNodeIndex.SetHex(jvRequest["directory"].asString());
+ }
+ else if (jvRequest["directory"].isMember("sub_index")
+ && !jvRequest["directory"]["sub_index"].isIntegral())
+ {
+ jvResult["error"] = "malformedRequest";
+ }
+ else
+ {
+ uint64 uSubIndex = jvRequest["directory"].isMember("sub_index")
+ ? jvRequest["directory"]["sub_index"].asUInt()
+ : 0;
+
+ if (jvRequest["directory"].isMember("dir_root"))
+ {
+ uint256 uDirRoot;
+
+ uDirRoot.SetHex(jvRequest["dir_root"].asString());
+
+ uNodeIndex = Ledger::getDirNodeIndex(uDirRoot, uSubIndex);
+ }
+ else if (jvRequest["directory"].isMember("owner"))
+ {
+ RippleAddress naOwnerID;
+
+ if (!naOwnerID.setAccountID(jvRequest["directory"]["owner"].asString()))
+ {
+ jvResult["error"] = "malformedAddress";
+ }
+ else
+ {
+ uint256 uDirRoot = Ledger::getOwnerDirIndex(naOwnerID.getAccountID());
+
+ uNodeIndex = Ledger::getDirNodeIndex(uDirRoot, uSubIndex);
+ }
+ }
+ else
+ {
+ jvResult["error"] = "malformedRequest";
+ }
+ }
+ }
+ else if (jvRequest.isMember("generator"))
+ {
+ RippleAddress naGeneratorID;
+
+ if (!jvRequest.isObject())
+ {
+ uNodeIndex.SetHex(jvRequest["generator"].asString());
+ }
+ else if (!jvRequest["generator"].isMember("regular_seed"))
+ {
+ jvResult["error"] = "malformedRequest";
+ }
+ else if (!naGeneratorID.setSeedGeneric(jvRequest["generator"]["regular_seed"].asString()))
+ {
+ jvResult["error"] = "malformedAddress";
+ }
+ else
+ {
+ RippleAddress na0Public; // To find the generator's index.
+ RippleAddress naGenerator = RippleAddress::createGeneratorPublic(naGeneratorID);
+
+ na0Public.setAccountPublic(naGenerator, 0);
+
+ uNodeIndex = Ledger::getGeneratorIndex(na0Public.getAccountID());
+ }
+ }
+ else if (jvRequest.isMember("offer"))
+ {
+ RippleAddress naAccountID;
+
+ if (!jvRequest.isObject())
+ {
+ uNodeIndex.SetHex(jvRequest["offer"].asString());
+ }
+ else if (!jvRequest["offer"].isMember("account")
+ || !jvRequest["offer"].isMember("seq")
+ || !jvRequest["offer"]["seq"].isIntegral())
+ {
+ jvResult["error"] = "malformedRequest";
+ }
+ else if (!naAccountID.setAccountID(jvRequest["offer"]["account"].asString()))
+ {
+ jvResult["error"] = "malformedAddress";
+ }
+ else
+ {
+ uint32 uSequence = jvRequest["offer"]["seq"].asUInt();
+
+ uNodeIndex = Ledger::getOfferIndex(naAccountID.getAccountID(), uSequence);
+ }
+ }
+ else if (jvRequest.isMember("ripple_state"))
+ {
+ RippleAddress naA;
+ RippleAddress naB;
+ uint160 uCurrency;
+ Json::Value jvRippleState = jvRequest["ripple_state"];
+
+ if (!jvRippleState.isMember("currency")
+ || !jvRippleState.isMember("accounts")
+ || !jvRippleState["accounts"].isArray()
+ || 2 != jvRippleState["accounts"].size()
+ || !jvRippleState["accounts"][0u].isString()
+ || !jvRippleState["accounts"][1u].isString()
+ || jvRippleState["accounts"][0u].asString() == jvRippleState["accounts"][1u].asString()
+ ) {
+
+ cLog(lsINFO)
+ << boost::str(boost::format("ledger_entry: ripple_state: accounts: %d currency: %d array: %d size: %d equal: %d")
+ % jvRippleState.isMember("accounts")
+ % jvRippleState.isMember("currency")
+ % jvRippleState["accounts"].isArray()
+ % jvRippleState["accounts"].size()
+ % (jvRippleState["accounts"][0u].asString() == jvRippleState["accounts"][1u].asString())
+ );
+
+ jvResult["error"] = "malformedRequest";
+ }
+ else if (!naA.setAccountID(jvRippleState["accounts"][0u].asString())
+ || !naB.setAccountID(jvRippleState["accounts"][1u].asString())) {
+ jvResult["error"] = "malformedAddress";
+ }
+ else if (!STAmount::currencyFromString(uCurrency, jvRippleState["currency"].asString())) {
+ jvResult["error"] = "malformedCurrency";
+ }
+ else
+ {
+ uNodeIndex = Ledger::getRippleStateIndex(naA, naB, uCurrency);
+ }
+ }
+ else
+ {
+ jvResult["error"] = "unknownOption";
+ }
+
+ if (!!uNodeIndex)
+ {
+ SLE::pointer sleNode = mNetOps->getSLE(lpLedger, uNodeIndex);
+
+ if (!sleNode)
+ {
+ // Not found.
+ // XXX Should also provide proof.
+ jvResult["error"] = "entryNotFound";
+ }
+ else if (bNodeBinary)
+ {
+ // XXX Should also provide proof.
+ Serializer s;
+
+ sleNode->add(s);
+
+ jvResult["node_binary"] = strHex(s.peekData());
+ jvResult["index"] = uNodeIndex.ToString();
+ }
+ else
+ {
+ jvResult["node"] = sleNode->getJson(0);
+ jvResult["index"] = uNodeIndex.ToString();
+ }
+ }
+
+ return jvResult;
+}
+
// vim:ts=4
diff --git a/src/RPCHandler.h b/src/RPCHandler.h
index c001e7dffa..6dc6275467 100644
--- a/src/RPCHandler.h
+++ b/src/RPCHandler.h
@@ -28,14 +28,9 @@ class RPCHandler
Json::Value accountFromString(const uint256& uLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex);
Json::Value doAcceptLedger(const Json::Value ¶ms);
- Json::Value doAccountDomainSet(const Json::Value ¶ms);
- Json::Value doAccountEmailSet(const Json::Value ¶ms);
+
Json::Value doAccountInfo(const Json::Value& params);
- Json::Value doAccountMessageSet(const Json::Value ¶ms);
- Json::Value doAccountPublishSet(const Json::Value ¶ms);
- Json::Value doAccountRateSet(const Json::Value ¶ms);
Json::Value doAccountTransactions(const Json::Value& params);
- Json::Value doAccountWalletSet(const Json::Value ¶ms);
Json::Value doConnect(const Json::Value& params);
Json::Value doDataDelete(const Json::Value& params);
Json::Value doDataFetch(const Json::Value& params);
@@ -44,24 +39,18 @@ class RPCHandler
Json::Value doLedger(const Json::Value& params);
Json::Value doLogRotate(const Json::Value& params);
Json::Value doNicknameInfo(const Json::Value& params);
- Json::Value doNicknameSet(const Json::Value& params);
- Json::Value doOfferCreate(const Json::Value& params);
- Json::Value doOfferCancel(const Json::Value& params);
+
Json::Value doOwnerInfo(const Json::Value& params);
- Json::Value doPasswordFund(const Json::Value& params);
- Json::Value doPasswordSet(const Json::Value& params);
+
Json::Value doProfile(const Json::Value& params);
Json::Value doPeers(const Json::Value& params);
- Json::Value doRipple(const Json::Value ¶ms);
+
Json::Value doRippleLinesGet(const Json::Value ¶ms);
- Json::Value doRippleLineSet(const Json::Value& params);
- Json::Value doSend(const Json::Value& params);
Json::Value doServerInfo(const Json::Value& params);
Json::Value doSessionClose(const Json::Value& params);
Json::Value doSessionOpen(const Json::Value& params);
Json::Value doLogLevel(const Json::Value& params);
Json::Value doStop(const Json::Value& params);
- Json::Value doTransitSet(const Json::Value& params);
Json::Value doTx(const Json::Value& params);
Json::Value doTxHistory(const Json::Value& params);
Json::Value doSubmit(const Json::Value& params);
@@ -80,9 +69,6 @@ class RPCHandler
Json::Value doValidationSeed(const Json::Value& params);
Json::Value doWalletAccounts(const Json::Value& params);
- Json::Value doWalletAdd(const Json::Value& params);
- Json::Value doWalletClaim(const Json::Value& params);
- Json::Value doWalletCreate(const Json::Value& params);
Json::Value doWalletLock(const Json::Value& params);
Json::Value doWalletPropose(const Json::Value& params);
Json::Value doWalletSeed(const Json::Value& params);
@@ -91,6 +77,14 @@ class RPCHandler
Json::Value doLogin(const Json::Value& params);
+ Json::Value doLedgerAccept(const Json::Value& params);
+ Json::Value doLedgerClosed(const Json::Value& params);
+ Json::Value doLedgerCurrent(const Json::Value& params);
+ Json::Value doLedgerEntry(const Json::Value& params);
+ Json::Value doTransactionEntry(const Json::Value& params);
+
+
+ void addSubmitPath(Json::Value& txJSON);
public:
@@ -160,6 +154,8 @@ public:
Json::Value doCommand(const std::string& command, Json::Value& params,int role);
Json::Value rpcError(int iError);
+ Json::Value handleJSONSubmit(std::string& key, Json::Value& txJSON);
+
};
#endif
diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp
index 1ac494c3a8..efd7cf0202 100644
--- a/src/RippleCalc.cpp
+++ b/src/RippleCalc.cpp
@@ -1536,7 +1536,7 @@ TER PathState::pushNode(
terResult = pushImply(
pnCur.uAccountID, // Current account.
pnCur.uCurrencyID, // Wanted currency.
- !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as wanted issuer.
+ !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XRP); // Account as wanted issuer.
// Note: pnPrv may no longer be the immediately previous node.
}
@@ -1603,7 +1603,7 @@ TER PathState::pushNode(
terResult = pushImply(
!!pnPrv.uCurrencyID
? ACCOUNT_ONE // Rippling, but offer's don't have an account.
- : ACCOUNT_XNS,
+ : ACCOUNT_XRP,
pnPrv.uCurrencyID,
pnPrv.uIssuerID);
}
@@ -1636,8 +1636,8 @@ PathState::PathState(
{
const uint160 uInCurrencyID = saSendMax.getCurrency();
const uint160 uOutCurrencyID = saSend.getCurrency();
- const uint160 uInIssuerID = !!uInCurrencyID ? saSendMax.getIssuer() : ACCOUNT_XNS;
- const uint160 uOutIssuerID = !!uOutCurrencyID ? saSend.getIssuer() : ACCOUNT_XNS;
+ const uint160 uInIssuerID = !!uInCurrencyID ? saSendMax.getIssuer() : ACCOUNT_XRP;
+ const uint160 uOutIssuerID = !!uOutCurrencyID ? saSend.getIssuer() : ACCOUNT_XRP;
lesEntries = lesSource.duplicate();
@@ -1670,7 +1670,7 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: pushed: account=%s currenc
? uOutIssuerID == uReceiverID
? uReceiverID
: uOutIssuerID
- : ACCOUNT_XNS;
+ : ACCOUNT_XRP;
cLog(lsDEBUG) << boost::str(boost::format("PathState: implied check: uNxtCurrencyID=%s uNxtAccountID=%s")
% RippleAddress::createHumanAccountID(uNxtCurrencyID)
@@ -1730,7 +1730,7 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s curren
| STPathElement::typeIssuer,
uReceiverID, // Receive to output
uOutCurrencyID, // Desired currency
- !!uOutCurrencyID ? uReceiverID : ACCOUNT_XNS);
+ !!uOutCurrencyID ? uReceiverID : ACCOUNT_XRP);
}
if (tesSUCCESS == terStatus)
@@ -2441,13 +2441,13 @@ void TransactionEngine::calcNodeOffer(
{
TER terResult = temUNKNOWN;
- // Direct: not bridging via XNS
+ // Direct: not bridging via XRP
bool bDirectNext = true; // True, if need to load.
uint256 uDirectQuality;
uint256 uDirectTip = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID);
uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip);
- // Bridging: bridging via XNS
+ // Bridging: bridging via XRP
bool bBridge = true; // True, if bridging active. False, missing an offer.
uint256 uBridgeQuality;
STAmount saBridgeIn; // Amount available.
@@ -2475,10 +2475,10 @@ void TransactionEngine::calcNodeOffer(
if (!uCurCurrencyID && !uPrvCurrencyID)
{
- // Bridging: Neither currency is XNS.
- uInTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, CURRENCY_XNS, ACCOUNT_XNS);
+ // Bridging: Neither currency is XRP.
+ uInTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, CURRENCY_XRP, ACCOUNT_XRP);
uInEnd = Ledger::getQualityNext(uInTip);
- uOutTip = Ledger::getBookBase(CURRENCY_XNS, ACCOUNT_XNS, uCurCurrencyID, uCurIssuerID);
+ uOutTip = Ledger::getBookBase(CURRENCY_XRP, ACCOUNT_XRP, uCurCurrencyID, uCurIssuerID);
uOutEnd = Ledger::getQualityNext(uInTip);
}
diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp
index e3de616d28..def66e4f39 100644
--- a/src/SHAMap.cpp
+++ b/src/SHAMap.cpp
@@ -716,23 +716,22 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui
// Log(lsTRACE) << "fetchNodeExternal: missing " << hash;
throw SHAMapMissingNode(mType, id, hash);
}
- assert(Serializer::getSHA512Half(obj->getData()) == hash);
try
{
SHAMapTreeNode::pointer ret = boost::make_shared(id, obj->getData(), mSeq - 1, snfPREFIX);
-#ifdef DEBUG
if (id != *ret)
{
Log(lsFATAL) << "id:" << id << ", got:" << *ret;
assert(false);
+ return SHAMapTreeNode::pointer();
}
if (ret->getNodeHash() != hash)
{
Log(lsFATAL) << "Hashes don't match";
assert(false);
+ return SHAMapTreeNode::pointer();
}
-#endif
return ret;
}
catch (...)
diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h
index b86df1ddb5..4151379c52 100644
--- a/src/SerializedTypes.h
+++ b/src/SerializedTypes.h
@@ -25,9 +25,9 @@ enum PathFlags
PF_ISSUE = 0x80,
};
-#define CURRENCY_XNS uint160(0)
+#define CURRENCY_XRP uint160(0)
#define CURRENCY_ONE uint160(1) // Used as a place holder
-#define ACCOUNT_XNS uint160(0)
+#define ACCOUNT_XRP uint160(0)
#define ACCOUNT_ONE uint160(1) // Used as a place holder
DEFINE_INSTANCE(SerializedValue);
@@ -58,7 +58,7 @@ public:
virtual std::string getFullText() const;
virtual std::string getText() const // just the value
{ return std::string(); }
- virtual Json::Value getJson(int) const
+ virtual Json::Value getJson(int /*options*/) const
{ return getText(); }
virtual void add(Serializer& s) const { ; }
@@ -209,11 +209,11 @@ class STAmount : public SerializedType
protected:
uint160 mCurrency; // Compared by ==. Always update mIsNative.
- uint160 mIssuer; // Not compared by ==. 0 for XNS.
+ uint160 mIssuer; // Not compared by ==. 0 for XRP.
uint64 mValue;
int mOffset;
- bool mIsNative; // Always !mCurrency. Native is XNS.
+ bool mIsNative; // Always !mCurrency. Native is XRP.
bool mIsNegative;
void canonicalize();
@@ -274,7 +274,7 @@ public:
int getExponent() const { return mOffset; }
uint64 getMantissa() const { return mValue; }
- // When the currency is XNS, the value in raw units. S=signed
+ // When the currency is XRP, the value in raw units. S=signed
uint64 getNValue() const { if (!mIsNative) throw std::runtime_error("not native"); return mValue; }
void setNValue(uint64 v) { if (!mIsNative) throw std::runtime_error("not native"); mValue = v; }
int64 getSNValue() const;
diff --git a/src/Suppression.cpp b/src/Suppression.cpp
index ad96d4b152..5eee0ab7f3 100644
--- a/src/Suppression.cpp
+++ b/src/Suppression.cpp
@@ -58,6 +58,25 @@ bool SuppressionTable::addSuppressionPeer(const uint256& index, uint64 peer)
return created;
}
+bool SuppressionTable::addSuppressionPeer(const uint256& index, uint64 peer, int& flags)
+{
+ boost::mutex::scoped_lock sl(mSuppressionMutex);
+
+ bool created;
+ Suppression &s = findCreateEntry(index, created);
+ s.addPeer(peer);
+ flags = s.getFlags();
+ return created;
+}
+
+int SuppressionTable::getFlags(const uint256& index)
+{
+ boost::mutex::scoped_lock sl(mSuppressionMutex);
+
+ bool created;
+ return findCreateEntry(index, created).getFlags();
+}
+
bool SuppressionTable::addSuppressionFlags(const uint256& index, int flag)
{
boost::mutex::scoped_lock sl(mSuppressionMutex);
diff --git a/src/Suppression.h b/src/Suppression.h
index 14b611ede9..fe07e522b6 100644
--- a/src/Suppression.h
+++ b/src/Suppression.h
@@ -14,10 +14,11 @@
DEFINE_INSTANCE(Suppression);
-#define SF_RELAYED 0x01
-#define SF_SIGBAD 0x02
-#define SF_SIGGOOD 0x04
+#define SF_RELAYED 0x01 // Has already been relayed to other nodes
+#define SF_BAD 0x02 // Signature/format is bad
+#define SF_SIGGOOD 0x04 // Signature is good
#define SF_SAVED 0x08
+#define SF_RETRY 0x10 // Transaction can be retried
class Suppression : private IS_INSTANCE(Suppression)
{
@@ -61,12 +62,15 @@ public:
bool addSuppression(const uint256& index);
bool addSuppressionPeer(const uint256& index, uint64 peer);
+ bool addSuppressionPeer(const uint256& index, uint64 peer, int& flags);
bool addSuppressionFlags(const uint256& index, int flag);
bool setFlag(const uint256& index, int flag);
+ int getFlags(const uint256& index);
Suppression getEntry(const uint256&);
bool swapSet(const uint256& index, std::set& peers, int flag);
+ bool swapSet(const uint256& index, std::set& peers);
};
#endif
diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp
index 8ff5c1f341..8b30023167 100644
--- a/src/TransactionAction.cpp
+++ b/src/TransactionAction.cpp
@@ -518,9 +518,9 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac
if (bCreate && !saDstAmount.isNative())
{
// This restriction could be relaxed.
- Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XNS.";
+ Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XRP.";
- return temCREATEXNS;
+ return temCREATEXRP;
}
else if (!bCreate)
{
@@ -569,11 +569,11 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac
}
else
{
- // Direct XNS payment.
+ // Direct XRP payment.
- STAmount saSrcXNSBalance = mTxnAccount->getFieldAmount(sfBalance);
+ STAmount saSrcXRPBalance = mTxnAccount->getFieldAmount(sfBalance);
- if (saSrcXNSBalance < saDstAmount)
+ if (saSrcXRPBalance < saDstAmount)
{
// Transaction might succeed, if applied in a different order.
Log(lsINFO) << "doPayment: Delay transaction: Insufficent funds.";
@@ -582,7 +582,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac
}
else
{
- mTxnAccount->setFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount);
+ mTxnAccount->setFieldAmount(sfBalance, saSrcXRPBalance - saDstAmount);
sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + saDstAmount);
terResult = tesSUCCESS;
@@ -953,7 +953,7 @@ Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGe
}
else if (saTakerPays.isNative() && saTakerGets.isNative())
{
- Log(lsWARNING) << "doOfferCreate: Malformed offer: XNS for XNS";
+ Log(lsWARNING) << "doOfferCreate: Malformed offer: XRP for XRP";
terResult = temBAD_OFFER;
}
diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp
index 0535029396..3c6789ce5b 100644
--- a/src/TransactionEngine.cpp
+++ b/src/TransactionEngine.cpp
@@ -455,7 +455,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
terResult = terRETRY;
}
- if (tesSUCCESS == terResult || isTepPartial(terResult))
+ if ((tesSUCCESS == terResult) || isTepPartial(terResult))
{
// Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially).
Serializer m;
diff --git a/src/TransactionErr.cpp b/src/TransactionErr.cpp
index 9f50b4d3ab..93f3c86877 100644
--- a/src/TransactionErr.cpp
+++ b/src/TransactionErr.cpp
@@ -34,7 +34,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman)
{ temBAD_TRANSFER_RATE, "temBAD_TRANSFER_RATE", "Malformed: Transfer rate must be >= 1.0" },
{ temBAD_SET_ID, "temBAD_SET_ID", "Malformed." },
{ temBAD_SEQUENCE, "temBAD_SEQUENCE", "Malformed: Sequence in not in the past." },
- { temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." },
+ { temCREATEXRP, "temCREATEXRP", "Can not specify non XRP for Create." },
{ temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." },
{ temDST_NEEDED, "temDST_NEEDED", "Destination not specified." },
{ temINSUF_FEE_P, "temINSUF_FEE_P", "Fee not allowed." },
diff --git a/src/TransactionErr.h b/src/TransactionErr.h
index f672caf7f3..93c03515f4 100644
--- a/src/TransactionErr.h
+++ b/src/TransactionErr.h
@@ -36,7 +36,7 @@ enum TER // aka TransactionEngineResult
temBAD_TRANSFER_RATE,
temBAD_SEQUENCE,
temBAD_SET_ID,
- temCREATEXNS,
+ temCREATEXRP,
temDST_IS_SRC,
temDST_NEEDED,
temINSUF_FEE_P,
diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp
index f8fdff08df..8866b039f9 100644
--- a/src/TransactionMeta.cpp
+++ b/src/TransactionMeta.cpp
@@ -121,6 +121,7 @@ static bool compare(const STObject& o1, const STObject& o2)
STObject TransactionMetaSet::getAsObject() const
{
STObject metaData(sfTransactionMetaData);
+ assert(mResult != 255);
metaData.setFieldU8(sfTransactionResult, mResult);
metaData.addObject(mNodes);
return metaData;
diff --git a/src/WSConnection.cpp b/src/WSConnection.cpp
new file mode 100644
index 0000000000..8e8328784a
--- /dev/null
+++ b/src/WSConnection.cpp
@@ -0,0 +1,304 @@
+#include "WSConnection.h"
+#include "WSHandler.h"
+
+#include "../json/reader.h"
+#include "../json/writer.h"
+//
+// WSConnection
+//
+
+SETUP_LOG();
+
+WSConnection::~WSConnection()
+{
+ mNetwork.unsubTransactions(this);
+ mNetwork.unsubRTTransactions(this);
+ mNetwork.unsubLedger(this);
+ mNetwork.unsubServer(this);
+ mNetwork.unsubAccount(this, mSubAccountInfo,true);
+ mNetwork.unsubAccount(this, mSubAccountInfo,false);
+}
+
+void WSConnection::send(const Json::Value& jvObj)
+{
+ mHandler->send(mConnection, jvObj);
+}
+
+//
+// Utilities
+//
+
+Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
+{
+ static struct {
+ const char* pCommand;
+ doFuncPtr dfpFunc;
+ } commandsA[] = {
+ // Request-Response Commands:
+ { "submit", &WSConnection::doSubmit },
+ { "subscribe", &WSConnection::doSubscribe },
+ { "unsubscribe", &WSConnection::doUnsubscribe },
+ { "rpc", &WSConnection::doRPC },
+ };
+
+ if (!jvRequest.isMember("command"))
+ {
+ Json::Value jvResult(Json::objectValue);
+
+ jvResult["type"] = "response";
+ jvResult["result"] = "error";
+ jvResult["error"] = "missingCommand";
+ jvResult["command"] = jvRequest;
+
+ return jvResult;
+ }
+
+ std::string strCommand = jvRequest["command"].asString();
+
+ int i = NUMBER(commandsA);
+
+ while (i-- && strCommand != commandsA[i].pCommand)
+ ;
+
+ Json::Value jvResult(Json::objectValue);
+
+ jvResult["type"] = "response";
+
+ if (i < 0)
+ {
+ jvResult["error"] = "unknownCommand"; // Unknown command.
+ }
+ else
+ {
+ (this->*(commandsA[i].dfpFunc))(jvResult, jvRequest);
+ }
+
+ if (jvRequest.isMember("id"))
+ {
+ jvResult["id"] = jvRequest["id"];
+ }
+
+ if (jvResult.isMember("error"))
+ {
+ jvResult["result"] = "error";
+ jvResult["request"] = jvRequest;
+ }
+ else
+ {
+ jvResult["result"] = "success";
+ }
+
+ return jvResult;
+}
+
+boost::unordered_set WSConnection::parseAccountIds(const Json::Value& jvArray)
+{
+ boost::unordered_set usnaResult;
+
+ for (Json::Value::const_iterator it = jvArray.begin(); it != jvArray.end(); it++)
+ {
+ RippleAddress naString;
+
+ if (!(*it).isString() || !naString.setAccountID((*it).asString()))
+ {
+ usnaResult.clear();
+ break;
+ }
+ else
+ {
+ (void) usnaResult.insert(naString);
+ }
+ }
+
+ return usnaResult;
+}
+
+//
+// Commands
+//
+
+/*
+server : Sends a message anytime the server status changes such as network connectivity.
+ledger : Sends a message at every ledger close.
+transactions : Sends a message for every transaction that makes it into a ledger.
+rt_transactions
+accounts
+rt_accounts
+*/
+void WSConnection::doSubscribe(Json::Value& jvResult, Json::Value& jvRequest)
+{
+ if (jvRequest.isMember("streams"))
+ {
+ for (Json::Value::iterator it = jvRequest["streams"].begin(); it != jvRequest["streams"].end(); it++)
+ {
+ if ((*it).isString() )
+ {
+ std::string streamName=(*it).asString();
+
+ if(streamName=="server")
+ {
+ mNetwork.subServer(this);
+ }else if(streamName=="ledger")
+ {
+ mNetwork.subLedger(this);
+ }else if(streamName=="transactions")
+ {
+ mNetwork.subTransactions(this);
+ }else if(streamName=="rt_transactions")
+ {
+ mNetwork.subRTTransactions(this);
+ }else
+ {
+ jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
+ }
+ }else
+ {
+ jvResult["error"] = "malformedSteam";
+ }
+ }
+ }
+
+ if (jvRequest.isMember("rt_accounts"))
+ {
+ boost::unordered_set usnaAccoundIds = parseAccountIds(jvRequest["rt_accounts"]);
+
+ if (usnaAccoundIds.empty())
+ {
+ jvResult["error"] = "malformedAccount";
+ }else
+ {
+ boost::mutex::scoped_lock sl(mLock);
+
+ BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
+ {
+ mSubAccountInfo.insert(naAccountID);
+ }
+
+ mNetwork.subAccount(this, usnaAccoundIds,true);
+ }
+ }
+
+ if (jvRequest.isMember("accounts"))
+ {
+ boost::unordered_set usnaAccoundIds = parseAccountIds(jvRequest["accounts"]);
+
+ if (usnaAccoundIds.empty())
+ {
+ jvResult["error"] = "malformedAccount";
+ }else
+ {
+ boost::mutex::scoped_lock sl(mLock);
+
+ BOOST_FOREACH(const RippleAddress& naAccountID, usnaAccoundIds)
+ {
+ mSubAccountInfo.insert(naAccountID);
+ }
+
+ mNetwork.subAccount(this, usnaAccoundIds,false);
+ }
+ }
+}
+
+void WSConnection::doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest)
+{
+ if (jvRequest.isMember("streams"))
+ {
+ for (Json::Value::iterator it = jvRequest["streams"].begin(); it != jvRequest["streams"].end(); it++)
+ {
+ if ((*it).isString() )
+ {
+ std::string streamName=(*it).asString();
+
+ if(streamName=="server")
+ {
+ mNetwork.unsubServer(this);
+ }else if(streamName=="ledger")
+ {
+ mNetwork.unsubLedger(this);
+ }else if(streamName=="transactions")
+ {
+ mNetwork.unsubTransactions(this);
+ }else if(streamName=="rt_transactions")
+ {
+ mNetwork.unsubRTTransactions(this);
+ }else
+ {
+ jvResult["error"] = str(boost::format("Unknown stream: %s") % streamName);
+ }
+ }else
+ {
+ jvResult["error"] = "malformedSteam";
+ }
+ }
+ }
+
+ if (jvRequest.isMember("rt_accounts"))
+ {
+ boost::unordered_set