mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge branch 'master' into continuousClose
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#define SYSTEM_NAME "newcoin"
|
||||
#define SYSTEM_CURRENCY_CODE "XNS"
|
||||
#define SYSTEM_CURRENCY_PRECISION 6
|
||||
#define SYSTEM_CURRENCY_CODE_RIPPLE "XNR"
|
||||
|
||||
#define SYSTEM_CURRENCY_GIFT 1000ull
|
||||
#define SYSTEM_CURRENCY_USERS 100000000ull
|
||||
@@ -54,8 +55,6 @@ public:
|
||||
std::vector<std::string> VALIDATORS; // Validators from newcoind.cfg.
|
||||
std::vector<std::string> IPS; // Peer IPs from newcoind.cfg.
|
||||
|
||||
|
||||
|
||||
// Network parameters
|
||||
int NETWORK_START_TIME; // The Unix time we start ledger 0.
|
||||
int TRANSACTION_FEE_BASE;
|
||||
@@ -88,7 +87,6 @@ public:
|
||||
std::string RPC_PASSWORD;
|
||||
bool RPC_ALLOW_REMOTE;
|
||||
|
||||
|
||||
// Validation
|
||||
NewcoinAddress VALIDATION_SEED;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ void HttpsClient::httpsNext()
|
||||
{
|
||||
mDeadline.async_wait(
|
||||
boost::bind(
|
||||
&HttpsClient::handleDeadline,
|
||||
&HttpsClient::ShandleDeadline,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
@@ -78,7 +78,7 @@ void HttpsClient::httpsNext()
|
||||
|
||||
mResolver.async_resolve(*mQuery,
|
||||
boost::bind(
|
||||
&HttpsClient::handleResolve,
|
||||
&HttpsClient::ShandleResolve,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::iterator));
|
||||
@@ -149,7 +149,7 @@ void HttpsClient::handleResolve(
|
||||
mSocketSsl.lowest_layer(),
|
||||
itrEndpoint,
|
||||
boost::bind(
|
||||
&HttpsClient::handleConnect,
|
||||
&HttpsClient::ShandleConnect,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
@@ -183,7 +183,7 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult)
|
||||
if (!mShutdown)
|
||||
{
|
||||
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::client,
|
||||
boost::bind(&HttpsClient::handleRequest,
|
||||
boost::bind(&HttpsClient::ShandleRequest,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
@@ -219,7 +219,7 @@ void HttpsClient::handleRequest(const boost::system::error_code& ecResult)
|
||||
boost::asio::async_write(
|
||||
mSocketSsl,
|
||||
mRequest,
|
||||
boost::bind(&HttpsClient::handleWrite,
|
||||
boost::bind(&HttpsClient::ShandleWrite,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
@@ -244,7 +244,7 @@ void HttpsClient::handleWrite(const boost::system::error_code& ecResult)
|
||||
mSocketSsl,
|
||||
mResponse,
|
||||
boost::asio::transfer_all(),
|
||||
boost::bind(&HttpsClient::handleData,
|
||||
boost::bind(&HttpsClient::ShandleData,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
class HttpsClient : public boost::enable_shared_from_this<HttpsClient>
|
||||
{
|
||||
private:
|
||||
typedef boost::shared_ptr<HttpsClient> pointer;
|
||||
|
||||
boost::asio::ssl::context mCtx;
|
||||
boost::asio::ip::tcp::resolver mResolver;
|
||||
boost::shared_ptr<boost::asio::ip::tcp::resolver::query> mQuery;
|
||||
@@ -38,16 +40,28 @@ private:
|
||||
boost::posix_time::time_duration mTimeout;
|
||||
|
||||
void handleDeadline(const boost::system::error_code& ecResult);
|
||||
static void ShandleDeadline(pointer This, const boost::system::error_code& ecResult)
|
||||
{ This->handleDeadline(ecResult); }
|
||||
|
||||
void handleResolve(
|
||||
const boost::system::error_code& ecResult,
|
||||
boost::asio::ip::tcp::resolver::iterator endpoint_iterator
|
||||
);
|
||||
void handleResolve(const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
|
||||
static void ShandleResolve(pointer This, const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
|
||||
{ This->handleResolve(ecResult, endpoint_iterator); }
|
||||
|
||||
void handleConnect(const boost::system::error_code& ecResult);
|
||||
static void ShandleConnect(pointer This, const boost::system::error_code& ecResult)
|
||||
{ This->handleConnect(ecResult); }
|
||||
|
||||
void handleRequest(const boost::system::error_code& ecResult);
|
||||
static void ShandleRequest(pointer This, const boost::system::error_code& ecResult)
|
||||
{ This->handleRequest(ecResult); }
|
||||
|
||||
void handleWrite(const boost::system::error_code& ecResult);
|
||||
static void ShandleWrite(pointer This, const boost::system::error_code& ecResult)
|
||||
{ This->handleWrite(ecResult); }
|
||||
|
||||
void handleData(const boost::system::error_code& ecResult);
|
||||
static void ShandleData(pointer This, const boost::system::error_code& ecResult)
|
||||
{ This->handleData(ecResult); }
|
||||
|
||||
void parseData();
|
||||
void httpsNext();
|
||||
|
||||
@@ -74,6 +74,9 @@ public:
|
||||
|
||||
static NewcoinAddress createAccountID(const uint160& uiAccountID);
|
||||
|
||||
static std::string createHumanAccountID(const uint160& uiAccountID)
|
||||
{ return createAccountID(uiAccountID).humanAccountID(); }
|
||||
|
||||
static std::string createHumanAccountID(const std::vector<unsigned char>& vPrivate)
|
||||
{ return createAccountPrivate(vPrivate).humanAccountID(); }
|
||||
|
||||
|
||||
16
src/Peer.cpp
16
src/Peer.cpp
@@ -88,7 +88,7 @@ void Peer::detach(const char *rsn)
|
||||
mSendQ.clear();
|
||||
|
||||
(void) mVerifyTimer.cancel();
|
||||
mSocketSsl.async_shutdown(boost::bind(&Peer::handleShutdown, shared_from_this(), boost::asio::placeholders::error));
|
||||
mSocketSsl.async_shutdown(boost::bind(&Peer::sHandleShutdown, shared_from_this(), boost::asio::placeholders::error));
|
||||
|
||||
if (mNodePublic.isValid())
|
||||
{
|
||||
@@ -165,7 +165,7 @@ void Peer::connect(const std::string strIp, int iPort)
|
||||
else
|
||||
{
|
||||
mVerifyTimer.expires_from_now(boost::posix_time::seconds(NODE_VERIFY_SECONDS), err);
|
||||
mVerifyTimer.async_wait(boost::bind(&Peer::handleVerifyTimer, shared_from_this(), boost::asio::placeholders::error));
|
||||
mVerifyTimer.async_wait(boost::bind(&Peer::sHandleVerifyTimer, shared_from_this(), boost::asio::placeholders::error));
|
||||
|
||||
if (err)
|
||||
{
|
||||
@@ -183,7 +183,7 @@ void Peer::connect(const std::string strIp, int iPort)
|
||||
getSocket(),
|
||||
itrEndpoint,
|
||||
boost::bind(
|
||||
&Peer::handleConnect,
|
||||
&Peer::sHandleConnect,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::iterator));
|
||||
@@ -223,7 +223,7 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip
|
||||
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
|
||||
|
||||
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::client,
|
||||
boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error));
|
||||
boost::bind(&Peer::sHandleStart, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ void Peer::connected(const boost::system::error_code& error)
|
||||
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
|
||||
|
||||
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::server,
|
||||
boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error));
|
||||
boost::bind(&Peer::sHandleStart, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
else if (!mDetaching)
|
||||
{
|
||||
@@ -267,7 +267,7 @@ void Peer::sendPacketForce(PackedMessage::pointer packet)
|
||||
mSendingPacket = packet;
|
||||
|
||||
boost::asio::async_write(mSocketSsl, boost::asio::buffer(packet->getBuffer()),
|
||||
boost::bind(&Peer::handle_write, shared_from_this(),
|
||||
boost::bind(&Peer::sHandle_write, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
@@ -296,7 +296,7 @@ void Peer::start_read_header()
|
||||
mReadbuf.resize(HEADER_SIZE);
|
||||
|
||||
boost::asio::async_read(mSocketSsl, boost::asio::buffer(mReadbuf),
|
||||
boost::bind(&Peer::handle_read_header, shared_from_this(), boost::asio::placeholders::error));
|
||||
boost::bind(&Peer::sHandle_read_header, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ void Peer::start_read_body(unsigned msg_len)
|
||||
mReadbuf.resize(HEADER_SIZE + msg_len);
|
||||
|
||||
boost::asio::async_read(mSocketSsl, boost::asio::buffer(&mReadbuf[HEADER_SIZE], msg_len),
|
||||
boost::bind(&Peer::handle_read_body, shared_from_this(), boost::asio::placeholders::error));
|
||||
boost::bind(&Peer::sHandle_read_body, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
22
src/Peer.h
22
src/Peer.h
@@ -24,10 +24,15 @@ typedef std::pair<std::string,int> ipPort;
|
||||
class Peer : public boost::enable_shared_from_this<Peer>
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<Peer> pointer;
|
||||
|
||||
static const int psbGotHello = 0, psbSentHello = 1, psbInMap = 2, psbTrusted = 3;
|
||||
static const int psbNoLedgers = 4, psbNoTransactions = 5, psbDownLevel = 6;
|
||||
|
||||
void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it);
|
||||
static void sHandleConnect(Peer::pointer ptr, const boost::system::error_code& error,
|
||||
boost::asio::ip::tcp::resolver::iterator it)
|
||||
{ ptr->handleConnect(error, it); }
|
||||
|
||||
private:
|
||||
bool mClientConnect; // In process of connecting as client.
|
||||
@@ -47,7 +52,12 @@ private:
|
||||
boost::asio::deadline_timer mVerifyTimer;
|
||||
|
||||
void handleStart(const boost::system::error_code& ecResult);
|
||||
static void sHandleStart(Peer::pointer ptr, const boost::system::error_code& ecResult)
|
||||
{ ptr->handleStart(ecResult); }
|
||||
|
||||
void handleVerifyTimer(const boost::system::error_code& ecResult);
|
||||
static void sHandleVerifyTimer(Peer::pointer ptr, const boost::system::error_code& ecResult)
|
||||
{ ptr->handleVerifyTimer(ecResult); }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -60,10 +70,21 @@ protected:
|
||||
Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx);
|
||||
|
||||
void handleShutdown(const boost::system::error_code& error) { ; }
|
||||
static void sHandleShutdown(Peer::pointer ptr, const boost::system::error_code& error)
|
||||
{ ptr->handleShutdown(error); }
|
||||
|
||||
void handle_write(const boost::system::error_code& error, size_t bytes_transferred);
|
||||
static void sHandle_write(Peer::pointer ptr, const boost::system::error_code& error, size_t bytes_transferred)
|
||||
{ ptr->handle_write(error, bytes_transferred); }
|
||||
|
||||
void handle_read_header(const boost::system::error_code& error);
|
||||
static void sHandle_read_header(Peer::pointer ptr, const boost::system::error_code& error)
|
||||
{ ptr->handle_read_header(error); }
|
||||
|
||||
void handle_read_body(const boost::system::error_code& error);
|
||||
static void sHandle_read_body(Peer::pointer ptr, const boost::system::error_code& error)
|
||||
{ ptr->handle_read_body(error); }
|
||||
|
||||
void processReadBuffer();
|
||||
void start_read_header();
|
||||
void start_read_body(unsigned msg_len);
|
||||
@@ -97,7 +118,6 @@ protected:
|
||||
void getSessionCookie(std::string& strDst);
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<Peer> pointer;
|
||||
|
||||
//bool operator == (const Peer& other);
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ Json::Value RPCServer::RPCError(int iError)
|
||||
{ rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." },
|
||||
{ rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." },
|
||||
{ rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." },
|
||||
{ rpcMUST_SEND_XNS, "mustSendXns", "Can only send XNS to accounts which are not created." },
|
||||
{ rpcNICKNAME_MALFORMED,"nicknameMalformed","Nickname is malformed." },
|
||||
{ rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." },
|
||||
{ rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." },
|
||||
@@ -100,7 +99,7 @@ void RPCServer::connected()
|
||||
else mRole=GUEST;
|
||||
|
||||
mSocket.async_read_some(boost::asio::buffer(mReadBuffer),
|
||||
boost::bind(&RPCServer::handle_read, shared_from_this(),
|
||||
boost::bind(&RPCServer::Shandle_read, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
@@ -127,7 +126,7 @@ void RPCServer::handle_read(const boost::system::error_code& e,
|
||||
else
|
||||
{ // not done keep reading
|
||||
mSocket.async_read_some(boost::asio::buffer(mReadBuffer),
|
||||
boost::bind(&RPCServer::handle_read, shared_from_this(),
|
||||
boost::bind(&RPCServer::Shandle_read, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
@@ -301,15 +300,27 @@ Json::Value RPCServer::authorize(const uint256& uLedger,
|
||||
|
||||
// Find the index of the account from the master generator, so we can generate the public and private keys.
|
||||
NewcoinAddress naMasterAccountPublic;
|
||||
unsigned int iIndex = -1; // Compensate for initial increment.
|
||||
unsigned int iIndex = 0; // Compensate for initial increment.
|
||||
bool bFound = false;
|
||||
|
||||
// XXX Stop after Config.account_probe_max
|
||||
// Don't look at ledger entries to determine if the account exists. Don't want to leak to thin server that these accounts are
|
||||
// related.
|
||||
do {
|
||||
++iIndex;
|
||||
while (!bFound && iIndex != theConfig.ACCOUNT_PROBE_MAX)
|
||||
{
|
||||
naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex);
|
||||
} while (naSrcAccountID.getAccountID() != naMasterAccountPublic.getAccountID());
|
||||
|
||||
Log(lsINFO) << "authorize: " << iIndex << " : " << naMasterAccountPublic.humanAccountID() << " : " << naSrcAccountID.humanAccountID();
|
||||
|
||||
bFound = naSrcAccountID.getAccountID() == naMasterAccountPublic.getAccountID();
|
||||
if (!bFound)
|
||||
++iIndex;
|
||||
}
|
||||
|
||||
if (!bFound)
|
||||
{
|
||||
return RPCError(rpcACT_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Use the regular generator to determine the associated public and private keys.
|
||||
NewcoinAddress naGenerator = NewcoinAddress::createGeneratorPublic(naRegularSeed);
|
||||
@@ -319,9 +330,9 @@ Json::Value RPCServer::authorize(const uint256& uLedger,
|
||||
|
||||
if (asSrc->bHaveAuthorizedKey() && (asSrc->getAuthorizedKey().getAccountID() != naAccountPublic.getAccountID()))
|
||||
{
|
||||
std::cerr << "iIndex: " << iIndex << std::endl;
|
||||
std::cerr << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey().getAccountID()) << std::endl;
|
||||
std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl;
|
||||
// std::cerr << "iIndex: " << iIndex << std::endl;
|
||||
// std::cerr << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey().getAccountID()) << std::endl;
|
||||
// std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl;
|
||||
|
||||
return RPCError(rpcPASSWD_CHANGED);
|
||||
}
|
||||
@@ -330,6 +341,8 @@ Json::Value RPCServer::authorize(const uint256& uLedger,
|
||||
|
||||
if (saSrcBalance < saFee)
|
||||
{
|
||||
Log(lsINFO) << "authorize: Insufficent funds for fees: fee=" << saFee.getText() << " balance=" << saSrcBalance.getText();
|
||||
|
||||
return RPCError(rpcINSUF_FUNDS);
|
||||
}
|
||||
else
|
||||
@@ -1177,15 +1190,33 @@ Json::Value RPCServer::doSend(const Json::Value& params)
|
||||
if (params.size() < 6)
|
||||
saSrcAmount = saDstAmount;
|
||||
|
||||
if (saSrcBalance < saDstAmount)
|
||||
// Do a few simple checks.
|
||||
if (!saSrcAmount.isNative())
|
||||
{
|
||||
Log(lsINFO) << "doSend: Ripple";
|
||||
|
||||
nothing();
|
||||
}
|
||||
else if (!saSrcBalance.isPositive())
|
||||
{
|
||||
// No native currency to send.
|
||||
Log(lsINFO) << "doSend: No native currency to send: " << saSrcBalance.getText();
|
||||
|
||||
return RPCError(rpcINSUF_FUNDS);
|
||||
}
|
||||
else if (saDstAmount.isNative() && saSrcAmount < saDstAmount)
|
||||
{
|
||||
// Not enough native currency.
|
||||
|
||||
Log(lsINFO) << "doSend: Insufficent funds: src=" << saSrcAmount.getText() << " dst=" << saDstAmount.getText();
|
||||
|
||||
return RPCError(rpcINSUF_FUNDS);
|
||||
}
|
||||
|
||||
Transaction::pointer trans;
|
||||
|
||||
if (asDst) {
|
||||
// Ordinary send.
|
||||
// Destination exists, ordinary send.
|
||||
|
||||
STPathSet spPaths;
|
||||
|
||||
@@ -1200,13 +1231,9 @@ Json::Value RPCServer::doSend(const Json::Value& params)
|
||||
saSrcAmount,
|
||||
spPaths);
|
||||
}
|
||||
else if (!saDstAmount.isNative())
|
||||
{
|
||||
return RPCError(rpcMUST_SEND_XNS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create and send.
|
||||
// Create destination and send.
|
||||
|
||||
trans = Transaction::sharedCreate(
|
||||
naAccountPublic, naAccountPrivate,
|
||||
@@ -1215,7 +1242,7 @@ Json::Value RPCServer::doSend(const Json::Value& params)
|
||||
saFee,
|
||||
0, // YYY No source tag
|
||||
naDstAccountID,
|
||||
saDstAmount); // Initial funds in XNC.
|
||||
saDstAmount); // Initial funds in XNS.
|
||||
}
|
||||
|
||||
(void) mNetOps->processTransaction(trans);
|
||||
@@ -2070,7 +2097,7 @@ void RPCServer::sendReply()
|
||||
{
|
||||
//std::cout << "RPC reply: " << mReplyStr << std::endl;
|
||||
boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr),
|
||||
boost::bind(&RPCServer::handle_write, shared_from_this(),
|
||||
boost::bind(&RPCServer::Shandle_write, shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
@@ -2099,7 +2126,7 @@ void RPCServer::handle_write(const boost::system::error_code& e)
|
||||
mIncomingRequest.headers.clear();
|
||||
mRequestParser.reset();
|
||||
mSocket.async_read_some(boost::asio::buffer(mReadBuffer),
|
||||
boost::bind(&RPCServer::handle_read, shared_from_this(),
|
||||
boost::bind(&RPCServer::Shandle_read, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ public:
|
||||
rpcACT_NOT_FOUND,
|
||||
rpcINSUF_FUNDS,
|
||||
rpcLGR_NOT_FOUND,
|
||||
rpcMUST_SEND_XNS,
|
||||
rpcNICKNAME_MISSING,
|
||||
rpcNO_ACCOUNT,
|
||||
rpcPASSWD_CHANGED,
|
||||
@@ -71,6 +70,8 @@ public:
|
||||
|
||||
Json::Value RPCError(int iError);
|
||||
|
||||
typedef boost::shared_ptr<RPCServer> pointer;
|
||||
|
||||
private:
|
||||
typedef Json::Value (RPCServer::*doFuncPtr)(const Json::Value ¶ms);
|
||||
enum {
|
||||
@@ -96,9 +97,13 @@ private:
|
||||
RPCServer(const RPCServer&); // no implementation
|
||||
RPCServer& operator=(const RPCServer&); // no implementation
|
||||
|
||||
void handle_write(const boost::system::error_code& error);
|
||||
void handle_write(const boost::system::error_code& ec);
|
||||
static void Shandle_write(pointer This, const boost::system::error_code& ec)
|
||||
{ This->handle_write(ec); }
|
||||
|
||||
void handle_read(const boost::system::error_code& e, std::size_t bytes_transferred);
|
||||
void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred);
|
||||
static void Shandle_read(pointer This, const boost::system::error_code& ec, std::size_t bytes_transferred)
|
||||
{ This->handle_read(ec, bytes_transferred); }
|
||||
|
||||
std::string handleRequest(const std::string& requestStr);
|
||||
void sendReply();
|
||||
@@ -166,8 +171,6 @@ private:
|
||||
Json::Value doLogin(const Json::Value& params);
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<RPCServer> pointer;
|
||||
|
||||
static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps)
|
||||
{
|
||||
return pointer(new RPCServer(io_service, mNetOps));
|
||||
|
||||
@@ -15,9 +15,7 @@ RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) :
|
||||
|
||||
mBalance = mLedgerEntry->getIValueFieldAmount(sfBalance);
|
||||
|
||||
// YYY Should never fail.
|
||||
if (mLowID.isValid() && mHighID.isValid())
|
||||
mValid = true;
|
||||
mValid = true;
|
||||
}
|
||||
|
||||
void RippleState::setViewAccount(const NewcoinAddress& naView)
|
||||
@@ -27,7 +25,7 @@ void RippleState::setViewAccount(const NewcoinAddress& naView)
|
||||
if (bViewLowestNew != mViewLowest)
|
||||
{
|
||||
mViewLowest = bViewLowestNew;
|
||||
mBalance.changeSign();
|
||||
mBalance.negate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name)
|
||||
switch(s.get8())
|
||||
{
|
||||
case STPathElement::typeEnd:
|
||||
if(path.empty())
|
||||
if (path.empty())
|
||||
{
|
||||
if (!paths.empty())
|
||||
throw std::runtime_error("empty last path");
|
||||
@@ -335,16 +335,17 @@ int STPathSet::getLength() const
|
||||
Json::Value STPath::getJson(int) const
|
||||
{
|
||||
Json::Value ret(Json::arrayValue);
|
||||
for (std::vector<STPathElement>::const_iterator it = mPath.begin(), end = mPath.end(); it != end; ++it)
|
||||
|
||||
BOOST_FOREACH(std::vector<STPathElement>::const_iterator::value_type it, mPath)
|
||||
{
|
||||
switch (it->getNodeType())
|
||||
switch (it.getNodeType())
|
||||
{
|
||||
case STPathElement::typeAccount:
|
||||
{
|
||||
Json::Value elem(Json::objectValue);
|
||||
NewcoinAddress account;
|
||||
account.setAccountID(it->getNode());
|
||||
elem["account"] = account.humanAccountID();
|
||||
|
||||
elem["account"] = NewcoinAddress::createHumanAccountID(it.getNode());
|
||||
|
||||
ret.append(elem);
|
||||
break;
|
||||
}
|
||||
@@ -352,7 +353,9 @@ Json::Value STPath::getJson(int) const
|
||||
case STPathElement::typeOffer:
|
||||
{
|
||||
Json::Value elem(Json::objectValue);
|
||||
elem["offer"] = it->getNode().GetHex();
|
||||
|
||||
elem["offer"] = it.getNode().GetHex();
|
||||
|
||||
ret.append(elem);
|
||||
break;
|
||||
}
|
||||
@@ -360,14 +363,17 @@ Json::Value STPath::getJson(int) const
|
||||
default: throw std::runtime_error("Unknown path element");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value STPathSet::getJson(int options) const
|
||||
{
|
||||
Json::Value ret(Json::arrayValue);
|
||||
for (std::vector<STPath>::const_iterator it = value.begin(), end = value.end(); it!=end; ++it)
|
||||
ret.append(it->getJson(options));
|
||||
|
||||
BOOST_FOREACH(std::vector<STPath>::const_iterator::value_type it, value)
|
||||
ret.append(it.getJson(options));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -375,22 +381,22 @@ std::string STPath::getText() const
|
||||
{
|
||||
std::string ret("[");
|
||||
bool first = true;
|
||||
for (std::vector<STPathElement>::const_iterator it = mPath.begin(), end = mPath.end(); it != end; ++it)
|
||||
|
||||
BOOST_FOREACH(std::vector<STPathElement>::const_iterator::value_type it, mPath)
|
||||
{
|
||||
if (!first) ret += ", ";
|
||||
switch (it->getNodeType())
|
||||
switch (it.getNodeType())
|
||||
{
|
||||
case STPathElement::typeAccount:
|
||||
{
|
||||
NewcoinAddress account;
|
||||
account.setAccountID(it->getNode());
|
||||
ret += account.humanAccountID();
|
||||
ret += NewcoinAddress::createHumanAccountID(it.getNode());
|
||||
break;
|
||||
}
|
||||
|
||||
case STPathElement::typeOffer:
|
||||
{
|
||||
ret += "Offer(";
|
||||
ret += it->getNode().GetHex();
|
||||
ret += it.getNode().GetHex();
|
||||
ret += ")";
|
||||
break;
|
||||
}
|
||||
@@ -399,6 +405,7 @@ std::string STPath::getText() const
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
return ret + "]";
|
||||
}
|
||||
|
||||
@@ -406,14 +413,15 @@ std::string STPathSet::getText() const
|
||||
{
|
||||
std::string ret("{");
|
||||
bool firstPath = true;
|
||||
for (std::vector<STPath>::const_iterator it = value.begin(), end = value.end(); it != end; ++it)
|
||||
|
||||
BOOST_FOREACH(std::vector<STPath>::const_iterator::value_type it, value)
|
||||
{
|
||||
if (!firstPath)
|
||||
{
|
||||
ret += ", ";
|
||||
firstPath = false;
|
||||
}
|
||||
ret += it->getText();
|
||||
ret += it.getText();
|
||||
}
|
||||
return ret + "}";
|
||||
}
|
||||
@@ -421,14 +429,16 @@ std::string STPathSet::getText() const
|
||||
void STPathSet::add(Serializer& s) const
|
||||
{
|
||||
bool firstPath = true;
|
||||
for (std::vector<STPath>::const_iterator pit = value.begin(), pend = value.end(); pit != pend; ++pit)
|
||||
|
||||
BOOST_FOREACH(std::vector<STPath>::const_iterator::value_type pit, value)
|
||||
{
|
||||
if (!firstPath)
|
||||
{
|
||||
s.add8(STPathElement::typeBoundary);
|
||||
firstPath = false;
|
||||
}
|
||||
for (std::vector<STPathElement>::const_iterator eit = pit->begin(), eend = pit->end(); eit != eend; ++eit)
|
||||
|
||||
for (std::vector<STPathElement>::const_iterator eit = pit.begin(), eend = pit.end(); eit != eend; ++eit)
|
||||
{
|
||||
s.add8(eit->getNodeType());
|
||||
s.add160(eit->getNode());
|
||||
|
||||
@@ -206,10 +206,12 @@ class STAmount : public SerializedType
|
||||
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
|
||||
|
||||
protected:
|
||||
uint160 mCurrency;
|
||||
uint64 mValue;
|
||||
int mOffset;
|
||||
bool mIsNative, mIsNegative;
|
||||
uint160 mCurrency;
|
||||
|
||||
uint64 mValue;
|
||||
int mOffset;
|
||||
bool mIsNative; // True for native stamps, ripple stamps are not native.
|
||||
bool mIsNegative;
|
||||
|
||||
void canonicalize();
|
||||
STAmount* duplicate() const { return new STAmount(*this); }
|
||||
@@ -277,7 +279,7 @@ public:
|
||||
bool isGEZero() const { return !mIsNegative; }
|
||||
operator bool() const { return !isZero(); }
|
||||
|
||||
void changeSign() { if (!isZero()) mIsNegative = !mIsNegative; }
|
||||
void negate() { if (!isZero()) mIsNegative = !mIsNegative; }
|
||||
void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; mIsNegative = false; }
|
||||
|
||||
const uint160& getCurrency() const { return mCurrency; }
|
||||
@@ -504,6 +506,8 @@ public:
|
||||
int getNodeType() const { return mType; }
|
||||
bool isAccount() const { return mType == typeAccount; }
|
||||
bool isOffer() const { return mType == typeOffer; }
|
||||
|
||||
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a class of offers.
|
||||
const uint160& getNode() const { return mNode; }
|
||||
|
||||
void setType(int type) { mType = type; }
|
||||
|
||||
@@ -24,49 +24,51 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std
|
||||
const char* cpToken;
|
||||
const char* cpHuman;
|
||||
} transResultInfoA[] = {
|
||||
{ tenGEN_IN_USE, "tenGEN_IN_USE", "Generator already in use." },
|
||||
{ tenCREATEXNS, "tenCREATEXNS", "Can not specify non XNS for Create." },
|
||||
{ tenEXPLICITXNS, "tenEXPLICITXNS", "XNS is used by default, don't specify it." },
|
||||
{ tenDST_NEEDED, "tenDST_NEEDED", "Destination not specified." },
|
||||
{ tenDST_IS_SRC, "tenDST_IS_SRC", "Destination may not be source." },
|
||||
{ tenBAD_GEN_AUTH, "tenBAD_GEN_AUTH", "Not authorized to claim generator." },
|
||||
{ tenBAD_ADD_AUTH, "tenBAD_ADD_AUTH", "Not authorized to add account." },
|
||||
{ tenBAD_CLAIM_ID, "tenBAD_CLAIM_ID", "Malformed." },
|
||||
{ tenBAD_SET_ID, "tenBAD_SET_ID", "Malformed." },
|
||||
{ tenDIRECT_XNS_ONLY, "tenDIRECT_XNS_ONLY", "Direct payments are non-ripple XNS only." },
|
||||
{ tenRIPPLE_EMPTY, "tenRIPPLE_EMPTY", "PathSet with no paths." },
|
||||
{ tenCLAIMED, "tenCLAIMED", "Can not claim a previously claimed account." },
|
||||
{ tenCREATED, "tenCREATED", "Can't add an already created account." },
|
||||
{ tenMSG_SET, "tenMSG_SET", "Can't change a message key." },
|
||||
{ tenBAD_ADD_AUTH, "tenBAD_ADD_AUTH", "Not authorized to add account." },
|
||||
{ tenBAD_AMOUNT, "tenBAD_AMOUNT", "Can only send positive amounts." },
|
||||
{ tenBAD_AUTH_MASTER, "tenBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." },
|
||||
{ tenBAD_RIPPLE, "tenBAD_RIPPLE", "Ledger prevents ripple from succeeding." },
|
||||
{ terALREADY, "terALREADY", "The exact transaction was already in this ledger" },
|
||||
{ tenFAILED, "tenFAILED", "Something broke horribly" },
|
||||
{ tenBAD_CLAIM_ID, "tenBAD_CLAIM_ID", "Malformed." },
|
||||
{ tenBAD_GEN_AUTH, "tenBAD_GEN_AUTH", "Not authorized to claim generator." },
|
||||
{ tenBAD_RIPPLE, "tenBAD_RIPPLE", "Ledger prevents ripple from succeeding." },
|
||||
{ tenBAD_SET_ID, "tenBAD_SET_ID", "Malformed." },
|
||||
{ tenCLAIMED, "tenCLAIMED", "Can not claim a previously claimed account." },
|
||||
{ tenCREATED, "tenCREATED", "Can't add an already created account." },
|
||||
{ tenCREATEXNS, "tenCREATEXNS", "Can not specify non XNS for Create." },
|
||||
{ tenDST_IS_SRC, "tenDST_IS_SRC", "Destination may not be source." },
|
||||
{ tenDST_NEEDED, "tenDST_NEEDED", "Destination not specified." },
|
||||
{ tenEXPLICITXNS, "tenEXPLICITXNS", "XNS is used by default, don't specify it." },
|
||||
{ tenFAILED, "tenFAILED", "Something broke horribly" },
|
||||
{ tenGEN_IN_USE, "tenGEN_IN_USE", "Generator already in use." },
|
||||
{ tenINSUF_FEE_P, "tenINSUF_FEE_P", "fee totally insufficient" },
|
||||
{ tenINVALID, "tenINVALID", "The transaction is ill-formed" },
|
||||
{ tenMSG_SET, "tenMSG_SET", "Can't change a message key." },
|
||||
{ tenREDUNDANT, "tenREDUNDANT", "Sends same currency to self." },
|
||||
{ tenRIPPLE_EMPTY, "tenRIPPLE_EMPTY", "PathSet with no paths." },
|
||||
{ tenUNKNOWN, "tenUNKNOWN", "The transactions requires logic not implemented yet" },
|
||||
{ tenINSUF_FEE_P, "tenINSUF_FEE_P", "fee totally insufficient" },
|
||||
{ tenINVALID, "tenINVALID", "The transaction is ill-formed" },
|
||||
{ terSUCCESS, "terSUCCESS", "The transaction was applied" },
|
||||
{ terALREADY, "terALREADY", "The exact transaction was already in this ledger" },
|
||||
{ terBAD_AUTH, "terBAD_AUTH", "Transaction's public key is not authorized." },
|
||||
{ terBAD_RIPPLE, "terBAD_RIPPLE", "No ripple path can be satisfied." },
|
||||
{ terBAD_SEQ, "terBAD_SEQ", "This sequence number should be zero for prepaid transactions." },
|
||||
{ terCREATED, "terCREATED", "Can not create a previously created account." },
|
||||
{ terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." },
|
||||
{ terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee" },
|
||||
{ terINSUF_FEE_T, "terINSUF_FEE_T", "fee insufficient now (account doesn't exist, network load)" },
|
||||
{ terNODE_NOT_FOUND, "terNODE_NOT_FOUND", "Can not delete a dir node." },
|
||||
{ terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "?"},
|
||||
{ terNODE_NO_ROOT, "terNODE_NO_ROOT", "?"},
|
||||
{ terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist" },
|
||||
{ terNO_DST, "terNO_DST", "The destination does not exist" },
|
||||
{ terNO_PATH, "terNO_PATH", "No path existed or met transaction/balance requirements" },
|
||||
{ terPAST_LEDGER, "terPAST_LEDGER", "The transaction expired and can't be applied" },
|
||||
{ terPAST_SEQ, "terPAST_SEQ", "This sequence number has already past" },
|
||||
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction" },
|
||||
{ terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." },
|
||||
{ terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." },
|
||||
{ terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." },
|
||||
{ terCREATED, "terCREATED", "Can not create a previously created account." },
|
||||
{ terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." },
|
||||
{ terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." },
|
||||
{ terUNCLAIMED, "terUNCLAIMED", "Can not use an unclaimed account." },
|
||||
{ terBAD_AUTH, "terBAD_AUTH", "Transaction's public key is not authorized." },
|
||||
{ terBAD_RIPPLE, "terBAD_RIPPLE", "No ripple path can be satisfied." },
|
||||
{ terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee" },
|
||||
{ terINSUF_FEE_T, "terINSUF_FEE_T", "fee insufficient now (account doesn't exist, network load)" },
|
||||
{ terNODE_NOT_FOUND, "terNODE_NOT_FOUND", "Can not delete a dir node." },
|
||||
{ terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "?" },
|
||||
{ terNODE_NO_ROOT, "terNODE_NO_ROOT", "?" },
|
||||
{ terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist" },
|
||||
{ terNO_DST, "terNO_DST", "The destination does not exist" },
|
||||
{ terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." },
|
||||
{ terNO_PATH, "terNO_PATH", "No path existed or met transaction/balance requirements" },
|
||||
{ terOVER_LIMIT, "terOVER_LIMIT", "Over limit." },
|
||||
{ terPAST_LEDGER, "terPAST_LEDGER", "The transaction expired and can't be applied" },
|
||||
{ terPAST_SEQ, "terPAST_SEQ", "This sequence number has already past" },
|
||||
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction" },
|
||||
{ terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." },
|
||||
{ terSUCCESS, "terSUCCESS", "The transaction was applied" },
|
||||
{ terUNCLAIMED, "terUNCLAIMED", "Can not use an unclaimed account." },
|
||||
{ terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." },
|
||||
};
|
||||
|
||||
int iIndex = NUMBER(transResultInfoA);
|
||||
@@ -82,7 +84,11 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std
|
||||
|
||||
return iIndex >= 0;
|
||||
}
|
||||
// We return the uNodeDir so that on delete we can quickly know where the element is mentioned in the directory.
|
||||
|
||||
// <-> accounts: Affected accounts for the transaction.
|
||||
// <-- uNodeDir: For deletion, present to make dirDelete efficient.
|
||||
// --> uBase: The index of the base of the directory. Nodes are based off of this.
|
||||
// --> uLedgerIndex: Value to add to directory.
|
||||
TransactionEngineResult TransactionEngine::dirAdd(
|
||||
std::vector<AffectedAccount>& accounts,
|
||||
uint64& uNodeDir,
|
||||
@@ -108,7 +114,6 @@ TransactionEngineResult TransactionEngine::dirAdd(
|
||||
|
||||
sleRoot = boost::make_shared<SerializedLedgerEntry>(ltDIR_ROOT);
|
||||
|
||||
|
||||
sleRoot->setIndex(uRootIndex);
|
||||
Log(lsTRACE) << "dirAdd: Creating dir index: " << sleRoot->getIndex().ToString();
|
||||
|
||||
@@ -180,6 +185,10 @@ TransactionEngineResult TransactionEngine::dirAdd(
|
||||
return terSUCCESS;
|
||||
}
|
||||
|
||||
// <-> accounts: Affected accounts for the transaction.
|
||||
// --> uNodeDir: Node containing entry.
|
||||
// --> uBase: The index of the base of the directory. Nodes are based off of this.
|
||||
// --> uLedgerIndex: Value to add to directory.
|
||||
TransactionEngineResult TransactionEngine::dirDelete(
|
||||
std::vector<AffectedAccount>& accounts,
|
||||
const uint64& uNodeDir,
|
||||
@@ -880,20 +889,21 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
||||
const uint160& uSrcAccountID)
|
||||
{
|
||||
TransactionEngineResult terResult = terSUCCESS;
|
||||
std::cerr << "doCreditSet>" << std::endl;
|
||||
Log(lsINFO) << "doCreditSet>";
|
||||
|
||||
// Check if destination makes sense.
|
||||
uint160 uDstAccountID = txn.getITFieldAccount(sfDestination);
|
||||
|
||||
if (!uDstAccountID)
|
||||
{
|
||||
std::cerr << "doCreditSet: Invalid transaction: Payment destination account not specifed." << std::endl;
|
||||
Log(lsINFO) << "doCreditSet: Invalid transaction: Destination account not specifed.";
|
||||
|
||||
return tenDST_NEEDED;
|
||||
}
|
||||
// XXX Might make sense for ripple.
|
||||
else if (uSrcAccountID == uDstAccountID)
|
||||
{
|
||||
std::cerr << "doCreditSet: Invalid transaction: Source account is the same as destination." << std::endl;
|
||||
Log(lsINFO) << "doCreditSet: Invalid transaction: Can not extend credit to self.";
|
||||
|
||||
return tenDST_IS_SRC;
|
||||
}
|
||||
|
||||
@@ -901,7 +911,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
||||
SLE::pointer sleDst = mLedger->getAccountRoot(qry, uDstAccountID);
|
||||
if (!sleDst)
|
||||
{
|
||||
std::cerr << "doCreditSet: Delay transaction: Destination account does not exist." << std::endl;
|
||||
Log(lsINFO) << "doCreditSet: Delay transaction: Destination account does not exist.";
|
||||
|
||||
return terNO_DST;
|
||||
}
|
||||
@@ -911,41 +921,69 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
||||
bool bSltD = uSrcAccountID < uDstAccountID;
|
||||
uint32 uFlags = bSltD ? lsfLowIndexed : lsfHighIndexed;
|
||||
STAmount saBalance(uCurrency);
|
||||
bool bAddIndex;
|
||||
bool bAddIndex = false;
|
||||
bool bDelIndex = false;
|
||||
|
||||
qry = lepNONE;
|
||||
SLE::pointer sleRippleState = mLedger->getRippleState(qry, uSrcAccountID, uDstAccountID, uCurrency);
|
||||
if (sleRippleState)
|
||||
{
|
||||
bAddIndex = !(sleRippleState->getFlags() & uFlags);
|
||||
// A line exists in one or more directions.
|
||||
#if 0
|
||||
if (saLimitAmount.isZero())
|
||||
{
|
||||
// Zeroing line.
|
||||
uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID();
|
||||
uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID();
|
||||
bool bLow = uLowID == uSrcAccountID;
|
||||
bool bHigh = uLowID == uDstAccountID;
|
||||
bool bBalanceZero = sleRippleState->getIValueFieldAmount(sfBalance).isZero();
|
||||
STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit);
|
||||
bool bDstLimitZero = saDstLimit.isZero();
|
||||
|
||||
std::cerr << "doCreditSet: Modifying ripple line: bAddIndex=" << bAddIndex << std::endl;
|
||||
assert(bLow || bHigh);
|
||||
|
||||
sleRippleState->setIFieldAmount(bSltD ? sfLowLimit : sfHighLimit, saLimitAmount);
|
||||
if (bBalanceZero && bDstLimitZero)
|
||||
{
|
||||
// Zero balance and eliminating last limit.
|
||||
|
||||
if (bAddIndex)
|
||||
sleRippleState->setFlag(uFlags);
|
||||
bDelIndex = true;
|
||||
terResult = dirDelete(accounts, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!bDelIndex)
|
||||
{
|
||||
bAddIndex = !(sleRippleState->getFlags() & uFlags);
|
||||
|
||||
accounts.push_back(std::make_pair(taaMODIFY, sleRippleState));
|
||||
sleRippleState->setIFieldAmount(bSltD ? sfLowLimit : sfHighLimit, saLimitAmount);
|
||||
|
||||
if (bAddIndex)
|
||||
sleRippleState->setFlag(uFlags);
|
||||
|
||||
accounts.push_back(std::make_pair(taaMODIFY, sleRippleState));
|
||||
}
|
||||
|
||||
Log(lsINFO) << "doCreditSet: Modifying ripple line: bAddIndex=" << bAddIndex << " bDelIndex=" << bDelIndex;
|
||||
}
|
||||
// Line does not exist.
|
||||
else if (saLimitAmount.isZero())
|
||||
{
|
||||
std::cerr << "doCreditSet: Setting non-existant ripple line to 0." << std::endl;
|
||||
Log(lsINFO) << "doCreditSet: Redundant: Setting non-existant ripple line to 0.";
|
||||
|
||||
return terNO_LINE_NO_ZERO;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new ripple line.
|
||||
STAmount saZero(uCurrency);
|
||||
|
||||
bAddIndex = true;
|
||||
sleRippleState = boost::make_shared<SerializedLedgerEntry>(ltRIPPLE_STATE);
|
||||
|
||||
sleRippleState->setIndex(Ledger::getRippleStateIndex(uSrcAccountID, uDstAccountID, uCurrency));
|
||||
std::cerr << "doCreditSet: Creating ripple line: "
|
||||
<< sleRippleState->getIndex().ToString()
|
||||
<< std::endl;
|
||||
Log(lsINFO) << "doCreditSet: Creating ripple line: "
|
||||
<< sleRippleState->getIndex().ToString();
|
||||
|
||||
sleRippleState->setFlag(uFlags);
|
||||
sleRippleState->setIFieldAmount(sfBalance, saZero); // Zero balance in currency.
|
||||
@@ -959,17 +997,13 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
||||
|
||||
if (bAddIndex)
|
||||
{
|
||||
// Add entries so clients can find lines.
|
||||
// - Client needs to be able to walk who account has given credit to and who has account's credit.
|
||||
// - Client doesn't need to know every account who has extended credit but it owed nothing.
|
||||
uint64 uSrcRef; // Ignored, ripple_state dirs never delete.
|
||||
|
||||
// XXX Verify extend is passing the right bits, not the zero bits.
|
||||
// XXX Make dirAdd more flexiable to take vector.
|
||||
terResult = dirAdd(accounts, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex());
|
||||
}
|
||||
|
||||
std::cerr << "doCreditSet<" << std::endl;
|
||||
Log(lsINFO) << "doCreditSet<";
|
||||
|
||||
return terResult;
|
||||
}
|
||||
@@ -1083,47 +1117,61 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac
|
||||
return result;
|
||||
}
|
||||
|
||||
// XXX Need to audit for things like setting accountID not having memory.
|
||||
TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn,
|
||||
std::vector<AffectedAccount>& accounts,
|
||||
const uint160& uSrcAccountID)
|
||||
{
|
||||
// Ripple if source or destination is non-native or if there are paths.
|
||||
uint32 txFlags = txn.getFlags();
|
||||
uint160 uDstAccountID = txn.getITFieldAccount(sfDestination);
|
||||
// XXX Could also be ripple if direct credit lines.
|
||||
bool bRipple = txn.getITFieldPresent(sfPaths);
|
||||
bool bCreate = !!(txFlags & tfCreateAccount);
|
||||
STAmount saAmount = txn.getITFieldAmount(sfAmount);
|
||||
STAmount saSrcBalance = accounts[0].second->getIValueFieldAmount(sfBalance);
|
||||
bool bNoRippleDirect = !!(txFlags & tfNoRippleDirect);
|
||||
bool bPaths = txn.getITFieldPresent(sfPaths);
|
||||
bool bMax = txn.getITFieldPresent(sfSendMax);
|
||||
uint160 uDstAccountID = txn.getITFieldAccount(sfDestination);
|
||||
STAmount saDstAmount = txn.getITFieldAmount(sfAmount);
|
||||
STAmount saMaxAmount = bMax ? txn.getITFieldAmount(sfSendMax) : saDstAmount;
|
||||
uint160 uSrcCurrency = saMaxAmount.getCurrency();
|
||||
uint160 uDstCurrency = saDstAmount.getCurrency();
|
||||
|
||||
if (!uDstAccountID)
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: Payment destination account not specifed." << std::endl;
|
||||
return tenINVALID;
|
||||
}
|
||||
// XXX Only bad if no currency conversion in between through other people's offer.
|
||||
else if (uSrcAccountID == uDstAccountID)
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: Source account is the same as destination." << std::endl;
|
||||
return tenINVALID;
|
||||
}
|
||||
Log(lsINFO) << "doPayment: Invalid transaction: Payment destination account not specifed.";
|
||||
|
||||
// XXX Allow ripple to create.
|
||||
return tenDST_NEEDED;
|
||||
}
|
||||
else if (!saDstAmount.isPositive())
|
||||
{
|
||||
Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getCurrencyHuman() << " " << saDstAmount.getText();
|
||||
|
||||
return tenBAD_AMOUNT;
|
||||
}
|
||||
else if (uSrcAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
|
||||
{
|
||||
Log(lsINFO) << boost::str(boost::format("doPayment: Invalid transaction: Redunant transaction: src=%s, dst=%s, src_cur=%s, dst_cur=%s")
|
||||
% uSrcAccountID.ToString()
|
||||
% uDstAccountID.ToString()
|
||||
% uSrcCurrency.ToString()
|
||||
% uDstCurrency.ToString());
|
||||
|
||||
return tenREDUNDANT;
|
||||
}
|
||||
|
||||
LedgerStateParms qry = lepNONE;
|
||||
SLE::pointer sleDst = mLedger->getAccountRoot(qry, uDstAccountID);
|
||||
if (!sleDst)
|
||||
{
|
||||
// Destination account does not exist.
|
||||
// XXX Also make sure non-ripple dest if creating.
|
||||
if (bCreate && !saAmount.isNative())
|
||||
if (bCreate && !saDstAmount.isNative())
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: Create account may only fund XNS." << std::endl;
|
||||
// This restriction could be relaxed.
|
||||
Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XNS.";
|
||||
|
||||
return tenCREATEXNS;
|
||||
}
|
||||
else if (!bCreate)
|
||||
{
|
||||
std::cerr << "doPayment: Delay transaction: Destination account does not exist." << std::endl;
|
||||
Log(lsINFO) << "doPayment: Delay transaction: Destination account does not exist.";
|
||||
|
||||
return terNO_DST;
|
||||
}
|
||||
@@ -1140,7 +1188,8 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
||||
// Destination exists.
|
||||
else if (bCreate)
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: Account already created." << std::endl;
|
||||
// Retryable: if account created this ledger, reordering might allow account to be made by this transaction.
|
||||
Log(lsINFO) << "doPayment: Invalid transaction: Account already created.";
|
||||
|
||||
return terCREATED;
|
||||
}
|
||||
@@ -1149,42 +1198,117 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
||||
accounts.push_back(std::make_pair(taaMODIFY, sleDst));
|
||||
}
|
||||
|
||||
bool bRipple = bPaths || bMax || !saDstAmount.isNative();
|
||||
|
||||
if (!bRipple)
|
||||
{
|
||||
// Direct XNS payment.
|
||||
if (!saAmount.isNative())
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: direct " SYSTEM_CURRENCY_CODE " required." << std::endl;
|
||||
STAmount saSrcXNSBalance = accounts[0].second->getIValueFieldAmount(sfBalance);
|
||||
|
||||
return tenDIRECT_XNS_ONLY;
|
||||
}
|
||||
|
||||
if (saSrcBalance < saAmount)
|
||||
if (saSrcXNSBalance < saDstAmount)
|
||||
{
|
||||
std::cerr << "doPayment: Delay transaction: Insufficent funds." << std::endl;
|
||||
// Transaction might succeed, if applied in a different order.
|
||||
Log(lsINFO) << "doPayment: Delay transaction: Insufficent funds.";
|
||||
|
||||
return terUNFUNDED;
|
||||
}
|
||||
|
||||
accounts[0].second->setIFieldAmount(sfBalance, saSrcBalance - saAmount);
|
||||
accounts[1].second->setIFieldAmount(sfBalance, accounts[1].second->getIValueFieldAmount(sfBalance) + saAmount);
|
||||
accounts[0].second->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount);
|
||||
accounts[1].second->setIFieldAmount(sfBalance, accounts[1].second->getIValueFieldAmount(sfBalance) + saDstAmount);
|
||||
|
||||
return terSUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Try direct ripple first.
|
||||
// Ripple payment
|
||||
//
|
||||
|
||||
uint160 uDstCurrency = saAmount.getCurrency();
|
||||
|
||||
qry = lepNONE;
|
||||
SLE::pointer sleRippleState = mLedger->getRippleState(qry, uSrcAccountID, uDstAccountID, uDstCurrency);
|
||||
|
||||
if (sleRippleState)
|
||||
// Try direct ripple first.
|
||||
if (!bNoRippleDirect && uSrcAccountID != uDstAccountID && uSrcCurrency == uDstCurrency)
|
||||
{
|
||||
// There is a direct relationship.
|
||||
qry = lepNONE;
|
||||
SLE::pointer sleRippleState = mLedger->getRippleState(qry, uSrcAccountID, uDstAccountID, uDstCurrency);
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
// There is a direct credit-line of some direction.
|
||||
// - We can always pay IOUs back.
|
||||
// - We can issue IOUs to the limit.
|
||||
// XXX Not implemented:
|
||||
// - Give preference to pushing out IOUs over sender credit limit.
|
||||
// - Give preference to pushing out IOUs to creating them.
|
||||
// - Create IOUs as last resort.
|
||||
uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID();
|
||||
uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID();
|
||||
bool bSendHigh = uLowID == uSrcAccountID && uHighID == uDstAccountID;
|
||||
bool bSendLow = uLowID == uDstAccountID && uHighID == uSrcAccountID;
|
||||
// Flag we need if we end up owing IOUs.
|
||||
uint32 uFlags = bSendHigh ? lsfLowIndexed : lsfHighIndexed;
|
||||
|
||||
assert(bSendLow || bSendHigh);
|
||||
|
||||
STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit);
|
||||
|
||||
STAmount saDstBalance = sleRippleState->getIValueFieldAmount(sfBalance);
|
||||
if (bSendHigh)
|
||||
{
|
||||
// Put balance in dst terms.
|
||||
saDstBalance.negate();
|
||||
}
|
||||
|
||||
saDstBalance += saDstAmount;
|
||||
if (saDstBalance > saDstLimit)
|
||||
{
|
||||
// Would exceed credit limit.
|
||||
// YYY Note: in the future could push out other credits to make payment fit.
|
||||
|
||||
Log(lsINFO) << "doPayment: Delay transaction: Over limit: proposed balance="
|
||||
<< saDstBalance.getText()
|
||||
<< " limit="
|
||||
<< saDstLimit.getText();
|
||||
|
||||
return terOVER_LIMIT;
|
||||
}
|
||||
|
||||
if (saDstBalance.isZero())
|
||||
{
|
||||
// XXX May be able to delete indexes for credit limits which are zero.
|
||||
nothing();
|
||||
}
|
||||
else if (saDstBalance.isNegative())
|
||||
{
|
||||
// dst still has outstanding IOUs, sle already indexed.
|
||||
nothing();
|
||||
}
|
||||
// src has outstanding IOUs, sle should be indexed.
|
||||
else if (! (sleRippleState->getFlags() & uFlags))
|
||||
{
|
||||
// Need to add index.
|
||||
TransactionEngineResult terResult = terSUCCESS;
|
||||
uint64 uSrcRef; // Ignored, ripple_state dirs never delete.
|
||||
|
||||
terResult = dirAdd(accounts,
|
||||
uSrcRef,
|
||||
Ledger::getRippleDirIndex(uSrcAccountID), // The source ended up owing.
|
||||
sleRippleState->getIndex()); // Adding current entry.
|
||||
|
||||
if (terSUCCESS != terResult)
|
||||
return terResult;
|
||||
|
||||
sleRippleState->setFlag(uFlags); // Note now indexed.
|
||||
}
|
||||
|
||||
if (bSendHigh)
|
||||
{
|
||||
// Put balance in low terms.
|
||||
saDstBalance.negate();
|
||||
}
|
||||
|
||||
sleRippleState->setIFieldAmount(sfBalance, saDstBalance);
|
||||
accounts.push_back(std::make_pair(taaMODIFY, sleRippleState));
|
||||
|
||||
return terSUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
STPathSet spsPaths = txn.getITFieldPathSet(sfPaths);
|
||||
@@ -1192,7 +1316,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
||||
// XXX If we are parsing for determing forwarding check maximum path count.
|
||||
if (!spsPaths.getPathCount())
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: No paths." << std::endl;
|
||||
Log(lsINFO) << "doPayment: Invalid transaction: No paths.";
|
||||
|
||||
return tenRIPPLE_EMPTY;
|
||||
}
|
||||
@@ -1202,13 +1326,13 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
||||
BOOST_FOREACH(std::vector<STPath>& spPath, spsPaths)
|
||||
{
|
||||
|
||||
std::cerr << "doPayment: Implementation error: Not implemented." << std::endl;
|
||||
Log(lsINFO) << "doPayment: Implementation error: Not implemented.";
|
||||
|
||||
return tenUNKNOWN;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::cerr << "doPayment: Delay transaction: No ripple paths could be satisfied." << std::endl;
|
||||
Log(lsINFO) << "doPayment: Delay transaction: No ripple paths could be satisfied.";
|
||||
|
||||
return terBAD_RIPPLE;
|
||||
}
|
||||
|
||||
@@ -10,43 +10,49 @@
|
||||
|
||||
enum TransactionEngineResult
|
||||
{
|
||||
// Note: Numbers are currently unstable. Use tokens.
|
||||
|
||||
// tenCAN_NEVER_SUCCEED = <0
|
||||
|
||||
// Malformed: Fee claimed
|
||||
tenGEN_IN_USE = -300,
|
||||
tenCREATEXNS,
|
||||
tenEXPLICITXNS,
|
||||
tenDST_NEEDED,
|
||||
tenDST_IS_SRC,
|
||||
tenBAD_GEN_AUTH,
|
||||
tenBAD_ADD_AUTH,
|
||||
tenBAD_AMOUNT,
|
||||
tenBAD_CLAIM_ID,
|
||||
tenBAD_GEN_AUTH,
|
||||
tenBAD_SET_ID,
|
||||
tenDIRECT_XNS_ONLY,
|
||||
tenCREATEXNS,
|
||||
tenDST_IS_SRC,
|
||||
tenDST_NEEDED,
|
||||
tenEXPLICITXNS,
|
||||
tenREDUNDANT,
|
||||
tenRIPPLE_EMPTY,
|
||||
|
||||
// Invalid: Ledger won't allow.
|
||||
tenCLAIMED = -200,
|
||||
tenCREATED,
|
||||
tenMSG_SET,
|
||||
tenBAD_AUTH_MASTER,
|
||||
tenBAD_RIPPLE,
|
||||
tenCREATED,
|
||||
tenMSG_SET,
|
||||
terALREADY,
|
||||
|
||||
// Other
|
||||
tenFAILED = -100,
|
||||
tenUNKNOWN,
|
||||
tenINSUF_FEE_P,
|
||||
tenINVALID,
|
||||
tenUNKNOWN,
|
||||
|
||||
terSUCCESS = 0,
|
||||
|
||||
// terFAILED_BUT_COULD_SUCCEED = >0
|
||||
// Conflict with ledger database: Fee claimed
|
||||
// Might succeed if not conflict is not caused by transaction ordering.
|
||||
terBAD_AUTH,
|
||||
terBAD_RIPPLE,
|
||||
terBAD_SEQ,
|
||||
terCREATED,
|
||||
terDIR_FULL,
|
||||
terFUNDS_SPENT,
|
||||
terINSUF_FEE_B,
|
||||
terINSUF_FEE_T,
|
||||
terNODE_NOT_FOUND,
|
||||
@@ -54,17 +60,15 @@ enum TransactionEngineResult
|
||||
terNODE_NO_ROOT,
|
||||
terNO_ACCOUNT,
|
||||
terNO_DST,
|
||||
terNO_LINE_NO_ZERO,
|
||||
terNO_PATH,
|
||||
terOVER_LIMIT,
|
||||
terPAST_LEDGER,
|
||||
terPAST_SEQ,
|
||||
terPRE_SEQ,
|
||||
terUNFUNDED,
|
||||
terNO_LINE_NO_ZERO,
|
||||
terSET_MISSING_DST,
|
||||
terFUNDS_SPENT,
|
||||
terUNCLAIMED,
|
||||
terBAD_AUTH,
|
||||
terBAD_RIPPLE,
|
||||
terUNFUNDED,
|
||||
};
|
||||
|
||||
bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman);
|
||||
|
||||
@@ -37,6 +37,7 @@ const int TransactionMaxLen = 1048576;
|
||||
|
||||
// Transaction flags.
|
||||
const uint32 tfCreateAccount = 0x00010000;
|
||||
const uint32 tfNoRippleDirect = 0x00020000;
|
||||
|
||||
const uint32 tfUnsetEmailHash = 0x00010000;
|
||||
const uint32 tfUnsetWalletLocator = 0x00020000;
|
||||
|
||||
Reference in New Issue
Block a user