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

This commit is contained in:
Arthur Britto
2012-11-05 09:42:05 -08:00
48 changed files with 1779 additions and 2817 deletions

57
js/events.js Normal file
View File

@@ -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;

View File

@@ -171,6 +171,7 @@
<ClCompile Include="src\utils.cpp" />
<ClCompile Include="src\ValidationCollection.cpp" />
<ClCompile Include="src\Wallet.cpp" />
<ClCompile Include="src\WSConnection.cpp" />
<ClCompile Include="src\WSDoor.cpp" />
<ClCompile Include="websocketpp\src\base64\base64.cpp" />
<ClCompile Include="websocketpp\src\md5\md5.c" />
@@ -205,15 +206,20 @@
<ClInclude Include="src\ConnectionPool.h" />
<ClInclude Include="src\Contract.h" />
<ClInclude Include="src\Conversion.h" />
<ClInclude Include="src\FieldNames.h" />
<ClInclude Include="src\HashedObject.h" />
<ClInclude Include="src\HashPrefixes.h" />
<ClInclude Include="src\HttpReply.h" />
<ClInclude Include="src\HttpRequest.h" />
<ClInclude Include="src\HttpsClient.h" />
<ClInclude Include="src\InstanceCounter.h" />
<ClInclude Include="src\Interpreter.h" />
<ClInclude Include="src\JobQueue.h" />
<ClInclude Include="src\key.h" />
<ClInclude Include="src\Ledger.h" />
<ClInclude Include="src\LedgerAcquire.h" />
<ClInclude Include="src\LedgerConsensus.h" />
<ClInclude Include="src\LedgerEntrySet.h" />
<ClInclude Include="src\LedgerFormats.h" />
<ClInclude Include="src\LedgerHistory.h" />
<ClInclude Include="src\LedgerMaster.h" />
@@ -233,8 +239,12 @@
<ClInclude Include="src\Peer.h" />
<ClInclude Include="src\PeerDoor.h" />
<ClInclude Include="src\PubKeyCache.h" />
<ClInclude Include="src\RangeSet.h" />
<ClInclude Include="src\RequestParser.h" />
<ClInclude Include="src\rfc1751.h" />
<ClInclude Include="src\ripple.pb.h" />
<ClInclude Include="src\RippleAddress.h" />
<ClInclude Include="src\RippleCalc.h" />
<ClInclude Include="src\RippleLines.h" />
<ClInclude Include="src\RippleState.h" />
<ClInclude Include="src\RPC.h" />
@@ -250,19 +260,29 @@
<ClInclude Include="src\SerializedTransaction.h" />
<ClInclude Include="src\SerializedTypes.h" />
<ClInclude Include="src\SerializedValidation.h" />
<ClInclude Include="src\SerializeProto.h" />
<ClInclude Include="src\Serializer.h" />
<ClInclude Include="src\SHAMap.h" />
<ClInclude Include="src\SHAMapSync.h" />
<ClInclude Include="src\SNTPClient.h" />
<ClInclude Include="src\Suppression.h" />
<ClInclude Include="src\TaggedCache.h" />
<ClInclude Include="src\Transaction.h" />
<ClInclude Include="src\TransactionEngine.h" />
<ClInclude Include="src\TransactionErr.h" />
<ClInclude Include="src\TransactionFormats.h" />
<ClInclude Include="src\TransactionMaster.h" />
<ClInclude Include="src\TransactionMeta.h" />
<ClInclude Include="src\types.h" />
<ClInclude Include="src\uint256.h" />
<ClInclude Include="src\UniqueNodeList.h" />
<ClInclude Include="src\utils.h" />
<ClInclude Include="src\ValidationCollection.h" />
<ClInclude Include="src\Version.h" />
<ClInclude Include="src\Wallet.h" />
<ClInclude Include="src\WSConnection.h" />
<ClInclude Include="src\WSDoor.h" />
<ClInclude Include="src\WSHandler.h" />
<ClInclude Include="TimingService.h" />
<ClInclude Include="ExtendedTransaction.h" />
<ClInclude Include="util\pugiconfig.hpp" />

View File

@@ -309,6 +309,15 @@
<ClCompile Include="src\RangeSet.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\JobQueue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\InstanceCounter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\WSConnection.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="KnownNodeList.h">
@@ -566,6 +575,63 @@
<ClInclude Include="src\RPCHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\WSHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\FieldNames.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\HashPrefixes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\InstanceCounter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\JobQueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\LedgerEntrySet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\RangeSet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ripple.pb.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\RippleAddress.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\RippleCalc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\SerializeProto.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\SHAMapSync.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\SNTPClient.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Suppression.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\TransactionErr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\TransactionMeta.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\WSConnection.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\WSDoor.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="wallet.xml" />

View File

@@ -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);

View File

@@ -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<unsigned char *>(&mNonceST), sizeof(mNonceST));

View File

@@ -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); }

View File

@@ -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(); }

View File

@@ -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)

View File

@@ -10,9 +10,9 @@
#include <boost/filesystem.hpp>
#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

View File

@@ -21,7 +21,6 @@ HashedObjectStore::HashedObjectStore(int cacheSize, int cacheAge) :
bool HashedObjectStore::store(HashedObjectType type, uint32 index,
const std::vector<unsigned char>& 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<HashedObject>(type, index, data, hash);
if (!mCache.canonicalize(hash, object))

View File

@@ -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();

View File

@@ -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 };

View File

@@ -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;

View File

@@ -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

View File

@@ -170,7 +170,7 @@ void LedgerAcquire::addPeers()
if (!found)
{
BOOST_FOREACH(Peer::ref peer, peerList)
peerHas(peer);
peerHas(peer);
}
}

View File

@@ -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<Peer::pointer> 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<PeerSet> TransactionAcquire::pmDowncast()
{
return boost::shared_polymorphic_downcast<PeerSet>(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<SHAMapNode>& nodeIDs,
const std::list< std::vector<unsigned char> >& 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<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin();
@@ -116,12 +150,18 @@ bool TransactionAcquire::takeNodes(const std::list<SHAMapNode>& 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<uint256, SHAMap::pointer>::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<uint256, TransactionAcquire::pointer>::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<LedgerProposal::pointer> >::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<uint64> 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<PackedMessage>(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;
}

View File

@@ -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();

View File

@@ -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.

View File

@@ -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<Ledger>(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;
}

View File

@@ -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<uint256, Transaction::pointer> 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(); }
};

View File

@@ -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();
}

View File

@@ -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; }

View File

@@ -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<uint64> 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<PackedMessage>(tx, ripple::mtTRANSACTION);
theApp->getConnectionPool().relayMessageBut(peers, packet);
}
return trans;
}
cLog(lsDEBUG) << "Status other than success " << r;
std::set<uint64> 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<PackedMessage>(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<ripple::TMProposeSet> 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<LedgerProposal>(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<LedgerProposal>(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<uint64> peers;
theApp->getSuppression().swapSet(proposal->getSuppression(), peers, SF_RELAYED);
PackedMessage::pointer message = boost::make_shared<PackedMessage>(*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>& peer, const uint256& h
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& 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>& 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<boost::interprocess::interprocess_upgradable_mutex> 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<boost::interprocess::interprocess_upgradable_mutex> 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<boost::interprocess::interprocess_upgradable_mutex> 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<boost::interprocess::interprocess_upgradable_mutex> 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<boost::interprocess::interprocess_upgradable_mutex> 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<boost::interprocess::interprocess_upgradable_mutex> 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<InfoSub*> usisNotify;
boost::unordered_set<InfoSub*> notify;
{
boost::interprocess::sharable_lock<boost::interprocess::interprocess_upgradable_mutex> 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<boost::interprocess::interprocess_upgradable_mutex> 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<RippleAddress>& vnaAccountIDs)
void NetworkOPs::subAccount(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs,bool rt)
{
subInfoMapType& subMap=mSubAccount;
if(rt) subMap=mSubRTAccount;
boost::interprocess::scoped_lock<boost::interprocess::interprocess_upgradable_mutex> 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<InfoSub*> 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<InfoSub*> 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<RippleAddress>& vnaAccountIDs)
void NetworkOPs::unsubAccount(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs,bool rt)
{
subInfoMapType& subMap= rt ? mSubRTAccount : mSubAccount;
boost::interprocess::scoped_lock<boost::interprocess::interprocess_upgradable_mutex> 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<RippleAddress>& vnaAccountIDs)
{
boost::interprocess::scoped_lock<boost::interprocess::interprocess_upgradable_mutex> sl(mMonitorLock);
BOOST_FOREACH(const RippleAddress& naAccountID, vnaAccountIDs)
{
subInfoMapType::iterator simIterator = mSubAccountTransaction.find(naAccountID.getAccountID());
if (simIterator == mSubAccountTransaction.end())
{
// Not found
boost::unordered_set<InfoSub*> 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<RippleAddress>& vnaAccountIDs)
{
boost::interprocess::scoped_lock<boost::interprocess::interprocess_upgradable_mutex> 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

View File

@@ -51,6 +51,8 @@ protected:
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::value_type subInfoMapValue;
typedef boost::unordered_map<uint160,boost::unordered_set<InfoSub*> >::iterator subInfoMapIterator;
typedef boost::unordered_map<uint160,std::pair<InfoSub*,uint32> > 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<InfoSub*> mSubLedger; // ledger accepteds
boost::unordered_set<InfoSub*> mSubLedgerAccounts; // ledger accepteds + affected accounts
boost::unordered_set<InfoSub*> mSubTransaction; // all transactions
boost::unordered_set<InfoSub*> mSubTxMeta; // all transaction meta
// subInfoMapType mSubTransactionAccounts;
subInfoMapType mSubAccount;
subInfoMapType mSubRTAccount;
subSubmitMapType mSubmitMap;
boost::unordered_set<InfoSub*> mSubLedger; // accepted ledgers
boost::unordered_set<InfoSub*> mSubServer; // when server changes connectivity state
boost::unordered_set<InfoSub*> mSubTransactions; // all accepted transactions
boost::unordered_set<InfoSub*> 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<unsigned char>& myNode, std::list< std::vector<unsigned char> >& 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<ripple::TMProposeSet> set,
RippleAddress nodePublic, uint256 checkLedger, bool sigGood);
bool gotTXData(const boost::shared_ptr<Peer>& peer, const uint256& hash,
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
bool recvValidation(const SerializedValidation::pointer& val);
@@ -199,6 +203,7 @@ public:
boost::unordered_map<uint160,
std::list<LedgerProposal::pointer> >& peekStoredProposals() { return mStoredProposals; }
void storeProposal(const LedgerProposal::pointer& proposal, const RippleAddress& peerPublic);
uint256 getConsensusLCL();
// client information retrieval functions
std::vector< std::pair<uint32, uint256> >
@@ -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<RippleAddress>& vnaAccountIDs);
void unsubAccountInfo(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs);
void subAccountTransaction(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs);
void unsubAccountTransaction(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs);
// void subAccountChanges(InfoSub* ispListener, const uint256 uLedgerHash);
// void unsubAccountChanges(InfoSub* ispListener);
void subAccount(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& vnaAccountIDs,bool rt);
void unsubAccount(InfoSub* ispListener, const boost::unordered_set<RippleAddress>& 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

View File

@@ -276,7 +276,7 @@ public:
}
};
class SendXNSOp : public Operation
class SendXRPOp : public Operation
{
public:
bool work(Interpreter* interpreter)

View File

@@ -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);

View File

@@ -9,7 +9,7 @@ But for now it is probably faster to just generate it each time
class OrderBookDB
{
std::vector<OrderBook::pointer> mEmptyVector;
std::vector<OrderBook::pointer> mXNSOrders;
std::vector<OrderBook::pointer> mXRPOrders;
std::map<uint160, std::vector<OrderBook::pointer> > mIssuerMap;
std::map<uint256, bool > mKnownMap;
@@ -17,8 +17,8 @@ class OrderBookDB
public:
OrderBookDB(Ledger::pointer ledger);
// return list of all orderbooks that want XNS
std::vector<OrderBook::pointer>& getXNSInBooks(){ return mXNSOrders; }
// return list of all orderbooks that want XRP
std::vector<OrderBook::pointer>& getXRPInBooks(){ return mXRPOrders; }
// return list of all orderbooks that want IssuerID
std::vector<OrderBook::pointer>& getBooks(const uint160& issuerID);
// return list of all orderbooks that want this issuerID and currencyID

View File

@@ -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));

View File

@@ -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<ripple::TMProposeSet> msg = boost::make_shared<ripple::TMProposeSet>();
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> peer)
{
#ifndef TRUST_NETWORK
try
{
#endif
Transaction::pointer tx;
if ((flags & SF_SIGGOOD) != 0)
{
tx = boost::make_shared<Transaction>(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<Transaction>(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<SerializedTransaction>(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<Peer>(shared_from_this())));
tx = boost::make_shared<Transaction>(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<ripple::TMProposeSet> packet,
LedgerProposal::pointer proposal, uint256 consensusLCL, RippleAddress nodePublic, boost::weak_ptr<Peer> 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<uint64> peers;
theApp->getSuppression().swapSet(proposal->getSuppression(), peers, SF_RELAYED);
PackedMessage::pointer message = boost::make_shared<PackedMessage>(set, ripple::mtPROPOSE_LEDGER);
theApp->getConnectionPool().relayMessageBut(peers, message);
}
else
cLog(lsDEBUG) << "Not relaying untrusted proposal";
}
void Peer::recvPropose(const boost::shared_ptr<ripple::TMProposeSet>& 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<PackedMessage>(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<LedgerProposal>(
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<Peer>(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<unsigned char> > rawNodes;
if(map->getNodeFat(mn, nodeIDs, rawNodes, fatRoot, fatLeaves))
{
assert(nodeIDs.size() == rawNodes.size());
cLog(lsDEBUG) << "getNodeFat got " << rawNodes.size() << " nodes";
std::vector<SHAMapNode>::iterator nodeIDIterator;
std::list< std::vector<unsigned char> >::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<PackedMessage>(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<std::string>(GET_VERSION_MAJOR(mHello.protoversion())) + "." +
ret["protocol"] = boost::lexical_cast<std::string>(GET_VERSION_MAJOR(mHello.protoversion())) + "." +
boost::lexical_cast<std::string>(GET_VERSION_MINOR(mHello.protoversion()));
if (!!mClosedLedgerHash)

View File

@@ -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<std::string,int> 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<ripple::TMProposeSet>& packet);
void recvHaveTxSet(ripple::TMHaveTransactionSet& packet);
void getSessionCookie(std::string& strDst);

View File

@@ -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()
{

View File

@@ -15,4 +15,5 @@ class RPCDoor
bool isClientAllowed(const std::string& ip);
public:
RPCDoor(boost::asio::io_service& io_service);
~RPCDoor();
};

File diff suppressed because it is too large Load Diff

View File

@@ -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 &params);
Json::Value doAccountDomainSet(const Json::Value &params);
Json::Value doAccountEmailSet(const Json::Value &params);
Json::Value doAccountInfo(const Json::Value& params);
Json::Value doAccountMessageSet(const Json::Value &params);
Json::Value doAccountPublishSet(const Json::Value &params);
Json::Value doAccountRateSet(const Json::Value &params);
Json::Value doAccountTransactions(const Json::Value& params);
Json::Value doAccountWalletSet(const Json::Value &params);
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 &params);
Json::Value doRippleLinesGet(const Json::Value &params);
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

View File

@@ -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);
}

View File

@@ -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<SHAMapTreeNode>(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 (...)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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<uint64>& peers, int flag);
bool swapSet(const uint256& index, std::set<uint64>& peers);
};
#endif

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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." },

View File

@@ -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,

View File

@@ -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;

304
src/WSConnection.cpp Normal file
View File

@@ -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<RippleAddress> WSConnection::parseAccountIds(const Json::Value& jvArray)
{
boost::unordered_set<RippleAddress> 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<RippleAddress> 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<RippleAddress> 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<RippleAddress> 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.unsubAccount(this, usnaAccoundIds,true);
}
}
if (jvRequest.isMember("accounts"))
{
boost::unordered_set<RippleAddress> 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.unsubAccount(this, usnaAccoundIds,false);
}
}
}
void WSConnection::doRPC(Json::Value& jvResult, Json::Value& jvRequest)
{
if (jvRequest.isMember("rpc_command") )
{
jvResult=theApp->getRPCHandler().doCommand(jvRequest["rpc_command"].asString(),jvRequest["params"],RPCHandler::GUEST);
}else jvResult["error"] = "fieldNotCommand";
}
// XXX Currently requires secret. Allow signed transaction as an alternative.
void WSConnection::doSubmit(Json::Value& jvResult, Json::Value& jvRequest)
{
if (!jvRequest.isMember("tx_json"))
{
jvResult["error"] = "fieldNotFoundTransaction";
}else if (!jvRequest.isMember("key"))
{
jvResult["error"] = "fieldNotFoundKey";
}else
{
jvResult=theApp->getRPCHandler().handleJSONSubmit(jvRequest["key"].asString(),jvRequest["tx_json"]);
// TODO: track the transaction mNetwork.subSubmit(this, jvResult["tx hash"] );
}
}

55
src/WSConnection.h Normal file
View File

@@ -0,0 +1,55 @@
#include "../websocketpp/src/sockets/tls.hpp"
#include "../websocketpp/src/websocketpp.hpp"
#include "WSDoor.h"
#include "Application.h"
#include "Log.h"
#include "NetworkOPs.h"
template <typename endpoint_type>
class WSServerHandler;
//
// Storage for connection specific info
// - Subscriptions
//
class WSConnection : public InfoSub
{
public:
typedef websocketpp::WSDOOR_SERVER::handler::connection_ptr connection_ptr;
typedef websocketpp::WSDOOR_SERVER::handler::message_ptr message_ptr;
protected:
typedef void (WSConnection::*doFuncPtr)(Json::Value& jvResult, Json::Value &jvRequest);
boost::mutex mLock;
boost::unordered_set<RippleAddress> mSubAccountInfo;
boost::unordered_set<RippleAddress> mSubAccountTransaction;
WSServerHandler<websocketpp::WSDOOR_SERVER>* mHandler;
connection_ptr mConnection;
NetworkOPs& mNetwork;
public:
// WSConnection()
// : mHandler((WSServerHandler<websocketpp::WSDOOR_SERVER>*)(NULL)),
// mConnection(connection_ptr()) { ; }
WSConnection(WSServerHandler<websocketpp::WSDOOR_SERVER>* wshpHandler, connection_ptr cpConnection)
: mHandler(wshpHandler), mConnection(cpConnection), mNetwork(theApp->getOPs()) { ; }
virtual ~WSConnection();
// Implement overridden functions from base class:
void send(const Json::Value& jvObj);
// Utilities
Json::Value invokeCommand(Json::Value& jvRequest);
boost::unordered_set<RippleAddress> parseAccountIds(const Json::Value& jvArray);
// Commands
void doSubmit(Json::Value& jvResult, Json::Value& jvRequest);
void doRPC(Json::Value& jvResult, Json::Value& jvRequest);
void doSubscribe(Json::Value& jvResult, Json::Value& jvRequest);
void doUnsubscribe(Json::Value& jvResult, Json::Value& jvRequest);
};

File diff suppressed because it is too large Load Diff

124
src/WSHandler.h Normal file
View File

@@ -0,0 +1,124 @@
#ifndef __WSHANDLER__
#define __WSHANDLER__
class WSConnection;
// A single instance of this object is made.
// This instance dispatches all events. There is no per connection persistence.
template <typename endpoint_type>
class WSServerHandler : public endpoint_type::handler
{
public:
typedef typename endpoint_type::handler::connection_ptr connection_ptr;
typedef typename endpoint_type::handler::message_ptr message_ptr;
// Private reasons to close.
enum {
crTooSlow = 4000, // Client is too slow.
};
private:
boost::shared_ptr<boost::asio::ssl::context> mCtx;
protected:
boost::mutex mMapLock;
// For each connection maintain an associated object to track subscriptions.
boost::unordered_map<connection_ptr, boost::shared_ptr<WSConnection> > mMap;
public:
WSServerHandler(boost::shared_ptr<boost::asio::ssl::context> spCtx) : mCtx(spCtx) {}
boost::shared_ptr<boost::asio::ssl::context> on_tls_init()
{
return mCtx;
}
void send(connection_ptr cpClient, message_ptr mpMessage)
{
try
{
cpClient->send(mpMessage->get_payload(), mpMessage->get_opcode());
}
catch (...)
{
cpClient->close(websocketpp::close::status::value(crTooSlow), std::string("Client is too slow."));
}
}
void send(connection_ptr cpClient, const std::string& strMessage)
{
try
{
cLog(lsDEBUG) << "Ws:: Sending '" << strMessage << "'";
cpClient->send(strMessage);
}
catch (...)
{
cpClient->close(websocketpp::close::status::value(crTooSlow), std::string("Client is too slow."));
}
}
void send(connection_ptr cpClient, const Json::Value& jvObj)
{
Json::FastWriter jfwWriter;
// cLog(lsDEBUG) << "Ws:: Object '" << jfwWriter.write(jvObj) << "'";
send(cpClient, jfwWriter.write(jvObj));
}
void on_open(connection_ptr cpClient)
{
boost::mutex::scoped_lock sl(mMapLock);
mMap[cpClient] = boost::make_shared<WSConnection>(this, cpClient);
}
void on_close(connection_ptr cpClient)
{
boost::mutex::scoped_lock sl(mMapLock);
mMap.erase(cpClient);
}
void on_message(connection_ptr cpClient, message_ptr mpMessage)
{
Json::Value jvRequest;
Json::Reader jrReader;
if (mpMessage->get_opcode() != websocketpp::frame::opcode::TEXT)
{
Json::Value jvResult(Json::objectValue);
jvResult["type"] = "error";
jvResult["error"] = "wsTextRequired"; // We only accept text messages.
send(cpClient, jvResult);
}
else if (!jrReader.parse(mpMessage->get_payload(), jvRequest) || jvRequest.isNull() || !jvRequest.isObject())
{
Json::Value jvResult(Json::objectValue);
jvResult["type"] = "error";
jvResult["error"] = "jsonInvalid"; // Received invalid json.
jvResult["value"] = mpMessage->get_payload();
send(cpClient, jvResult);
}
else
{
send(cpClient, mMap[cpClient]->invokeCommand(jvRequest));
}
}
// Respond to http requests.
void http(connection_ptr cpClient)
{
cpClient->set_body(
"<!DOCTYPE html><html><head><title>" SYSTEM_NAME " Test</title></head>"
"<body><h1>" SYSTEM_NAME " Test</h1><p>This page shows http(s) connectivity is working.</p></body></html>");
}
};
#endif