Merge branch 'master' into continuousClose

This commit is contained in:
JoelKatz
2012-07-05 17:12:37 -07:00
14 changed files with 398 additions and 192 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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