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

This commit is contained in:
jed
2012-11-26 22:14:52 -08:00
41 changed files with 2434 additions and 2180 deletions

View File

@@ -92,6 +92,7 @@ public:
bool isGeneric() const { return fieldCode == 0; }
bool isInvalid() const { return fieldCode == -1; }
bool isUseful() const { return fieldCode > 0; }
bool isKnown() const { return fieldType != STI_UNKNOWN; }
bool isBinary() const { return fieldValue < 256; }
bool isDiscardable() const { return fieldValue > 256; }

View File

@@ -23,22 +23,23 @@ enum JobType
jtINVALID = -1,
jtVALIDATION_ut = 0, // A validation from an untrusted source
jtCLIENTOP_ut = 1, // A client operation from a non-local/untrusted source
jtTRANSACTION = 2, // A transaction received from the network
jtPROPOSAL_ut = 3, // A proposal from an untrusted source
jtCLIENTOP_t = 4, // A client operation from a trusted source
jtVALIDATION_t = 5, // A validation from a trusted source
jtTRANSACTION_l = 6, // A local transaction
jtPROPOSAL_t = 7, // A proposal from a trusted source
jtADMIN = 8, // An administrative operation
jtDEATH = 9, // job of death, used internally
jtPROOFWORK = 2, // A proof of work demand from another server
jtTRANSACTION = 3, // A transaction received from the network
jtPROPOSAL_ut = 4, // A proposal from an untrusted source
jtCLIENTOP_t = 5, // A client operation from a trusted source
jtVALIDATION_t = 6, // A validation from a trusted source
jtTRANSACTION_l = 7, // A local transaction
jtPROPOSAL_t = 8, // A proposal from a trusted source
jtADMIN = 9, // An administrative operation
jtDEATH = 10, // job of death, used internally
// special types not dispatched by the job pool
jtCLIENT = 10,
jtPEER = 11,
jtDISK = 12,
jtRPC = 13,
jtACCEPTLEDGER = 14,
jtPUBLEDGER = 15,
jtCLIENT = 16,
jtPEER = 17,
jtDISK = 18,
jtRPC = 19,
jtACCEPTLEDGER = 20,
jtPUBLEDGER = 21,
};
#define NUM_JOB_TYPES 24

View File

@@ -328,8 +328,8 @@ bool LedgerEntrySet::threadTx(SLE::ref threadTo, Ledger::ref ledger,
if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID))
return false;
if (prevTxID.isZero() || TransactionMetaSet::thread(mSet.getAffectedNode(threadTo->getIndex(), sfModifiedNode),
prevTxID, prevLgrID))
if (prevTxID.isZero() ||
TransactionMetaSet::thread(mSet.getAffectedNode(threadTo, sfModifiedNode), prevTxID, prevLgrID))
return true;
assert(false);
@@ -359,7 +359,7 @@ bool LedgerEntrySet::threadOwners(SLE::ref node, Ledger::ref ledger,
return false;
}
void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
void LedgerEntrySet::calcRawMeta(Serializer& s, TER result, uint32 index)
{ // calculate the raw meta data and return it. This must be called before the set is committed
// Entries modified only as a result of building the transaction metadata
@@ -402,14 +402,17 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
SLE::pointer origNode = mLedger->getSLE(it.first);
SLE::pointer curNode = it.second.mEntry;
if ((type == &sfModifiedNode) && (*curNode == *origNode))
continue;
uint16 nodeType = curNode ? curNode->getFieldU16(sfLedgerEntryType) : origNode->getFieldU16(sfLedgerEntryType);
mSet.setAffectedNode(it.first, *type, nodeType);
if (type == &sfDeletedNode)
{
assert(origNode);
assert(curNode);
assert(origNode && curNode);
threadOwners(origNode, mLedger, newMod); // thread transaction to owners
STObject prevs(sfPreviousFields);
@@ -432,6 +435,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
}
else if (type == &sfModifiedNode)
{
assert(curNode && origNode);
if (curNode->isThreadedType()) // thread transaction to node it modified
threadTx(curNode, mLedger, newMod);
@@ -455,7 +459,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
}
else if (type == &sfCreatedNode) // if created, thread to owner(s)
{
assert(!origNode);
assert(curNode && !origNode);
threadOwners(curNode, mLedger, newMod);
if (curNode->isThreadedType()) // always thread to self
@@ -470,6 +474,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
if (!news.empty())
mSet.getAffectedNode(it.first).addObject(news);
}
else assert(false);
}
// add any new modified nodes to the modification set
@@ -477,7 +482,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
BOOST_FOREACH(u256_sle_pair& it, newMod)
entryModify(it.second);
mSet.addRaw(s, result);
mSet.addRaw(s, result, index);
cLog(lsTRACE) << "Metadata:" << mSet.getJson(0);
}

View File

@@ -124,7 +124,7 @@ public:
STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault);
Json::Value getJson(int) const;
void calcRawMeta(Serializer&, TER result);
void calcRawMeta(Serializer&, TER result, uint32 index);
// iterator functions
typedef std::map<uint256, LedgerEntrySetEntry>::iterator iterator;

View File

@@ -581,6 +581,17 @@ void Peer::processReadBuffer()
}
break;
case ripple::mtPROOFOFWORK:
{
ripple::TMProofWork msg;
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
recvProofWork(msg);
else
cLog(lsWARNING) << "parse error: " << type;
}
break;
default:
cLog(lsWARNING) << "Unknown Msg: " << type;
cLog(lsWARNING) << strHex(&mReadbuf[0], mReadbuf.size());
@@ -1124,6 +1135,23 @@ void Peer::recvAccount(ripple::TMAccount& packet)
{
}
void Peer::recvProofWork(ripple::TMProofWork& packet)
{
if (packet.has_result())
{ // this is a reply to a proof of work we sent
// WRITEME
return;
}
if (packet.has_target() && packet.has_challenge() && packet.has_iterations())
{ // this is a challenge
// WRITEME
return;
}
cLog(lsINFO) << "Received in valid proof of work object from peer";
}
void Peer::recvStatus(ripple::TMStatusChange& packet)
{
cLog(lsTRACE) << "Received status change from peer " << getIP();

View File

@@ -126,6 +126,7 @@ protected:
void recvStatus(ripple::TMStatusChange& packet);
void recvPropose(const boost::shared_ptr<ripple::TMProposeSet>& packet);
void recvHaveTxSet(ripple::TMHaveTransactionSet& packet);
void recvProofWork(ripple::TMProofWork& packet);
void getSessionCookie(std::string& strDst);

File diff suppressed because it is too large Load Diff

View File

@@ -101,20 +101,32 @@ public:
STAmount saOutPass; // <-- Amount actually sent.
bool bConsumed; // If true, use consumes full liquidity. False, may or may not.
PathState* setIndex(const int iIndex) {
mIndex = iIndex;
return this;
}
PathState(
const int iIndex,
const STAmount& saSend,
const STAmount& saSendMax,
const Ledger::ref lrLedger = Ledger::pointer()
) : mLedger(lrLedger), saInReq(saSendMax), saOutReq(saSend) { ; }
void setExpanded(
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID,
const STAmount& saSend,
const STAmount& saSendMax
const uint160& uSenderID
);
void setCanonical(
PathState::ref pspExpanded
);
Json::Value getJson() const;
static PathState::pointer createPathState(
const int iIndex,
static PathState::pointer createExpanded(
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
@@ -123,7 +135,22 @@ public:
const STAmount& saSendMax
)
{
return boost::make_shared<PathState>(iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax);
PathState::pointer pspNew = boost::make_shared<PathState>(saSend, saSendMax, lesSource.getLedgerRef());
pspNew->setExpanded(lesSource, spSourcePath, uReceiverID, uSenderID);
return pspNew;
}
static PathState::pointer createCanonical(
PathState::ref pspExpanded
)
{
PathState::pointer pspNew = boost::make_shared<PathState>(pspExpanded->saOutAct, pspExpanded->saInAct);
pspNew->setCanonical(pspExpanded);
return pspNew;
}
static bool lessPriority(PathState::ref lhs, PathState::ref rhs);
@@ -141,7 +168,6 @@ public:
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
PathState::pointer pathCreate(const STPath& spPath);
void pathNext(PathState::ref pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
TER calcNode(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality);
TER calcNodeRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality);

View File

@@ -57,6 +57,7 @@
FIELD(OfferSequence, UINT32, 25)
FIELD(FirstLedgerSequence, UINT32, 26)
FIELD(LastLedgerSequence, UINT32, 27)
FIELD(TransactionIndex, UINT32, 28)
// 64-bit integers
FIELD(IndexNext, UINT64, 1)

View File

@@ -934,7 +934,7 @@ STArray* STArray::construct(SerializerIterator& sit, SField::ref field)
throw std::runtime_error("Unknown field");
}
value.push_back(STObject(fn));
value.push_back(new STObject(fn));
value.rbegin()->set(sit, 1);
}
@@ -1234,6 +1234,9 @@ BOOST_AUTO_TEST_SUITE(SerializedObject)
BOOST_AUTO_TEST_CASE( FieldManipulation_test )
{
if (sfGeneric.isUseful())
BOOST_FAIL("sfGeneric must not be useful");
SField sfTestVL(STI_VL, 255, "TestVL");
SField sfTestH256(STI_HASH256, 255, "TestH256");
SField sfTestU32(STI_UINT32, 255, "TestU32");

View File

@@ -46,6 +46,8 @@ public:
STObject(const std::vector<SOElement::ptr>& type, SerializerIterator& sit, SField::ref name) : SerializedType(name)
{ set(sit); setType(type); }
std::auto_ptr<STObject> oClone() const { return std::auto_ptr<STObject>(new STObject(*this)); }
static std::auto_ptr<STObject> parseJson(const Json::Value& value, SField::ref name = sfGeneric, int depth = 0);
virtual ~STObject() { ; }
@@ -81,7 +83,7 @@ public:
SerializedType& back() { return mData.back(); }
const SerializedType& back() const { return mData.back(); }
int getCount() const { return mData.size(); }
int getCount() const { return mData.size(); }
bool setFlag(uint32);
bool clearFlag(uint32);
@@ -167,6 +169,10 @@ public:
bool operator!=(const STObject& o) const { return ! (*this == o); }
};
// allow ptr_* collections of STObject's
inline STObject* new_clone(const STObject& s) { return s.oClone().release(); }
inline void delete_clone(const STObject* s) { boost::checked_delete(s); }
inline STObject::iterator range_begin(STObject& x) { return x.begin(); }
inline STObject::iterator range_end(STObject &x) { return x.end(); }
namespace boost
@@ -180,12 +186,12 @@ namespace boost
class STArray : public SerializedType, private IS_INSTANCE(SerializedArray)
{
public:
typedef std::vector<STObject> vector;
typedef std::vector<STObject>::iterator iterator;
typedef std::vector<STObject>::const_iterator const_iterator;
typedef std::vector<STObject>::reverse_iterator reverse_iterator;
typedef std::vector<STObject>::const_reverse_iterator const_reverse_iterator;
typedef std::vector<STObject>::size_type size_type;
typedef boost::ptr_vector<STObject> vector;
typedef boost::ptr_vector<STObject>::iterator iterator;
typedef boost::ptr_vector<STObject>::const_iterator const_iterator;
typedef boost::ptr_vector<STObject>::reverse_iterator reverse_iterator;
typedef boost::ptr_vector<STObject>::const_reverse_iterator const_reverse_iterator;
typedef boost::ptr_vector<STObject>::size_type size_type;
protected:
@@ -210,7 +216,7 @@ public:
vector& getValue() { return value; }
// vector-like functions
void push_back(const STObject& object) { value.push_back(object); }
void push_back(const STObject& object) { value.push_back(object.oClone()); }
STObject& operator[](int j) { return value[j]; }
const STObject& operator[](int j) const { return value[j]; }
iterator begin() { return value.begin(); }

View File

@@ -19,6 +19,15 @@ DECLARE_INSTANCE(SerializedValue);
STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0);
STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1);
SerializedType& SerializedType::operator=(const SerializedType& t)
{
if ((t.fName != fName) && fName->isUseful() && t.fName->isUseful())
Log(lsWARNING) << "Caution: " << t.fName->getName() << " not replacing " << fName->getName();
if (!fName->isUseful()) fName = t.fName;
return *this;
}
void STPathSet::printDebug() {
for (int i = 0; i < value.size(); i++) {
std::cout << i << ": ";

View File

@@ -10,6 +10,15 @@
#include "Serializer.h"
#include "FieldNames.h"
#include "InstanceCounter.h"
#include "Log.h"
// CAUTION: Do not create a vector (or similar container) of any object derived from
// SerializedType. Use Boost ptr_* containers. The copy assignment operator of
// SerializedType has semantics that will cause contained types to change their names
// when an object is deleted because copy assignment is used to "slide down" the
// remaining types and this will not copy the field name. Changing the copy assignment
// operator to copy the field name breaks the use of copy assignment just to copy values,
// which is used in the transaction engine code.
enum PathFlags
{
@@ -68,8 +77,8 @@ public:
void addFieldID(Serializer& s) const { s.addFieldID(fName->fieldType, fName->fieldValue); }
SerializedType& operator=(const SerializedType& t)
{ if (!fName->fieldCode) fName = t.fName; return *this; }
SerializedType& operator=(const SerializedType& t);
bool operator==(const SerializedType& t) const
{ return (getSType() == t.getSType()) && isEquivalent(t); }
bool operator!=(const SerializedType& t) const

View File

@@ -119,7 +119,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
{
// Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially).
Serializer m;
mNodes.calcRawMeta(m, terResult);
mNodes.calcRawMeta(m, terResult, mTxnSeq++);
txnWrite();

View File

@@ -56,6 +56,7 @@ private:
protected:
Ledger::pointer mLedger;
int mTxnSeq;
uint160 mTxnAccountID;
SLE::pointer mTxnAccount;
@@ -65,8 +66,8 @@ protected:
public:
typedef boost::shared_ptr<TransactionEngine> pointer;
TransactionEngine() { ; }
TransactionEngine(Ledger::ref ledger) : mLedger(ledger) { assert(mLedger); }
TransactionEngine() : mTxnSeq(0) { ; }
TransactionEngine(Ledger::ref ledger) : mLedger(ledger), mTxnSeq(0) { assert(mLedger); }
LedgerEntrySet& getNodes() { return mNodes; }
Ledger::pointer getLedger() { return mLedger; }

View File

@@ -20,6 +20,7 @@ TransactionMetaSet::TransactionMetaSet(const uint256& txid, uint32 ledger, const
throw std::runtime_error("bad metadata");
mResult = obj->getFieldU8(sfTransactionResult);
mIndex = obj->getFieldU32(sfTransactionIndex);
mNodes = * dynamic_cast<STArray*>(&obj->getField(sfAffectedNodes));
}
@@ -79,20 +80,21 @@ std::vector<RippleAddress> TransactionMetaSet::getAffectedAccounts()
}
*/
STObject& TransactionMetaSet::getAffectedNode(const uint256& node, SField::ref type)
STObject& TransactionMetaSet::getAffectedNode(SLE::ref node, SField::ref type)
{
assert(&type);
uint256 index = node->getIndex();
BOOST_FOREACH(STObject& it, mNodes)
{
if (it.getFieldH256(sfLedgerIndex) == node)
if (it.getFieldH256(sfLedgerIndex) == index)
return it;
}
mNodes.push_back(STObject(sfModifiedNode));
mNodes.push_back(STObject(type));
STObject& obj = mNodes.back();
assert(obj.getFName() == type);
obj.setFieldH256(sfLedgerIndex, node);
obj.setFieldH256(sfLedgerIndex, index);
obj.setFieldU16(sfLedgerEntryType, node->getFieldU16(sfLedgerEntryType));
return obj;
}
@@ -153,13 +155,15 @@ STObject TransactionMetaSet::getAsObject() const
STObject metaData(sfTransactionMetaData);
assert(mResult != 255);
metaData.setFieldU8(sfTransactionResult, mResult);
metaData.setFieldU32(sfTransactionIndex, mIndex);
metaData.addObject(mNodes);
return metaData;
}
void TransactionMetaSet::addRaw(Serializer& s, TER result)
void TransactionMetaSet::addRaw(Serializer& s, TER result, uint32 index)
{
mResult = static_cast<int>(result);
mIndex = index;
assert((mResult == 0) || ((mResult > 100) && (mResult <= 255)));
mNodes.sort(compare);

View File

@@ -12,6 +12,7 @@
#include "Serializer.h"
#include "SerializedTypes.h"
#include "SerializedObject.h"
#include "SerializedLedger.h"
#include "TransactionErr.h"
class TransactionMetaSet
@@ -22,13 +23,15 @@ public:
protected:
uint256 mTransactionID;
uint32 mLedger;
uint32 mIndex;
int mResult;
STArray mNodes;
public:
TransactionMetaSet() : mLedger(0), mResult(255) { ; }
TransactionMetaSet(const uint256& txID, uint32 ledger) : mTransactionID(txID), mLedger(ledger), mResult(255) { ; }
TransactionMetaSet() : mLedger(0), mIndex(static_cast<uint32>(-1)), mResult(255) { ; }
TransactionMetaSet(const uint256& txID, uint32 ledger, uint32 index) :
mTransactionID(txID), mLedger(ledger), mIndex(static_cast<uint32>(-1)), mResult(255) { ; }
TransactionMetaSet(const uint256& txID, uint32 ledger, const std::vector<unsigned char>&);
void init(const uint256& transactionID, uint32 ledger);
@@ -39,17 +42,18 @@ public:
uint32 getLgrSeq() { return mLedger; }
int getResult() const { return mResult; }
TER getResultTER() const { return static_cast<TER>(mResult); }
uint32 getIndex() const { return mIndex; }
bool isNodeAffected(const uint256&) const;
void setAffectedNode(const uint256&, SField::ref type, uint16 nodeType);
STObject& getAffectedNode(const uint256&, SField::ref type);
STObject& getAffectedNode(SLE::ref node, SField::ref type); // create if needed
STObject& getAffectedNode(const uint256&);
const STObject& peekAffectedNode(const uint256&) const;
//std::vector<RippleAddress> getAffectedAccounts();
Json::Value getJson(int p) const { return getAsObject().getJson(p); }
void addRaw(Serializer&, TER);
void addRaw(Serializer&, TER, uint32 index);
STObject getAsObject() const;

View File

@@ -5,7 +5,7 @@ enum MessageType {
mtHELLO = 1;
mtERROR_MSG = 2;
mtPING = 3;
mtPOW = 4;
mtPROOFOFWORK = 4;
// network presence detection
mtGET_CONTACTS = 10;
@@ -33,13 +33,13 @@ enum MessageType {
}
// empty message (or just result) = request proof of work
// token, iterations, target, challenge = give proof of work challenge
// token, response = show proof of work
// token, result = result of pow attempt
// token, iterations, target, challenge = issue demand for proof of work
// token, response = give solution to proof of work
// token, result = report result of pow
message TMProofWork
{
optional string token = 1;
required string token = 1;
optional uint32 iterations = 2;
optional bytes target = 3;
optional bytes challenge = 4;

View File

@@ -22,4 +22,4 @@ var Account = function (network, account) {
exports.Account = Account;
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -344,6 +344,10 @@ Amount.from_json = function(j) {
return (new Amount()).parse_json(j);
};
Amount.from_human = function(j) {
return (new Amount()).parse_human(j);
};
Amount.is_valid = function (j) {
return Amount.from_json(j).is_valid();
};
@@ -388,6 +392,18 @@ Amount.prototype.currency = function() {
return this._currency;
};
Amount.prototype.set_currency = function(c) {
if ('string' === typeof c) {
this._currency.parse_json(c);
}
else
{
c.copyTo(this._currency);
}
return this;
};
// Only checks the value. Not the currency and issuer.
Amount.prototype.is_valid = function() {
return !isNaN(this._value);
@@ -462,8 +478,15 @@ Amount.prototype.to_human = function (opts)
{
opts = opts || {};
var int_part = this._value.divide(consts.bi_xns_unit).toString(10);
var fraction_part = this._value.mod(consts.bi_xns_unit).toString(10);
// Default options
if ("undefined" === typeof opts.group_sep) opts.group_sep = true;
opts.group_width = opts.group_width || 3;
var denominator = this._is_native ?
consts.bi_xns_unit :
consts.bi_10.clone().pow(-this._offset);
var int_part = this._value.divide(denominator).toString(10);
var fraction_part = this._value.mod(denominator).toString(10);
int_part = int_part.replace(/^0*/, '');
fraction_part = fraction_part.replace(/0*$/, '');
@@ -472,6 +495,13 @@ Amount.prototype.to_human = function (opts)
fraction_part = fraction_part.slice(0, opts.precision);
}
if (opts.group_sep) {
if ("string" !== typeof opts.group_sep) {
opts.group_sep = ',';
}
int_part = utils.chunkString(int_part, opts.group_width, true).join(opts.group_sep);
}
var formatted = '';
formatted += int_part.length ? int_part : '0';
formatted += fraction_part.length ? '.'+fraction_part : '';
@@ -534,6 +564,67 @@ Amount.prototype.to_text_full = function() {
: this.to_text() + "/" + this._currency.to_json() + "/" + this._issuer.to_json();
};
/**
* Tries to correctly interpret an amount as entered by a user.
*
* Examples:
*
* XRP 250 => 250000000/XRP
* 25.2 XRP => 25200000/XRP
* USD 100.40 => 100.4/USD/?
* 100 => 100000000/XRP
*/
Amount.prototype.parse_human = function(j) {
// Cast to string
j = ""+j;
// Parse
var m = j.match(/^\s*([a-z]{3})?\s*(-)?(\d+)(?:\.(\d*))?\s*([a-z]{3})?\s*$/i);
if (m) {
var currency = m[1] || m[5] || "XRP",
integer = m[3] || "0",
fraction = m[4] || "",
precision = null;
currency = currency.toUpperCase();
this._value = new BigInteger(integer);
this.set_currency(currency);
// XRP have exactly six digits of precision
if (currency === 'XRP') {
fraction = fraction.slice(0, 6);
while (fraction.length < 6) {
fraction += "0";
}
this._is_native = true;
this._value = this._value.multiply(consts.bi_xns_unit).add(new BigInteger(fraction));
}
// Other currencies have arbitrary precision
else {
while (fraction[fraction.length - 1] === "0") {
fraction = fraction.slice(0, fraction.length - 1);
}
precision = fraction.length;
this._is_native = false;
var multiplier = consts.bi_10.clone().pow(precision);
this._value = this._value.multiply(multiplier).add(new BigInteger(fraction));
this._offset = -precision;
this.canonicalize();
}
this._is_negative = !!m[2];
} else {
this._value = NaN;
}
return this;
};
// Parse a XRP value from untrusted input.
// - integer = raw units
// - float = with precision 6
@@ -551,7 +642,7 @@ Amount.prototype.parse_native = function(j) {
this._value = new BigInteger(m[2]);
}
else {
// Float notation
// Float notation : values multiplied by 1,000,000.
var int_part = (new BigInteger(m[2])).multiply(consts.bi_xns_unit);
var fraction_part = (new BigInteger(m[3])).multiply(new BigInteger(String(Math.pow(10, 1+consts.xns_precision-m[3].length))));
@@ -578,7 +669,8 @@ Amount.prototype.parse_native = function(j) {
return this;
};
// Parse a non-native value.
// Parse a non-native value for the json wire format.
// Requires _currency to be set!
Amount.prototype.parse_value = function(j) {
this._is_native = false;
@@ -647,9 +739,9 @@ Amount.prototype.parse_json = function(j) {
var m = j.match(/^(.+)\/(...)\/(.+)$/);
if (m) {
this.parse_value(m[1]);
this._currency = Currency.from_json(m[2]);
this._issuer = UInt160.from_json(m[3]);
this.parse_value(m[1]);
}
else {
this.parse_native(j);
@@ -663,9 +755,9 @@ Amount.prototype.parse_json = function(j) {
else if ('object' === typeof j && 'value' in j) {
// Parse the passed value to sanitize and copy it.
this.parse_value(j.value);
this._currency.parse_json(j.currency); // Never XRP.
this._issuer.parse_json(j.issuer);
this.parse_value(j.value);
}
else {
this._value = NaN;
@@ -727,4 +819,4 @@ exports.UInt160 = UInt160;
exports.config = {};
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1216,4 +1216,4 @@ BigInteger.ONE = nbv(1);
exports.nbi = nbi;
exports.BigInteger = BigInteger;
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -55,4 +55,4 @@ Network.protocol.stop = function () {
exports.Network = Network;
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -88,4 +88,4 @@ exports.mkPath = mkPath;
exports.resetPath = resetPath;
exports.rmPath = rmPath;
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -22,6 +22,8 @@ var Amount = require('./amount.js').Amount;
var Currency = require('./amount.js').Currency;
var UInt160 = require('./amount.js').UInt160;
var utils = require('./utils');
// Request events emitted:
// 'success' : Request successful.
// 'error' : Request failed.
@@ -37,23 +39,16 @@ var Request = function (remote, command) {
};
this.remote = remote;
this.requested = false;
this.on('request', function () {
self.request_default();
});
};
Request.prototype = new EventEmitter;
// Send the request to a remote.
Request.prototype.request = function (remote) {
this.emit('request', remote);
};
Request.prototype.request_default = function () {
if (!this.requested) {
this.requested = true;
this.remote.request(this);
this.emit('request', remote);
}
};
@@ -189,7 +184,8 @@ var Remote = function (opts, trace) {
this.trusted = opts.trusted;
this.websocket_ip = opts.websocket_ip;
this.websocket_port = opts.websocket_port;
this.local_sequence = opts.local_sequence;
this.local_sequence = opts.local_sequence; // Locally track sequence numbers
this.local_fee = opts.local_fee; // Locally set fees
this.id = 0;
this.trace = opts.trace || trace;
this._ledger_current_index = undefined;
@@ -460,12 +456,12 @@ Remote.prototype._connect_message = function (ws, json) {
unexpected = true;
}
else if ('success' === message.status) {
if (this.trace) console.log("remote: response: %s", JSON.stringify(message, undefined, 2));
if (this.trace) utils.logObject("remote: response: %s", message);
request.emit('success', message.result);
}
else if (message.error) {
if (this.trace) console.log("remote: error: %s", JSON.stringify(message, undefined, 2));
if (this.trace) utils.logObject("remote: error: %s", message);
request.emit('error', {
'error' : 'remoteError',
@@ -491,7 +487,7 @@ Remote.prototype._connect_message = function (ws, json) {
// Account subscription event
case 'account':
if (this.trace) console.log("remote: account: %s", JSON.stringify(message, undefined, 2));
if (this.trace) utils.logObject("remote: account: %s", message);
break;
default:
@@ -535,12 +531,12 @@ Remote.prototype.request = function (request) {
this.id += 1; // Advance id.
if (this.trace) console.log("remote: request: %s", JSON.stringify(request.message));
if (this.trace) utils.logObject("remote: request: %s", request.message);
this.ws.send(JSON.stringify(request.message));
}
else {
if (this.trace) console.log("remote: request: DROPPING: %s", JSON.stringify(request.message));
if (this.trace) utils.logObject("remote: request: DROPPING: %s", request.message);
}
};
@@ -592,7 +588,8 @@ Remote.prototype.request_ledger_entry = function (type) {
this.type = type;
// Transparent caching:
request.on('request', function (remote) { // Intercept default request.
this.request_default = this.request;
this.request = function () { // Intercept default request.
if (self._ledger_hash) {
// XXX Add caching.
}
@@ -610,7 +607,7 @@ Remote.prototype.request_ledger_entry = function (type) {
if (node) {
// Emulate fetch of ledger entry.
this.request.emit('success', {
self.emit('success', {
// YYY Missing lots of fields.
'node' : node,
});
@@ -634,7 +631,7 @@ Remote.prototype.request_ledger_entry = function (type) {
this.request_default();
}
}
});
};
return request;
};
@@ -1174,7 +1171,7 @@ Transaction.prototype.submit = function (callback) {
// YYY Might check paths for invalid accounts.
if (undefined === tx_json.Fee) {
if (this.remote.local_fee && undefined === tx_json.Fee) {
if ('Payment' === tx_json.TransactionType
&& tx_json.Flags & Remote.flags.Payment.CreateAccount) {
@@ -1346,7 +1343,7 @@ Transaction.prototype.set_flags = function (flags) {
}
}
if (this.tx_json.Flags & Remote.flags.Payment.CreateAccount)
if (this.remote.local_fee && (this.tx_json.Flags & Remote.flags.Payment.CreateAccount))
this.tx_json.Fee = Remote.fees.account_create.to_json();
}
@@ -1399,10 +1396,13 @@ Transaction.prototype.offer_create = function (src, taker_pays, taker_gets, expi
this.secret = this._account_secret(src);
this.tx_json.TransactionType = 'OfferCreate';
this.tx_json.Account = UInt160.json_rewrite(src);
this.tx_json.Fee = Remote.fees.offer.to_json();
this.tx_json.TakerPays = Amount.json_rewrite(taker_pays);
this.tx_json.TakerGets = Amount.json_rewrite(taker_gets);
if (this.remote.local_fee) {
this.tx_json.Fee = Remote.fees.offer.to_json();
}
if (expiration)
this.tx_json.Expiration = Date === expiration.constructor
? expiration.getTime()
@@ -1489,4 +1489,4 @@ Transaction.prototype.wallet_add = function (src, amount, authorized_key, public
exports.config = {};
exports.Remote = Remote;
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -41,4 +41,4 @@ serializer.addUInt160 = function(value) {
serializer.getSHA512Half = function() {
};
// vim:ts=4
// vim:sw=2:sts=2:ts=8:et

View File

@@ -70,10 +70,30 @@ var stringToArray = function (s) {
return a;
};
exports.trace = trace;
exports.arraySet = arraySet;
exports.hexToString = hexToString;
exports.stringToArray = stringToArray;
exports.stringToHex = stringToHex;
var chunkString = function (str, n, leftAlign) {
var ret = [];
var i=0, len=str.length;
if (leftAlign) {
i = str.length % n;
if (i) ret.push(str.slice(0, i));
}
for(; i < len; i += n) {
ret.push(str.slice(i, n+i));
}
return ret;
};
// vim:sw=2:sts=2:ts=8
var logObject = function (msg, obj) {
console.log(msg, JSON.stringify(obj, undefined, 2));
};
exports.trace = trace;
exports.arraySet = arraySet;
exports.hexToString = hexToString;
exports.stringToArray = stringToArray;
exports.stringToHex = stringToHex;
exports.logObject = logObject;
exports.chunkString = chunkString;
// vim:sw=2:sts=2:ts=8:et

7
src/js/utils.web.js Normal file
View File

@@ -0,0 +1,7 @@
exports = module.exports = require('./utils.js');
// We override this function for browsers, because they print objects nicer
// natively than JSON.stringify can.
exports.logObject = function (msg, obj) {
console.log(msg, "", obj);
};

View File

@@ -1,12 +1,12 @@
var buster = require("buster");
var buster = require("buster");
var jsbn = require('../src/js/jsbn.js');
var BigInteger = jsbn.BigInteger;
var nbi = jsbn.nbi;
var jsbn = require('../src/js/jsbn.js');
var BigInteger = jsbn.BigInteger;
var nbi = jsbn.nbi;
var amount = require("../src/js/amount.js");
var Amount = require("../src/js/amount.js").Amount;
var UInt160 = require("../src/js/amount.js").UInt160;
var amount = require("../src/js/amount.js");
var Amount = require("../src/js/amount.js").Amount;
var UInt160 = require("../src/js/amount.js").UInt160;
require("../src/js/amount.js").config = require("./config.js");
@@ -107,4 +107,4 @@ buster.testCase("Amount", {
}
});
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -4,6 +4,8 @@ config["Newcoin tests"] = {
rootPath: "../",
environment: "node",
tests: [
"test/*-test.js"
"test/*-test.js"
]
}
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,20 +1,22 @@
//
// Configuration for unit tests
// Configuration for unit tests: to be locally customized as needed.
//
var path = require("path");
var path = require("path");
var testconfig = require("./testconfig.js");
exports.accounts = testconfig.accounts;
// Where to find the binary.
exports.rippled = path.resolve("build/rippled");
exports.server_default = "alpha";
exports.server_default = "alpha";
// Configuration for servers.
exports.servers = {
// A local test server.
"alpha" : {
'trusted' : true,
'no_server' : true,
// "peer_ip" : "0.0.0.0",
// "peer_port" : 51235,
'rpc_ip' : "0.0.0.0",
@@ -22,48 +24,10 @@ exports.servers = {
'websocket_ip' : "127.0.0.1",
'websocket_port' : 5006,
'local_sequence' : true,
'local_fee' : true,
// 'validation_seed' : "shhDFVsmS2GSu5vUyZSPXYfj1r79h",
// 'validators' : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta"
}
};
// Configuration for test accounts.
exports.accounts = {
// Users
"alice" : {
'account' : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
'secret' : "alice",
},
"bob" : {
'account' : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
'secret' : "bob",
},
"carol" : {
'account' : "rH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW",
'secret' : "carol",
},
// Nexuses
"bitstamp" : {
'account' : "r4jKmc2nQb5yEU6eycefiNKGHTU5NQJASx",
'secret' : "bitstamp",
},
"mtgox" : {
'account' : "rGihwhaqU8g7ahwAvTq6iX5rvsfcbgZw6v",
'secret' : "mtgox",
},
// Merchants
"amazon" : {
'account' : "rhheXqX7bDnXePJeMHhubDDvw2uUTtenPd",
'secret' : "amazon",
},
// Master account
"root" : {
'account' : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
'secret' : "masterpassphrase",
},
};
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,17 +1,17 @@
var async = require("async");
var buster = require("buster");
var async = require("async");
var buster = require("buster");
var Amount = require("../src/js/amount.js").Amount;
var Remote = require("../src/js/remote.js").Remote;
var Server = require("./server.js").Server;
var Amount = require("../src/js/amount.js").Amount;
var Remote = require("../src/js/remote.js").Remote;
var Server = require("./server.js").Server;
var testutils = require("./testutils.js");
var testutils = require("./testutils.js");
require("../src/js/amount.js").config = require("./config.js");
require("../src/js/remote.js").config = require("./config.js");
buster.testRunner.timeout = 5000;
buster.testCase("//Monitor account", {
'setUp' : testutils.build_setup({ verbose: true }),
'tearDown' : testutils.build_teardown(),
@@ -21,34 +21,34 @@ buster.testCase("//Monitor account", {
var self = this;
async.waterfall([
function (callback) {
self.what = "Create accounts.";
function (callback) {
self.what = "Create accounts.";
testutils.create_accounts(self.remote, "root", "10000", ["alice"], callback);
},
function (callback) {
self.what = "Close ledger.";
testutils.create_accounts(self.remote, "root", "10000", ["alice"], callback);
},
function (callback) {
self.what = "Close ledger.";
self.remote.once('ledger_closed', function (ledger_closed, ledger_index) {
callback();
});
self.remote.once('ledger_closed', function (ledger_closed, ledger_index) {
callback();
});
self.remote.ledger_accept();
},
function (callback) {
self.what = "Dumping root.";
self.remote.ledger_accept();
},
function (callback) {
self.what = "Dumping root.";
testutils.account_dump(self.remote, "root", function (error) {
buster.refute(error);
callback();
});
},
testutils.account_dump(self.remote, "root", function (error) {
buster.refute(error);
callback();
});
},
], function (error) {
buster.refute(error, self.what);
done();
buster.refute(error, self.what);
done();
});
},
});
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
var async = require("async");
var buster = require("buster");
var async = require("async");
var buster = require("buster");
var Amount = require("../src/js/amount.js").Amount;
var Remote = require("../src/js/remote.js").Remote;
var Server = require("./server.js").Server;
var Amount = require("../src/js/amount.js").Amount;
var Remote = require("../src/js/remote.js").Remote;
var Server = require("./server.js").Server;
var testutils = require("./testutils.js");
var testutils = require("./testutils.js");
require("../src/js/amount.js").config = require("./config.js");
require("../src/js/remote.js").config = require("./config.js");
@@ -21,46 +21,47 @@ buster.testCase("Path finding", {
var self = this;
async.waterfall([
function (callback) {
self.what = "Create accounts.";
function (callback) {
self.what = "Create accounts.";
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
},
function (callback) {
self.what = "Set credit limits.";
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
},
function (callback) {
self.what = "Set credit limits.";
testutils.credit_limits(self.remote,
{
"alice" : "600/USD/mtgox",
"bob" : "700/USD/mtgox",
},
callback);
},
function (callback) {
self.what = "Distribute funds.";
testutils.credit_limits(self.remote,
{
"alice" : "600/USD/mtgox",
"bob" : "700/USD/mtgox",
},
callback);
},
function (callback) {
self.what = "Distribute funds.";
testutils.payments(self.remote,
{
"mtgox" : [ "70/USD/alice", "50/USD/bob" ],
},
callback);
},
function (callback) {
self.what = "Find path from alice to mtgox";
testutils.payments(self.remote,
{
"mtgox" : [ "70/USD/alice", "50/USD/bob" ],
},
callback);
},
function (callback) {
self.what = "Find path from alice to mtgox";
self.remote.request_ripple_path_find("alice", "bob", "5/USD/mtgox",
[ { 'currency' : "USD" } ])
.on('success', function (m) {
console.log("proposed: m", JSON.stringify(m));
self.remote.request_ripple_path_find("alice", "bob", "5/USD/mtgox",
[ { 'currency' : "USD" } ])
.on('success', function (m) {
console.log("proposed: m", JSON.stringify(m));
callback();
})
.request();
},
], function (error) {
buster.refute(error, self.what);
done();
});
callback();
})
.request();
},
], function (error) {
buster.refute(error, self.what);
done();
});
},
});
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,19 +1,19 @@
var buster = require("buster");
var buster = require("buster");
var Amount = require("../src/js/amount.js").Amount;
var Remote = require("../src/js/remote.js").Remote;
var Server = require("./server.js").Server;
var Amount = require("../src/js/amount.js").Amount;
var Remote = require("../src/js/remote.js").Remote;
var Server = require("./server.js").Server;
var testutils = require("./testutils.js");
var testutils = require("./testutils.js");
require("../src/js/amount.js").config = require("./config.js");
require("../src/js/remote.js").config = require("./config.js");
// How long to wait for server to start.
var serverDelay = 1500; // XXX Not implemented.
var serverDelay = 1500; // XXX Not implemented.
buster.testRunner.timeout = 5000;
buster.testCase("Remote functions", {
'setUp' : testutils.build_setup(),
'tearDown' : testutils.build_teardown(),
@@ -21,16 +21,16 @@ buster.testCase("Remote functions", {
"request_ledger_current" :
function (done) {
this.remote.request_ledger_current().on('success', function (m) {
// console.log(m);
// console.log(m);
buster.assert.equals(m.ledger_current_index, 3);
done();
})
buster.assert.equals(m.ledger_current_index, 3);
done();
})
.on('error', function(m) {
// console.log(m);
// console.log(m);
buster.assert(false);
})
buster.assert(false);
})
.request();
},
@@ -38,16 +38,16 @@ buster.testCase("Remote functions", {
"request_ledger_hash" :
function (done) {
this.remote.request_ledger_hash().on('success', function (m) {
// console.log("result: %s", JSON.stringify(m));
// console.log("result: %s", JSON.stringify(m));
buster.assert.equals(m.ledger_index, 2);
done();
})
buster.assert.equals(m.ledger_index, 2);
done();
})
.on('error', function(m) {
// console.log("error: %s", m);
// console.log("error: %s", m);
buster.assert(false);
})
buster.assert(false);
})
.request();
},
@@ -56,30 +56,30 @@ buster.testCase("Remote functions", {
var self = this;
this.remote.request_ledger_hash().on('success', function (r) {
// console.log("result: %s", JSON.stringify(r));
// console.log("result: %s", JSON.stringify(r));
self.remote
.request_ledger_entry('account_root')
.ledger_hash(r.ledger_hash)
.account_root("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
self.remote
.request_ledger_entry('account_root')
.ledger_hash(r.ledger_hash)
.account_root("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
buster.assert('node' in r);
done();
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert('node' in r);
done();
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert(false);
})
.request();
})
buster.assert(false);
})
.request();
})
.on('error', function(m) {
// console.log("error: %s", m);
// console.log("error: %s", m);
buster.assert(false);
})
buster.assert(false);
})
.request();
},
@@ -89,31 +89,31 @@ buster.testCase("Remote functions", {
var self = this;
this.remote.request_ledger_hash().on('success', function (r) {
// console.log("result: %s", JSON.stringify(r));
// console.log("result: %s", JSON.stringify(r));
self.remote
.request_ledger_entry('account_root')
.ledger_hash(r.ledger_hash)
.account_root("zHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
self.remote
.request_ledger_entry('account_root')
.ledger_hash(r.ledger_hash)
.account_root("zHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
buster.assert(false);
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert(false);
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert.equals(m.error, 'remoteError');
buster.assert.equals(m.remote.error, 'malformedAddress');
done();
})
.request();
})
buster.assert.equals(m.error, 'remoteError');
buster.assert.equals(m.remote.error, 'malformedAddress');
done();
})
.request();
})
.on('error', function(m) {
// console.log("error: %s", m);
// console.log("error: %s", m);
buster.assert(false);
})
buster.assert(false);
})
.request();
},
@@ -122,31 +122,31 @@ buster.testCase("Remote functions", {
var self = this;
this.remote.request_ledger_hash().on('success', function (r) {
// console.log("result: %s", JSON.stringify(r));
// console.log("result: %s", JSON.stringify(r));
self.remote
.request_ledger_entry('account_root')
.ledger_hash(r.ledger_hash)
.account_root("alice")
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
self.remote
.request_ledger_entry('account_root')
.ledger_hash(r.ledger_hash)
.account_root("alice")
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
buster.assert(false);
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert(false);
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert.equals(m.error, 'remoteError');
buster.assert.equals(m.remote.error, 'entryNotFound');
done();
})
.request();
})
buster.assert.equals(m.error, 'remoteError');
buster.assert.equals(m.remote.error, 'entryNotFound');
done();
})
.request();
})
.on('error', function(m) {
// console.log("error: %s", m);
// console.log("error: %s", m);
buster.assert(false);
}).request();
buster.assert(false);
}).request();
},
"ledger_entry index" :
@@ -154,51 +154,52 @@ buster.testCase("Remote functions", {
var self = this;
this.remote.request_ledger_hash().on('success', function (r) {
// console.log("result: %s", JSON.stringify(r));
// console.log("result: %s", JSON.stringify(r));
self.remote
.request_ledger_entry('index')
.ledger_hash(r.ledger_hash)
.account_root("alice")
.index("2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8")
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
self.remote
.request_ledger_entry('index')
.ledger_hash(r.ledger_hash)
.account_root("alice")
.index("2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8")
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
buster.assert('node_binary' in r);
done();
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert('node_binary' in r);
done();
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert(false);
}).
request();
})
buster.assert(false);
}).
request();
})
.on('error', function(m) {
// console.log(m);
// console.log(m);
buster.assert(false);
})
buster.assert(false);
})
.request();
},
"create account" :
function (done) {
this.remote.transaction()
.payment('root', 'alice', Amount.from_json("10000"))
.set_flags('CreateAccount')
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
.payment('root', 'alice', Amount.from_json("10000"))
.set_flags('CreateAccount')
.on('success', function (r) {
// console.log("account_root: %s", JSON.stringify(r));
// Need to verify account and balance.
done();
})
.on('error', function(m) {
// console.log("error: %s", m);
// Need to verify account and balance.
buster.assert(true);
done();
})
.on('error', function(m) {
// console.log("error: %s", m);
buster.assert(false);
})
.submit();
buster.assert(false);
})
.submit();
},
"create account final" :
@@ -209,39 +210,39 @@ buster.testCase("Remote functions", {
var got_success;
this.remote.transaction()
.payment('root', 'alice', Amount.from_json("10000"))
.set_flags('CreateAccount')
.on('success', function (r) {
// console.log("create_account: %s", JSON.stringify(r));
.payment('root', 'alice', Amount.from_json("10000"))
.set_flags('CreateAccount')
.on('success', function (r) {
// console.log("create_account: %s", JSON.stringify(r));
got_success = true;
})
.on('error', function (m) {
// console.log("error: %s", m);
got_success = true;
})
.on('error', function (m) {
// console.log("error: %s", m);
buster.assert(false);
})
.on('final', function (m) {
// console.log("final: %s", JSON.stringify(m));
buster.assert(false);
})
.on('final', function (m) {
// console.log("final: %s", JSON.stringify(m));
buster.assert(got_success && got_proposed);
done();
})
.on('proposed', function (m) {
// console.log("proposed: %s", JSON.stringify(m));
buster.assert(got_success && got_proposed);
done();
})
.on('proposed', function (m) {
// console.log("proposed: %s", JSON.stringify(m));
// buster.assert.equals(m.result, 'terNO_DST');
buster.assert.equals(m.result, 'tesSUCCESS');
// buster.assert.equals(m.result, 'terNO_DST');
buster.assert.equals(m.result, 'tesSUCCESS');
got_proposed = true;
got_proposed = true;
self.remote.ledger_accept();
})
.on('status', function (s) {
// console.log("status: %s", JSON.stringify(s));
})
.submit();
self.remote.ledger_accept();
})
.on('status', function (s) {
// console.log("status: %s", JSON.stringify(s));
})
.submit();
},
});
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

File diff suppressed because it is too large Load Diff

View File

@@ -12,17 +12,17 @@ buster.testCase("Standalone server startup", {
alpha = Server.from_config("alpha");
alpha
.on('started', function () {
alpha
.on('stopped', function () {
buster.assert(true);
.on('started', function () {
alpha
.on('stopped', function () {
buster.assert(true);
done();
})
.stop();
})
.start();
done();
})
.stop();
})
.start();
}
});
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -2,11 +2,11 @@
//
// Usage:
// s = new Server(name, config)
// s.verbose() : optional
// s.verbose() : optional
// .start()
// 'started'
// 'started'
//
// s.stop() : stops server is started.
// s.stop() : stops server is started.
// 'stopped'
//
@@ -15,22 +15,22 @@
// Servers are created in tmp/server/$server
//
var buster = require("buster");
var child = require("child_process");
var fs = require("fs");
var path = require("path");
var util = require("util");
var buster = require("buster");
var child = require("child_process");
var fs = require("fs");
var path = require("path");
var util = require("util");
var EventEmitter = require('events').EventEmitter;
var config = require("./config.js");
var nodeutils = require("../src/js/nodeutils.js");
var config = require("./config.js");
var nodeutils = require("../src/js/nodeutils.js");
// Create a server object
var Server = function (name, config, verbose) {
this.name = name;
this.config = config;
this.started = false;
this.quiet = !verbose;
this.name = name;
this.config = config;
this.started = false;
this.quiet = !verbose;
};
Server.prototype = new EventEmitter;
@@ -66,7 +66,7 @@ Server.prototype._writeConfig = function(done) {
fs.writeFile(
this.configPath(),
Object.keys(this.config).map(function(o) {
return util.format("[%s]\n%s\n", o, self.config[o]);
return util.format("[%s]\n%s\n", o, self.config[o]);
}).join(""),
'utf8', done);
};
@@ -111,10 +111,10 @@ Server.prototype._makeBase = function (done) {
// Reset the server directory, build it if needed.
nodeutils.resetPath(path, '0777', function (e) {
if (e) {
throw e;
throw e;
}
else {
self._writeConfig(done);
self._writeConfig(done);
}
});
};
@@ -128,17 +128,17 @@ Server.prototype.verbose = function () {
// Create a standalone server.
// Prepare the working directory and spawn the server.
Server.prototype.start = function () {
var self = this;
var self = this;
if (!this.quiet) console.log("server: start: %s: %s", this.name, JSON.stringify(this.config));
this._makeBase(function (e) {
if (e) {
throw e;
throw e;
}
else {
self._serverSpawnSync();
self.emit('started');
self._serverSpawnSync();
self.emit('started');
}
});
@@ -153,10 +153,10 @@ Server.prototype.stop = function () {
// Update the on exit to invoke done.
this.child.on('exit', function (code, signal) {
if (!self.quiet) console.log("server: stop: server exited");
if (!self.quiet) console.log("server: stop: server exited");
self.emit('stopped');
delete this.child;
self.emit('stopped');
delete this.child;
});
this.child.kill();
@@ -171,4 +171,4 @@ Server.prototype.stop = function () {
exports.Server = Server;
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

48
test/testconfig.js Normal file
View File

@@ -0,0 +1,48 @@
//
// Configuration for unit tests: not to be locally customized.
//
// Configuration for test accounts.
exports.accounts = {
// Users
"alice" : {
'account' : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
'secret' : "alice",
},
"bob" : {
'account' : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
'secret' : "bob",
},
"carol" : {
'account' : "rH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW",
'secret' : "carol",
},
"dan" : {
'account' : "rJ85Mok8YRNxSo7NnxKGrPuk29uAeZQqwZ",
'secret' : "dan",
},
// Nexuses
"bitstamp" : {
'account' : "r4jKmc2nQb5yEU6eycefiNKGHTU5NQJASx",
'secret' : "bitstamp",
},
"mtgox" : {
'account' : "rGihwhaqU8g7ahwAvTq6iX5rvsfcbgZw6v",
'secret' : "mtgox",
},
// Merchants
"amazon" : {
'account' : "rhheXqX7bDnXePJeMHhubDDvw2uUTtenPd",
'secret' : "amazon",
},
// Master account
"root" : {
'account' : "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
'secret' : "masterpassphrase",
},
};
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,5 +1,4 @@
var async = require("async");
// var buster = require("buster");
var Amount = require("../src/js/amount.js").Amount;
var Remote = require("../src/js/remote.js").Remote;
@@ -15,24 +14,24 @@ var account_dump = function (remote, account, callback) {
async.waterfall([
function (callback) {
self.what = "Get latest account_root";
self.what = "Get latest account_root";
remote
.request_ledger_entry('account_root')
.ledger_hash(remote.ledger_hash())
.account_root("root")
.on('success', function (r) {
//console.log("account_root: %s", JSON.stringify(r, undefined, 2));
remote
.request_ledger_entry('account_root')
.ledger_hash(remote.ledger_hash())
.account_root("root")
.on('success', function (r) {
//console.log("account_root: %s", JSON.stringify(r, undefined, 2));
callback();
})
.on('error', function(m) {
console.log("error: %s", m);
callback();
})
.on('error', function(m) {
console.log("error: %s", m);
buster.assert(false);
callback();
})
.request();
buster.assert(false);
callback();
})
.request();
},
], function (error) {
callback(error);
@@ -106,10 +105,10 @@ var build_setup = function (opts, host) {
* @param host {String} Identifier for the host configuration to be used.
*/
var build_teardown = function (host) {
return function (done) {
host = host || config.server_default;
var data = this.store[host];
@@ -117,22 +116,22 @@ var build_teardown = function (host) {
async.series([
function disconnectWebsocketStep(callback) {
data.remote
.on('disconnected', callback)
.connect(false);
},
function stopServerStep(callback) {
if (opts.no_server)
if (opts.no_server)
{
return callback();
}
return callback();
}
data.server.on('stopped', callback).stop();
}
], done);
], done);
};
};
@@ -144,15 +143,15 @@ var create_accounts = function (remote, src, amount, accounts, callback) {
.payment(src, account, amount)
.set_flags('CreateAccount')
.on('proposed', function (m) {
// console.log("proposed: %s", JSON.stringify(m));
// console.log("proposed: %s", JSON.stringify(m));
callback(m.result != 'tesSUCCESS');
})
callback(m.result != 'tesSUCCESS');
})
.on('error', function (m) {
// console.log("error: %s", JSON.stringify(m));
// console.log("error: %s", JSON.stringify(m));
callback(m);
})
callback(m);
})
.submit();
}, callback);
};
@@ -163,14 +162,14 @@ var credit_limit = function (remote, src, amount, callback) {
remote.transaction()
.ripple_line_set(src, amount)
.on('proposed', function (m) {
// console.log("proposed: %s", JSON.stringify(m));
// console.log("proposed: %s", JSON.stringify(m));
callback(m.result != 'tesSUCCESS');
callback(m.result != 'tesSUCCESS');
})
.on('error', function (m) {
// console.log("error: %s", JSON.stringify(m));
// console.log("error: %s", JSON.stringify(m));
callback(m);
callback(m);
})
.submit();
};
@@ -181,8 +180,8 @@ var credit_limits = function (remote, balances, callback) {
var limits = [];
for (var src in balances) {
var values_src = balances[src];
var values = 'string' === typeof values_src ? [ values_src ] : values_src;
var values_src = balances[src];
var values = 'string' === typeof values_src ? [ values_src ] : values_src;
for (var index in values) {
limits.push( { "source" : src, "amount" : values[index] } );
@@ -192,7 +191,7 @@ var credit_limits = function (remote, balances, callback) {
async.every(limits,
function (limit, callback) {
credit_limit(remote, limit.source, limit.amount,
function (mismatch) { callback(!mismatch); });
function (mismatch) { callback(!mismatch); });
},
function (every) {
callback(!every);
@@ -205,14 +204,14 @@ var payment = function (remote, src, dst, amount, callback) {
remote.transaction()
.payment(src, dst, amount)
.on('proposed', function (m) {
// console.log("proposed: %s", JSON.stringify(m));
// console.log("proposed: %s", JSON.stringify(m));
callback(m.result != 'tesSUCCESS');
callback(m.result != 'tesSUCCESS');
})
.on('error', function (m) {
// console.log("error: %s", JSON.stringify(m));
// console.log("error: %s", JSON.stringify(m));
callback(m);
callback(m);
})
.submit();
};
@@ -223,8 +222,8 @@ var payments = function (remote, balances, callback) {
var sends = [];
for (var src in balances) {
var values_src = balances[src];
var values = 'string' === typeof values_src ? [ values_src ] : values_src;
var values_src = balances[src];
var values = 'string' === typeof values_src ? [ values_src ] : values_src;
for (var index in values) {
var amount_json = values[index];
@@ -237,7 +236,7 @@ var payments = function (remote, balances, callback) {
async.every(sends,
function (send, callback) {
payment(remote, send.source, send.destination, send.amount,
function (mismatch) { callback(!mismatch); });
function (mismatch) { callback(!mismatch); });
},
function (every) {
callback(!every);
@@ -251,14 +250,14 @@ var transfer_rate = function (remote, src, billionths, callback) {
.account_set(src)
.transfer_rate(billionths)
.on('proposed', function (m) {
// console.log("proposed: %s", JSON.stringify(m));
// console.log("proposed: %s", JSON.stringify(m));
callback(m.result != 'tesSUCCESS');
callback(m.result != 'tesSUCCESS');
})
.on('error', function (m) {
// console.log("error: %s", JSON.stringify(m));
// console.log("error: %s", JSON.stringify(m));
callback(m);
callback(m);
})
.submit();
};
@@ -270,32 +269,32 @@ var verify_balance = function (remote, src, amount_json, callback) {
if (amount_req.is_native()) {
remote.request_account_balance(src, 'CURRENT')
.once('account_balance', function (amount_act) {
if (!amount_act.equals(amount_req))
console.log("verify_balance: failed: %s / %s",
amount_act.to_text_full(),
amount_req.to_text_full());
if (!amount_act.equals(amount_req))
console.log("verify_balance: failed: %s / %s",
amount_act.to_text_full(),
amount_req.to_text_full());
callback(!amount_act.equals(amount_req));
})
callback(!amount_act.equals(amount_req));
})
.request();
}
else {
remote.request_ripple_balance(src, amount_req.issuer().to_json(), amount_req.currency().to_json(), 'CURRENT')
.once('ripple_state', function (m) {
// console.log("BALANCE: %s", JSON.stringify(m));
// console.log("account_balance: %s", m.account_balance.to_text_full());
// console.log("account_limit: %s", m.account_limit.to_text_full());
// console.log("issuer_balance: %s", m.issuer_balance.to_text_full());
// console.log("issuer_limit: %s", m.issuer_limit.to_text_full());
// console.log("BALANCE: %s", JSON.stringify(m));
// console.log("account_balance: %s", m.account_balance.to_text_full());
// console.log("account_limit: %s", m.account_limit.to_text_full());
// console.log("issuer_balance: %s", m.issuer_balance.to_text_full());
// console.log("issuer_limit: %s", m.issuer_limit.to_text_full());
var account_balance = Amount.from_json(m.account_balance);
var account_balance = Amount.from_json(m.account_balance);
if (!account_balance.equals(amount_req)) {
console.log("verify_balance: failed: %s vs %s is %s: %s", src, account_balance.to_text_full(), amount_req.to_text_full(), account_balance.not_equals_why(amount_req));
}
if (!account_balance.equals(amount_req)) {
console.log("verify_balance: failed: %s vs %s is %s: %s", src, account_balance.to_text_full(), amount_req.to_text_full(), account_balance.not_equals_why(amount_req));
}
callback(!account_balance.equals(amount_req));
})
callback(!account_balance.equals(amount_req));
})
.request();
}
};
@@ -304,8 +303,8 @@ var verify_balances = function (remote, balances, callback) {
var tests = [];
for (var src in balances) {
var values_src = balances[src];
var values = 'string' === typeof values_src ? [ values_src ] : values_src;
var values_src = balances[src];
var values = 'string' === typeof values_src ? [ values_src ] : values_src;
for (var index in values) {
tests.push( { "source" : src, "amount" : values[index] } );
@@ -315,7 +314,7 @@ var verify_balances = function (remote, balances, callback) {
async.every(tests,
function (check, callback) {
verify_balance(remote, check.source, check.amount,
function (mismatch) { callback(!mismatch); });
function (mismatch) { callback(!mismatch); });
},
function (every) {
callback(!every);
@@ -332,13 +331,13 @@ var verify_offer = function (remote, owner, seq, taker_pays, taker_gets, callbac
remote.request_ledger_entry('offer')
.offer_id(owner, seq)
.on('success', function (m) {
var wrong = (!Amount.from_json(m.node.TakerGets).equals(Amount.from_json(taker_gets))
|| !Amount.from_json(m.node.TakerPays).equals(Amount.from_json(taker_pays)));
var wrong = (!Amount.from_json(m.node.TakerGets).equals(Amount.from_json(taker_gets))
|| !Amount.from_json(m.node.TakerPays).equals(Amount.from_json(taker_pays)));
if (wrong)
console.log("verify_offer: failed: %s", JSON.stringify(m));
if (wrong)
console.log("verify_offer: failed: %s", JSON.stringify(m));
callback(wrong);
callback(wrong);
})
.request();
};
@@ -349,32 +348,32 @@ var verify_offer_not_found = function (remote, owner, seq, callback) {
remote.request_ledger_entry('offer')
.offer_id(owner, seq)
.on('success', function (m) {
console.log("verify_offer_not_found: found offer: %s", JSON.stringify(m));
console.log("verify_offer_not_found: found offer: %s", JSON.stringify(m));
callback('entryFound');
callback('entryFound');
})
.on('error', function (m) {
// console.log("verify_offer_not_found: success: %s", JSON.stringify(m));
// console.log("verify_offer_not_found: success: %s", JSON.stringify(m));
callback('remoteError' !== m.error
|| 'entryNotFound' !== m.remote.error);
callback('remoteError' !== m.error
|| 'entryNotFound' !== m.remote.error);
})
.request();
};
exports.account_dump = account_dump;
exports.account_dump = account_dump;
exports.build_setup = build_setup;
exports.create_accounts = create_accounts;
exports.credit_limit = credit_limit;
exports.credit_limits = credit_limits;
exports.payment = payment;
exports.payments = payments;
exports.build_teardown = build_teardown;
exports.transfer_rate = transfer_rate;
exports.verify_balance = verify_balance;
exports.verify_balances = verify_balances;
exports.verify_offer = verify_offer;
exports.verify_offer_not_found = verify_offer_not_found;
exports.build_setup = build_setup;
exports.create_accounts = create_accounts;
exports.credit_limit = credit_limit;
exports.credit_limits = credit_limits;
exports.payment = payment;
exports.payments = payments;
exports.build_teardown = build_teardown;
exports.transfer_rate = transfer_rate;
exports.verify_balance = verify_balance;
exports.verify_balances = verify_balances;
exports.verify_offer = verify_offer;
exports.verify_offer_not_found = verify_offer_not_found;
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,4 +1,4 @@
var fs = require("fs");
var fs = require("fs");
var buster = require("buster");
var utils = require("../src/js/utils.js");
@@ -23,4 +23,4 @@ buster.testCase("Utils", {
}
});
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et

View File

@@ -17,23 +17,23 @@ buster.testCase("WebSocket connection", {
"websocket connect and disconnect" :
function (done) {
var alpha = Remote.from_config("alpha");
var alpha = Remote.from_config("alpha");
alpha
.on('connected', function () {
// OPEN
buster.assert(true);
.on('connected', function () {
// OPEN
buster.assert(true);
alpha
.on('disconnected', function () {
// CLOSED
buster.assert(true);
done();
})
.connect(false);
})
.connect();
alpha
.on('disconnected', function () {
// CLOSED
buster.assert(true);
done();
})
.connect(false);
})
.connect();
},
});
// vim:sw=2:sts=2:ts=8
// vim:sw=2:sts=2:ts=8:et