mirror of
https://github.com/Xahau/xahaud.git
synced 2026-10-05 11:28:06 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
57
js/events.js
Normal file
57
js/events.js
Normal 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;
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ void LedgerAcquire::addPeers()
|
||||
if (!found)
|
||||
{
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
peerHas(peer);
|
||||
peerHas(peer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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(); }
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -276,7 +276,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class SendXNSOp : public Operation
|
||||
class SendXRPOp : public Operation
|
||||
{
|
||||
public:
|
||||
bool work(Interpreter* interpreter)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
203
src/Peer.cpp
203
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<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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -15,4 +15,5 @@ class RPCDoor
|
||||
bool isClientAllowed(const std::string& ip);
|
||||
public:
|
||||
RPCDoor(boost::asio::io_service& io_service);
|
||||
~RPCDoor();
|
||||
};
|
||||
|
||||
1877
src/RPCHandler.cpp
1877
src/RPCHandler.cpp
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (...)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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." },
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
304
src/WSConnection.cpp
Normal 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
55
src/WSConnection.h
Normal 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);
|
||||
|
||||
};
|
||||
1077
src/WSDoor.cpp
1077
src/WSDoor.cpp
File diff suppressed because it is too large
Load Diff
124
src/WSHandler.h
Normal file
124
src/WSHandler.h
Normal 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
|
||||
Reference in New Issue
Block a user