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

This commit is contained in:
Arthur Britto
2013-03-11 02:58:11 -07:00
14 changed files with 439 additions and 64 deletions

View File

@@ -21,6 +21,7 @@ static const uint64 tenTo17 = tenTo14 * 1000;
#if (ULONG_MAX > UINT_MAX)
#define BN_add_word64(bn, word) BN_add_word(bn, word)
#define BN_sub_word64(bn, word) BN_sub_word(bn, word)
#define BN_mul_word64(bn, word) BN_mul_word(bn, word)
#define BN_div_word64(bn, word) BN_div_word(bn, word)
#else
@@ -1248,25 +1249,6 @@ void STAmount::roundSelf()
}
}
#if 0
std::string STAmount::getExtendedText() const
{
if (mIsNative)
{
return str(boost::format("%s " SYSTEM_CURRENCY_CODE) % getText());
}
else
{
return str(boost::format("%s/%s/%s %dE%d" )
% getText()
% getHumanCurrency()
% RippleAddress::createHumanAccountID(mIssuer)
% getMantissa()
% getExponent());
}
}
#endif
Json::Value STAmount::getJson(int) const
{
Json::Value elem(Json::objectValue);

View File

@@ -0,0 +1,339 @@
#include <boost/test/unit_test.hpp>
#include "SerializedTypes.h"
#include "Log.h"
SETUP_LOG();
#if (ULONG_MAX > UINT_MAX)
#define BN_add_word64(bn, word) BN_add_word(bn, word)
#define BN_sub_word64(bn, word) BN_sub_word(bn, word)
#define BN_mul_word64(bn, word) BN_mul_word(bn, word)
#define BN_div_word64(bn, word) BN_div_word(bn, word)
#else
#include "BigNum64.h"
#endif
static const uint64 tenTo14 = 100000000000000ull;
static const uint64 tenTo14m1 = tenTo14 - 1;
static const uint64 tenTo17 = tenTo14 * 1000;
static const uint64 tenTo17m1 = tenTo17 - 1;
// CAUTION: This is early code and is *NOT* ready for real use yet.
static void canonicalizeRound(bool isNative, uint64& value, int& offset, bool roundUp)
{
if (!roundUp) // canonicalize already rounds down
return;
cLog(lsDEBUG) << "canonicalize< " << value << ":" << offset << (roundUp ? " up" : " down");
if (isNative)
{
if (offset < 0)
{
while (offset < -1)
{
value /= 10;
++offset;
}
value += 10; // add before last divide
value /= 10;
++offset;
}
}
else if (value > STAmount::cMaxValue)
{
while (value > (10 * STAmount::cMaxValue))
{
value /= 10;
++offset;
}
value += 9; // add before last divide
value /= 10;
++offset;
}
cLog(lsDEBUG) << "canonicalize> " << value << ":" << offset << (roundUp ? " up" : " down");
}
STAmount STAmount::addRound(const STAmount& v1, const STAmount& v2, bool roundUp)
{
v1.throwComparable(v2);
if (v2.mValue == 0)
return v1;
if (v1.mValue == 0)
return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, v2.mValue, v2.mOffset, v2.mIsNegative);
if (v1.mIsNative)
return STAmount(v1.getFName(), v1.getSNValue() + v2.getSNValue());
int ov1 = v1.mOffset, ov2 = v2.mOffset;
int64 vv1 = static_cast<int64>(v1.mValue), vv2 = static_cast<uint64>(v2.mValue);
if (v1.mIsNegative)
vv1 = -vv1;
if (v2.mIsNegative)
vv2 = -vv2;
if (ov1 < ov2)
{
while (ov1 < (ov2 - 1))
{
vv1 /= 10;
++ov1;
}
if (roundUp)
vv1 += 9;
vv1 /= 10;
++ov1;
}
if (ov2 < ov1)
{
while (ov2 < (ov1 - 1))
{
vv2 /= 10;
++ov2;
}
if (roundUp)
vv2 += 9;
vv2 /= 10;
++ov2;
}
int64 fv = vv1 + vv2;
if (fv >= 0)
{
uint64 v = static_cast<uint64>(fv);
canonicalizeRound(false, v, ov1, roundUp);
return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, v, ov1, false);
}
else
{
uint64 v = static_cast<uint64>(-fv);
canonicalizeRound(false, v, ov1, !roundUp);
return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, v, ov1, true);
}
}
STAmount STAmount::subRound(const STAmount& v1, const STAmount& v2, bool roundUp)
{
v1.throwComparable(v2);
if (v2.mValue == 0)
return v1;
if (v1.mValue == 0)
return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, v2.mValue, v2.mOffset, !v2.mIsNegative);
if (v1.mIsNative)
return STAmount(v1.getFName(), v1.getSNValue() - v2.getSNValue());
int ov1 = v1.mOffset, ov2 = v2.mOffset;
int64 vv1 = static_cast<int64>(v1.mValue), vv2 = static_cast<uint64>(v2.mValue);
if (v1.mIsNegative)
vv1 = -vv1;
if (!v2.mIsNegative)
vv2 = -vv2;
if (ov1 < ov2)
{
while (ov1 < (ov2 - 1))
{
vv1 /= 10;
++ov1;
}
if (roundUp)
vv1 += 9;
vv1 /= 10;
++ov1;
}
if (ov2 < ov1)
{
while (ov2 < (ov1 - 1))
{
vv2 /= 10;
++ov2;
}
if (roundUp)
vv2 += 9;
vv2 /= 10;
++ov2;
}
int64 fv = vv1 + vv2;
if (fv >= 0)
{
uint64 v = static_cast<uint64>(fv);
canonicalizeRound(false, v, ov1, roundUp);
return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, v, ov1, false);
}
else
{
uint64 v = static_cast<uint64>(-fv);
canonicalizeRound(false, v, ov1, !roundUp);
return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, v, ov1, true);
}
}
STAmount STAmount::mulRound(const STAmount& v1, const STAmount& v2,
const uint160& uCurrencyID, const uint160& uIssuerID, bool roundUp)
{
if (v1.isZero() || v2.isZero())
return STAmount(uCurrencyID, uIssuerID);
if (v1.mIsNative && v2.mIsNative && uCurrencyID.isZero())
{
uint64 minV = (v1.getSNValue() < v2.getSNValue()) ? v1.getSNValue() : v2.getSNValue();
uint64 maxV = (v1.getSNValue() < v2.getSNValue()) ? v2.getSNValue() : v1.getSNValue();
if (minV > 3000000000ull) // sqrt(cMaxNative)
throw std::runtime_error("Native value overflow");
if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
throw std::runtime_error("Native value overflow");
return STAmount(v1.getFName(), minV * maxV);
}
uint64 value1 = v1.mValue, value2 = v2.mValue;
int offset1 = v1.mOffset, offset2 = v2.mOffset;
if (v1.mIsNative)
{
while (value1 < STAmount::cMinValue)
{
value1 *= 10;
--offset1;
}
}
if (v2.mIsNative)
{
while (value2 < STAmount::cMinValue)
{
value2 *= 10;
--offset2;
}
}
bool resultNegative = v1.mIsNegative != v2.mIsNegative;
// Compute (numerator * denominator) / 10^14 with rounding
// 10^16 <= result <= 10^18
CBigNum v;
if ((BN_add_word64(&v, value1) != 1) || (BN_mul_word64(&v, value2) != 1))
throw std::runtime_error("internal bn error");
if (resultNegative != roundUp)
BN_add_word64(&v, tenTo14m1);
else
BN_sub_word64(&v, tenTo14m1);
if (BN_div_word64(&v, tenTo14) == ((uint64) -1))
throw std::runtime_error("internal bn error");
// 10^16 <= product <= 10^18
assert(BN_num_bytes(&v) <= 64);
uint64 amount = v.getuint64();
int offset = offset1 + offset2 + 14;
canonicalizeRound(uCurrencyID.isZero(), amount, offset, resultNegative != roundUp);
return STAmount(uCurrencyID, uIssuerID, amount, offset, resultNegative);
}
STAmount STAmount::divRound(const STAmount& num, const STAmount& den,
const uint160& uCurrencyID, const uint160& uIssuerID, bool roundUp)
{
if (den.isZero())
throw std::runtime_error("division by zero");
if (num.isZero())
return STAmount(uCurrencyID, uIssuerID);
uint64 numVal = num.mValue, denVal = den.mValue;
int numOffset = num.mOffset, denOffset = den.mOffset;
if (num.mIsNative)
while (numVal < STAmount::cMinValue)
{ // Need to bring into range
numVal *= 10;
--numOffset;
}
if (den.mIsNative)
while (denVal < STAmount::cMinValue)
{
denVal *= 10;
--denOffset;
}
bool resultNegative = num.mIsNegative != num.mIsNegative;
// Compute (numerator * 10^17) / denominator
CBigNum v;
if ((BN_add_word64(&v, numVal) != 1) || (BN_mul_word64(&v, tenTo17) != 1))
throw std::runtime_error("internal bn error");
if (resultNegative != roundUp)
BN_add_word64(&v, denVal - 1);
else
BN_sub_word64(&v, denVal - 1);
if (BN_div_word64(&v, denVal) == ((uint64) -1))
throw std::runtime_error("internal bn error");
// 10^16 <= quotient <= 10^18
assert(BN_num_bytes(&v) <= 64);
uint64 amount = v.getuint64();
int offset = numOffset - denOffset - 17;
canonicalizeRound(uCurrencyID.isZero(), amount, offset, resultNegative != roundUp);
return STAmount(uCurrencyID, uIssuerID, amount, offset, resultNegative);
}
BOOST_AUTO_TEST_SUITE(amountRound)
BOOST_AUTO_TEST_CASE( amountRound_test )
{
STAmount one(CURRENCY_ONE, ACCOUNT_ONE, 1);
STAmount two(CURRENCY_ONE, ACCOUNT_ONE, 2);
STAmount three(CURRENCY_ONE, ACCOUNT_ONE, 3);
STAmount oneThird1 = STAmount::divRound(one, three, CURRENCY_ONE, ACCOUNT_ONE, false);
STAmount oneThird2 = STAmount::divide(one, three, CURRENCY_ONE, ACCOUNT_ONE);
STAmount oneThird3 = STAmount::divRound(one, three, CURRENCY_ONE, ACCOUNT_ONE, true);
cLog(lsINFO) << oneThird1;
cLog(lsINFO) << oneThird2;
cLog(lsINFO) << oneThird3;
STAmount twoThird1 = STAmount::divRound(two, three, CURRENCY_ONE, ACCOUNT_ONE, false);
STAmount twoThird2 = STAmount::divide(two, three, CURRENCY_ONE, ACCOUNT_ONE);
STAmount twoThird3 = STAmount::divRound(two, three, CURRENCY_ONE, ACCOUNT_ONE, true);
cLog(lsINFO) << twoThird1;
cLog(lsINFO) << twoThird2;
cLog(lsINFO) << twoThird3;
STAmount oneA = STAmount::mulRound(oneThird1, three, CURRENCY_ONE, ACCOUNT_ONE, false);
STAmount oneB = STAmount::multiply(oneThird2, three, CURRENCY_ONE, ACCOUNT_ONE);
STAmount oneC = STAmount::mulRound(oneThird3, three, CURRENCY_ONE, ACCOUNT_ONE, true);
cLog(lsINFO) << oneA;
cLog(lsINFO) << oneB;
cLog(lsINFO) << oneC;
STAmount fourThirdsA = STAmount::addRound(twoThird2, twoThird2, false);
STAmount fourThirdsB = twoThird2 + twoThird2;
STAmount fourThirdsC = STAmount::addRound(twoThird2, twoThird2, true);
cLog(lsINFO) << fourThirdsA;
cLog(lsINFO) << fourThirdsB;
cLog(lsINFO) << fourThirdsC;
STAmount dripTest1 = STAmount::mulRound(twoThird2, two, uint160(), uint160(), false);
STAmount dripTest2 = STAmount::multiply(twoThird2, two, uint160(), uint160());
STAmount dripTest3 = STAmount::mulRound(twoThird2, two, uint160(), uint160(), true);
cLog(lsINFO) << dripTest1;
cLog(lsINFO) << dripTest2;
cLog(lsINFO) << dripTest3;
}
BOOST_AUTO_TEST_SUITE_END()
// vim:ts=4

View File

@@ -7,6 +7,12 @@ static int BN_add_word64(BIGNUM *a, uint64 w)
return BN_add(a, &bn, a);
}
static int BN_sub_word64(BIGNUM *a, uint64 w)
{
CBigNum bn(w);
return BN_sub(a, &bn, a);
}
static int BN_mul_word64(BIGNUM *a, uint64 w)
{
CBigNum bn(w);

View File

@@ -403,12 +403,12 @@ uint256 Ledger::getHash()
void Ledger::saveAcceptedLedger(Job&, bool fromConsensus)
{
cLog(lsTRACE) << "saveAcceptedLedger " << (fromConsensus ? "fromConsensus " : "fromAcquire ") << getLedgerSeq();
static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers INDEXED BY SeqLedger where LedgerSeq = %d;");
static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;");
static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers INDEXED BY SeqLedger where LedgerSeq = %u;");
static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %u;");
static boost::format AcctTransExists("SELECT LedgerSeq FROM AccountTransactions WHERE TransID = '%s';");
static boost::format transExists("SELECT Status FROM Transactions WHERE TransID = '%s';");
static boost::format
updateTx("UPDATE Transactions SET LedgerSeq = %d, Status = '%c', TxnMeta = %s WHERE TransID = '%s';");
updateTx("UPDATE Transactions SET LedgerSeq = %u, Status = '%c', TxnMeta = %s WHERE TransID = '%s';");
static boost::format addLedger("INSERT OR REPLACE INTO Ledgers "
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,"
"AccountSetHash,TransSetHash) VALUES ('%s','%u','%s','%s','%u','%u','%d','%u','%s','%s');");

View File

@@ -24,18 +24,18 @@ LoadManager::LoadManager(int creditRate, int creditLimit, int debitWarn, int deb
mCreditRate(creditRate), mCreditLimit(creditLimit), mDebitWarn(debitWarn), mDebitLimit(debitLimit),
mShutdown(false), mUptime(0), mCosts(LT_MAX)
{
addLoadCost(LoadCost(LT_InvalidRequest, 10, LC_CPU | LC_Network));
addLoadCost(LoadCost(LT_RequestNoReply, 1, LC_CPU | LC_Disk));
addLoadCost(LoadCost(LT_InvalidSignature, 100, LC_CPU));
addLoadCost(LoadCost(LT_UnwantedData, 5, LC_CPU | LC_Network));
addLoadCost(LoadCost(LT_BadData, 20, LC_CPU));
addLoadCost(LoadCost(LT_InvalidRequest, -10, LC_CPU | LC_Network));
addLoadCost(LoadCost(LT_RequestNoReply, -1, LC_CPU | LC_Disk));
addLoadCost(LoadCost(LT_InvalidSignature, -100, LC_CPU));
addLoadCost(LoadCost(LT_UnwantedData, -5, LC_CPU | LC_Network));
addLoadCost(LoadCost(LT_BadData, -20, LC_CPU));
addLoadCost(LoadCost(LT_NewTrusted, 10, 0));
addLoadCost(LoadCost(LT_NewTransaction, 2, 0));
addLoadCost(LoadCost(LT_NeededData, 10, 0));
addLoadCost(LoadCost(LT_NewTrusted, -10, 0));
addLoadCost(LoadCost(LT_NewTransaction, -2, 0));
addLoadCost(LoadCost(LT_NeededData, -10, 0));
addLoadCost(LoadCost(LT_RequestData, 5, LC_Disk | LC_Network));
addLoadCost(LoadCost(LT_CheapQuery, 1, LC_CPU));
addLoadCost(LoadCost(LT_RequestData, -5, LC_Disk | LC_Network));
addLoadCost(LoadCost(LT_CheapQuery, -1, LC_CPU));
}
@@ -124,7 +124,10 @@ void LoadManager::canonicalize(LoadSource& source, int now) const
{
source.mBalance += mCreditRate * (now - source.mLastUpdate);
if (source.mBalance > mCreditLimit)
{
source.mBalance = mCreditLimit;
source.mLogged = false;
}
}
source.mLastUpdate = now;
}
@@ -152,8 +155,11 @@ bool LoadManager::shouldCutoff(LoadSource& source) const
boost::mutex::scoped_lock sl(mLock);
int now = upTime();
canonicalize(source, now);
if (!source.isPrivileged() || (source.mBalance > mDebitLimit))
if (source.isPrivileged() || (source.mBalance > mDebitLimit))
return false;
if (source.mLogged)
return true;
source.mLogged = true;
}
logDisconnect(source.getName());
return true;

View File

@@ -66,11 +66,14 @@ protected:
int mFlags;
int mLastUpdate;
int mLastWarning;
bool mLogged;
public:
LoadSource(bool admin) : mBalance(0), mFlags(admin ? lsfPrivileged : 0), mLastUpdate(upTime()), mLastWarning(0)
LoadSource(bool admin) :
mBalance(0), mFlags(admin ? lsfPrivileged : 0), mLastUpdate(upTime()), mLastWarning(0), mLogged(false)
{ ; }
LoadSource(const std::string& name) : mName(name), mBalance(0), mFlags(0), mLastUpdate(upTime()), mLastWarning(0)
LoadSource(const std::string& name) :
mName(name), mBalance(0), mFlags(0), mLastUpdate(upTime()), mLastWarning(0), mLogged(false)
{ ; }
void rename(const std::string& name) { mName = name; }
@@ -80,6 +83,9 @@ public:
void setPrivileged() { mFlags |= lsfPrivileged; }
int getBalance() const { return mBalance; }
bool isLogged() const { return mLogged; }
void clearLogged() { mLogged = false; }
void setOutbound() { mFlags |= lsfOutbound; }
bool isOutbound() const { return (mFlags & lsfOutbound) != 0; }
};

View File

@@ -374,27 +374,24 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
if (r == tefFAILURE)
throw Fault(IO_ERROR);
if (isTerRetry(r))
{ // transaction should be held
cLog(lsDEBUG) << "Transaction should be held: " << r;
trans->setStatus(HELD);
theApp->getMasterTransaction().canonicalize(trans, true);
mLedgerMaster->addHeldTransaction(trans);
return trans;
}
if (r == tefPAST_SEQ)
{ // duplicate or conflict
cLog(lsINFO) << "Transaction is obsolete";
trans->setStatus(OBSOLETE);
return trans;
}
if (r == tesSUCCESS)
{
cLog(lsINFO) << "Transaction is now included in open ledger";
trans->setStatus(INCLUDED);
theApp->getMasterTransaction().canonicalize(trans, true);
}
else if (r == tefPAST_SEQ)
{ // duplicate or conflict
cLog(lsINFO) << "Transaction is obsolete";
trans->setStatus(OBSOLETE);
}
else if (isTerRetry(r))
{ // transaction should be held
cLog(lsDEBUG) << "Transaction should be held: " << r;
trans->setStatus(HELD);
theApp->getMasterTransaction().canonicalize(trans, true);
mLedgerMaster->addHeldTransaction(trans);
}
else
{
cLog(lsDEBUG) << "Status other than success " << r;
@@ -1068,7 +1065,7 @@ std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
std::string sql =
str(boost::format("SELECT LedgerSeq,Status,RawTxn,TxnMeta FROM Transactions where TransID in "
"(SELECT TransID from AccountTransactions "
" WHERE Account = '%s' AND LedgerSeq <= '%d' AND LedgerSeq >= '%d' ) ORDER BY LedgerSeq DESC LIMIT 200;")
" WHERE Account = '%s' AND LedgerSeq <= '%u' AND LedgerSeq >= '%u' ) ORDER BY LedgerSeq DESC LIMIT 200;")
% account.humanAccountID() % maxLedger % minLedger);
{
@@ -1104,7 +1101,7 @@ std::vector<NetworkOPs::txnMetaLedgerType> NetworkOPs::getAccountTxsB(
std::string sql =
str(boost::format("SELECT LedgerSeq, RawTxn,TxnMeta FROM Transactions where TransID in (SELECT TransID from AccountTransactions "
" WHERE Account = '%s' AND LedgerSeq <= '%d' AND LedgerSeq >= '%d' ) ORDER BY LedgerSeq DESC LIMIT 500;")
" WHERE Account = '%s' AND LedgerSeq <= '%u' AND LedgerSeq >= '%u' ) ORDER BY LedgerSeq DESC LIMIT 500;")
% account.humanAccountID() % maxLedger % minLedger);
{
@@ -1148,7 +1145,7 @@ std::vector<RippleAddress>
{
std::vector<RippleAddress> accounts;
std::string sql = str(boost::format
("SELECT DISTINCT Account FROM AccountTransactions INDEXED BY AcctLgrIndex WHERE LedgerSeq = '%d';")
("SELECT DISTINCT Account FROM AccountTransactions INDEXED BY AcctLgrIndex WHERE LedgerSeq = '%u';")
% ledgerSeq);
RippleAddress acct;
{

View File

@@ -427,6 +427,23 @@ public:
static STAmount multiply(const STAmount& v1, const STAmount& v2)
{ return multiply(v1, v2, v1); }
// Add, subtract, multiply, or divide rounding result in specified direction
static STAmount addRound(const STAmount& v1, const STAmount& v2, bool roundUp);
static STAmount subRound(const STAmount& v1, const STAmount& v2, bool roundUp);
static STAmount mulRound(const STAmount& v1, const STAmount& v2,
const uint160& currency, const uint160& issuer, bool roundUp);
static STAmount divRound(const STAmount& v1, const STAmount& v2,
const uint160& currency, const uint160& issuer, bool roundUp);
static STAmount mulRound(const STAmount& v1, const STAmount& v2, const STAmount& saUnit, bool roundUp)
{ return mulRound(v1, v2, saUnit.getCurrency(), saUnit.getIssuer(), roundUp); }
static STAmount mulRound(const STAmount& v1, const STAmount& v2, bool roundUp)
{ return mulRound(v1, v2, v1.getCurrency(), v1.getIssuer(), roundUp); }
static STAmount divRound(const STAmount& v1, const STAmount& v2, const STAmount& saUnit, bool roundUp)
{ return divRound(v1, v2, saUnit.getCurrency(), saUnit.getIssuer(), roundUp); }
static STAmount divRound(const STAmount& v1, const STAmount& v2, bool roundUp)
{ return divRound(v1, v2, v2.getCurrency(), v2.getIssuer(), roundUp); }
// Someone is offering X for Y, what is the rate?
// Rate: smaller is better, the taker wants the most out: in/out
static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn);

View File

@@ -90,10 +90,12 @@ public:
{
if (theApp->getLoadManager().shouldCutoff(mLoadSource))
{
#if SHOULD_DISCONNECT
connection_ptr ptr = mConnection.lock();
if (ptr)
ptr->close(websocketpp::close::status::PROTOCOL_ERROR, "overload");
return rpcError(rpcSLOW_DOWN);
#endif
}
if (!jvRequest.isMember("command"))
@@ -110,7 +112,7 @@ public:
jvResult["id"] = jvRequest["id"];
}
theApp->getLoadManager().adjust(mLoadSource, 5);
theApp->getLoadManager().adjust(mLoadSource, -5);
return jvResult;
}
@@ -131,7 +133,7 @@ public:
jvResult["result"] = mRPCHandler.doCommand(jvRequest, iRole, cost);
}
if (theApp->getLoadManager().adjust(mLoadSource, cost) && theApp->getLoadManager().shouldWarn(mLoadSource))
if (theApp->getLoadManager().adjust(mLoadSource, -cost) && theApp->getLoadManager().shouldWarn(mLoadSource))
jvResult["warning"] = "load";
// Currently we will simply unwrap errors returned by the RPC

View File

@@ -3,6 +3,8 @@ exports.Amount = require('./amount').Amount;
exports.UInt160 = require('./amount').UInt160;
exports.Seed = require('./amount').Seed;
exports.utils = require('./utils');
// Important: We do not guarantee any specific version of SJCL or for any
// specific features to be included. The version and configuration may change at
// any time without warning.

View File

@@ -32,7 +32,7 @@ var OrderBook = function (remote,
if (OrderBook.subscribe_events.indexOf(type) !== -1) {
if (!self._subs && 'open' === self._remote._online_state) {
self._remote.request_subscribe()
.books([self.to_json()])
.books([self.to_json()], true)
.request();
}
self._subs += 1;
@@ -54,7 +54,7 @@ var OrderBook = function (remote,
this._remote.on('connect', function () {
if (self._subs) {
self._remote.request_subscribe()
.books([self.to_json()])
.books([self.to_json()], true)
.request();
}
});

View File

@@ -203,7 +203,7 @@ Request.prototype.rt_accounts = function (accounts) {
return this.accounts(accounts, true);
};
Request.prototype.books = function (books) {
Request.prototype.books = function (books, state) {
var procBooks = [];
for (var i = 0, l = books.length; i < l; i++) {
@@ -221,6 +221,8 @@ Request.prototype.books = function (books) {
json["IssuerIn"] = UInt160.json_rewrite(book["IssuerIn"]);
}
if (state || book["StateNow"]) json["StateNow"] = true;
procBooks.push(json);
}
this.message.books = procBooks;

View File

@@ -243,17 +243,25 @@ var STAccount = exports.Account = new SerializedType({
});
var STPathSet = exports.PathSet = new SerializedType({
typeBoundary: 0xff,
typeEnd: 0x00,
typeAccount: 0x01,
typeCurrency: 0x10,
typeIssuer: 0x20,
serialize: function (so, val) {
// XXX
for (var i = 0, l = val.length; i < l; i++) {
// Boundary
if (i) STInt8.serialize(so, this.typeBoundary);
for (var j = 0, l2 = val[i].length; j < l2; j++) {
var entry = val[i][j];
var type = 0;
if (entry.account) type |= 0x01;
if (entry.currency) type |= 0x10;
if (entry.issuer) type |= 0x20;
if (entry.account) type |= this.typeAccount;
if (entry.currency) type |= this.typeCurrency;
if (entry.issuer) type |= this.typeIssuer;
STInt8.serialize(so, type);
@@ -268,10 +276,8 @@ var STPathSet = exports.PathSet = new SerializedType({
so.append(UInt160.from_json(entry.issuer).to_bytes());
}
}
if (j < l2) STInt8.serialize(so, 0xff);
}
STInt8.serialize(so, 0x00);
STInt8.serialize(so, this.typeEnd);
},
parse: function (so) {
// XXX

View File

@@ -97,6 +97,15 @@ var assert = function (assertion, msg) {
}
};
/**
* Convert a ripple epoch to a JavaScript timestamp.
*
* JavaScript timestamps are unix epoch in milliseconds.
*/
var toTimestamp = function (rpepoch) {
return (rpepoch + 0x386D4380) * 1000;
};
exports.trace = trace;
exports.arraySet = arraySet;
exports.hexToString = hexToString;
@@ -106,5 +115,6 @@ exports.stringToHex = stringToHex;
exports.chunkString = chunkString;
exports.logObject = logObject;
exports.assert = assert;
exports.toTimestamp = toTimestamp;
// vim:sw=2:sts=2:ts=8:et