mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin into api
This commit is contained in:
@@ -1,16 +1,18 @@
|
|||||||
|
var async = require("async");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
|
|
||||||
var utils = require("./utils.js");
|
var utils = require("./utils.js");
|
||||||
|
|
||||||
// Empty a directory.
|
// Empty a directory.
|
||||||
|
// done(err) : err = true if an error occured.
|
||||||
var emptyPath = function(dirPath, done) {
|
var emptyPath = function(dirPath, done) {
|
||||||
fs.readdir(dirPath, function(err, files) {
|
fs.readdir(dirPath, function(err, files) {
|
||||||
if (err) {
|
if (err) {
|
||||||
done(err);
|
done(err);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
utils.mapOr(rmPath, files.map(function(f) { return path.join(dirPath, f); }), done);
|
async.some(files.map(function(f) { return path.join(dirPath, f); }), rmPath, done);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -53,6 +55,7 @@ var resetPath = function(dirPath, mode, done) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Remove path recursively.
|
// Remove path recursively.
|
||||||
|
// done(err)
|
||||||
var rmPath = function(dirPath, done) {
|
var rmPath = function(dirPath, done) {
|
||||||
// console.log("rmPath: %s", dirPath);
|
// console.log("rmPath: %s", dirPath);
|
||||||
|
|
||||||
|
|||||||
86
js/remote.js
86
js/remote.js
@@ -36,11 +36,12 @@ var config = require('../test/config.js');
|
|||||||
var Request = function (remote, command) {
|
var Request = function (remote, command) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.message = {
|
this.message = {
|
||||||
'command' : command,
|
'command' : command,
|
||||||
'id' : undefined,
|
'id' : undefined,
|
||||||
};
|
};
|
||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
|
this.requested = false;
|
||||||
|
|
||||||
this.on('request', function () {
|
this.on('request', function () {
|
||||||
self.request_default();
|
self.request_default();
|
||||||
@@ -68,7 +69,10 @@ Request.prototype.request = function (remote) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Request.prototype.request_default = function () {
|
Request.prototype.request_default = function () {
|
||||||
this.remote.request(this);
|
if (!this.requested) {
|
||||||
|
this.requested = true;
|
||||||
|
this.remote.request(this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Request.prototype.ledger_choose = function (current) {
|
Request.prototype.ledger_choose = function (current) {
|
||||||
@@ -572,6 +576,7 @@ Remote.prototype.submit = function (transaction) {
|
|||||||
else {
|
else {
|
||||||
if (!transaction.transaction.Sequence) {
|
if (!transaction.transaction.Sequence) {
|
||||||
transaction.transaction.Sequence = this.account_seq(transaction.transaction.Account, 'ADVANCE');
|
transaction.transaction.Sequence = this.account_seq(transaction.transaction.Account, 'ADVANCE');
|
||||||
|
// console.log("Sequence: %s", transaction.transaction.Sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!transaction.transaction.Sequence) {
|
if (!transaction.transaction.Sequence) {
|
||||||
@@ -581,7 +586,7 @@ Remote.prototype.submit = function (transaction) {
|
|||||||
// Try again.
|
// Try again.
|
||||||
self.submit(transaction);
|
self.submit(transaction);
|
||||||
})
|
})
|
||||||
.on('error', function (message) {
|
.on('error_account_seq_cache', function (message) {
|
||||||
// XXX Maybe be smarter about this. Don't want to trust an untrusted server for this seq number.
|
// XXX Maybe be smarter about this. Don't want to trust an untrusted server for this seq number.
|
||||||
|
|
||||||
// Look in the current ledger.
|
// Look in the current ledger.
|
||||||
@@ -590,7 +595,7 @@ Remote.prototype.submit = function (transaction) {
|
|||||||
// Try again.
|
// Try again.
|
||||||
self.submit(transaction);
|
self.submit(transaction);
|
||||||
})
|
})
|
||||||
.on('error', function (message) {
|
.on('error_account_seq_cache', function (message) {
|
||||||
// Forward errors.
|
// Forward errors.
|
||||||
transaction.emit('error', message);
|
transaction.emit('error', message);
|
||||||
})
|
})
|
||||||
@@ -685,6 +690,11 @@ Remote.prototype.account_seq = function (account, advance) {
|
|||||||
seq = account_info.seq;
|
seq = account_info.seq;
|
||||||
|
|
||||||
if (advance) account_info.seq += 1;
|
if (advance) account_info.seq += 1;
|
||||||
|
|
||||||
|
// console.log("cached: %s current=%d next=%d", account, seq, account_info.seq);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// console.log("uncached: %s", account);
|
||||||
}
|
}
|
||||||
|
|
||||||
return seq;
|
return seq;
|
||||||
@@ -701,21 +711,40 @@ Remote.prototype.set_account_seq = function (account, seq) {
|
|||||||
// Return a request to refresh accounts[account].seq.
|
// Return a request to refresh accounts[account].seq.
|
||||||
Remote.prototype.account_seq_cache = function (account, current) {
|
Remote.prototype.account_seq_cache = function (account, current) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var request = this.request_ledger_entry('account_root');
|
var request;
|
||||||
|
|
||||||
|
if (!self.accounts[account]) self.accounts[account] = {};
|
||||||
|
|
||||||
|
var account_info = self.accounts[account];
|
||||||
|
|
||||||
|
request = account_info.caching_seq_request;
|
||||||
|
if (!request) {
|
||||||
|
// console.log("starting: %s", account);
|
||||||
|
request = self.request_ledger_entry('account_root')
|
||||||
|
.account_root(account)
|
||||||
|
.ledger_choose(current)
|
||||||
|
.on('success', function (message) {
|
||||||
|
delete account_info.caching_seq_request;
|
||||||
|
|
||||||
|
var seq = message.node.Sequence;
|
||||||
|
|
||||||
|
account_info.seq = seq;
|
||||||
|
|
||||||
|
// console.log("caching: %s %d", account, seq);
|
||||||
|
// If the caller also waits for 'success', they might run before this.
|
||||||
|
request.emit('success_account_seq_cache', message);
|
||||||
|
})
|
||||||
|
.on('error', function (message) {
|
||||||
|
// console.log("error: %s", account);
|
||||||
|
delete account_info.caching_seq_request;
|
||||||
|
|
||||||
|
request.emit('error_account_seq_cache', message);
|
||||||
|
});
|
||||||
|
|
||||||
|
account_info.caching_seq_request = request;
|
||||||
|
}
|
||||||
|
|
||||||
return request
|
return request
|
||||||
.account_root(account)
|
|
||||||
.ledger_choose(current)
|
|
||||||
.on('success', function (message) {
|
|
||||||
var seq = message.node.Sequence;
|
|
||||||
|
|
||||||
if (!self.accounts[account]) self.accounts[account] = {};
|
|
||||||
|
|
||||||
self.accounts[account].seq = seq;
|
|
||||||
|
|
||||||
// If the caller also waits for 'success', they might run before this.
|
|
||||||
request.emit('success_account_seq_cache');
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mark an account's root node as dirty.
|
// Mark an account's root node as dirty.
|
||||||
@@ -1042,6 +1071,16 @@ Transaction.prototype.send_max = function (send_max) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --> rate: In billionths.
|
||||||
|
Transaction.prototype.transfer_rate = function (rate) {
|
||||||
|
this.transaction.TransferRate = Number(rate);
|
||||||
|
|
||||||
|
if (this.transaction.TransferRate < 1e9)
|
||||||
|
throw 'invalidTransferRate';
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// Add flags to a transaction.
|
// Add flags to a transaction.
|
||||||
// --> flags: undefined, _flag_, or [ _flags_ ]
|
// --> flags: undefined, _flag_, or [ _flags_ ]
|
||||||
Transaction.prototype.set_flags = function (flags) {
|
Transaction.prototype.set_flags = function (flags) {
|
||||||
@@ -1081,14 +1120,15 @@ Transaction.prototype._account_secret = function (account) {
|
|||||||
return this.remote.config.accounts[account] ? this.remote.config.accounts[account].secret : undefined;
|
return this.remote.config.accounts[account] ? this.remote.config.accounts[account].secret : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
// .wallet_locator()
|
// Options:
|
||||||
// .message_key()
|
// .domain() NYI
|
||||||
// .domain()
|
// .message_key() NYI
|
||||||
// .transfer_rate()
|
// .transfer_rate()
|
||||||
// .publish()
|
// .wallet_locator() NYI
|
||||||
Transaction.prototype.account_set = function (src) {
|
Transaction.prototype.account_set = function (src) {
|
||||||
this.secret = this._account_secret(src);
|
this.secret = this._account_secret(src);
|
||||||
this.transaction.TransactionType = 'AccountSet';
|
this.transaction.TransactionType = 'AccountSet';
|
||||||
|
this.transaction.Account = UInt160.json_rewrite(src);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|||||||
19
js/utils.js
19
js/utils.js
@@ -19,24 +19,6 @@ var throwErr = function(done) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// apply function to elements of array. Return first true value to done or undefined.
|
|
||||||
var mapOr = function(func, array, done) {
|
|
||||||
if (array.length) {
|
|
||||||
func(array[array.length-1], function(v) {
|
|
||||||
if (v) {
|
|
||||||
done(v);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
array.length -= 1;
|
|
||||||
mapOr(func, array, done);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var trace = function(comment, func) {
|
var trace = function(comment, func) {
|
||||||
return function() {
|
return function() {
|
||||||
console.log("%s: %s", trace, arguments.toString);
|
console.log("%s: %s", trace, arguments.toString);
|
||||||
@@ -88,7 +70,6 @@ var stringToArray = function (s) {
|
|||||||
return a;
|
return a;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.mapOr = mapOr;
|
|
||||||
exports.trace = trace;
|
exports.trace = trace;
|
||||||
exports.arraySet = arraySet;
|
exports.arraySet = arraySet;
|
||||||
exports.hexToString = hexToString;
|
exports.hexToString = hexToString;
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ SField sfIndex(STI_HASH256, 258, "index");
|
|||||||
|
|
||||||
static int initFields()
|
static int initFields()
|
||||||
{
|
{
|
||||||
|
sfTxnSignature.notSigningField(); sfTxnSignatures.notSigningField();
|
||||||
|
sfSignature.notSigningField();
|
||||||
|
|
||||||
sfHighQualityIn.setMeta(SFM_CHANGE); sfHighQualityOut.setMeta(SFM_CHANGE);
|
sfHighQualityIn.setMeta(SFM_CHANGE); sfHighQualityOut.setMeta(SFM_CHANGE);
|
||||||
sfLowQualityIn.setMeta(SFM_CHANGE); sfLowQualityOut.setMeta(SFM_CHANGE);
|
sfLowQualityIn.setMeta(SFM_CHANGE); sfLowQualityOut.setMeta(SFM_CHANGE);
|
||||||
|
|
||||||
|
|||||||
@@ -60,16 +60,18 @@ public:
|
|||||||
const int fieldValue; // Code number for protocol
|
const int fieldValue; // Code number for protocol
|
||||||
std::string fieldName;
|
std::string fieldName;
|
||||||
SF_Meta fieldMeta;
|
SF_Meta fieldMeta;
|
||||||
|
bool signingField;
|
||||||
|
|
||||||
SField(int fc, SerializedTypeID tid, int fv, const char* fn) :
|
SField(int fc, SerializedTypeID tid, int fv, const char* fn) :
|
||||||
fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn), fieldMeta(SFM_NEVER)
|
fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn), fieldMeta(SFM_NEVER), signingField(true)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock sl(mapMutex);
|
boost::mutex::scoped_lock sl(mapMutex);
|
||||||
codeToField[fieldCode] = this;
|
codeToField[fieldCode] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SField(SerializedTypeID tid, int fv, const char *fn) :
|
SField(SerializedTypeID tid, int fv, const char *fn) :
|
||||||
fieldCode(FIELD_CODE(tid, fv)), fieldType(tid), fieldValue(fv), fieldName(fn), fieldMeta(SFM_NEVER)
|
fieldCode(FIELD_CODE(tid, fv)), fieldType(tid), fieldValue(fv), fieldName(fn),
|
||||||
|
fieldMeta(SFM_NEVER), signingField(true)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock sl(mapMutex);
|
boost::mutex::scoped_lock sl(mapMutex);
|
||||||
codeToField[fieldCode] = this;
|
codeToField[fieldCode] = this;
|
||||||
@@ -97,6 +99,11 @@ public:
|
|||||||
bool shouldMetaDel() const { return (fieldMeta == SFM_DELETE) || (fieldMeta == SFM_ALWAYS); }
|
bool shouldMetaDel() const { return (fieldMeta == SFM_DELETE) || (fieldMeta == SFM_ALWAYS); }
|
||||||
bool shouldMetaMod() const { return (fieldMeta == SFM_CHANGE) || (fieldMeta == SFM_ALWAYS); }
|
bool shouldMetaMod() const { return (fieldMeta == SFM_CHANGE) || (fieldMeta == SFM_ALWAYS); }
|
||||||
void setMeta(SF_Meta m) { fieldMeta = m; }
|
void setMeta(SF_Meta m) { fieldMeta = m; }
|
||||||
|
bool isSigningField() const { return signingField; }
|
||||||
|
void notSigningField() { signingField = false; }
|
||||||
|
|
||||||
|
bool shouldInclude(bool withSigningField) const
|
||||||
|
{ return (fieldValue < 256) && (withSigningField || signingField); }
|
||||||
|
|
||||||
bool operator==(const SField& f) const { return fieldCode == f.fieldCode; }
|
bool operator==(const SField& f) const { return fieldCode == f.fieldCode; }
|
||||||
bool operator!=(const SField& f) const { return fieldCode != f.fieldCode; }
|
bool operator!=(const SField& f) const { return fieldCode != f.fieldCode; }
|
||||||
|
|||||||
@@ -799,7 +799,11 @@ void RippleCalc::calcNodeRipple(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur...
|
// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur...
|
||||||
// No account adjustments in reverse as we don't know how much is going to actually be pushed through yet.
|
// Based on required deliverable, propagate redeem, issue, and deliver requests to the previous node.
|
||||||
|
// Inflate amount requested by required fees.
|
||||||
|
// Reedems are limited based on IOUs previous has on hand.
|
||||||
|
// Issues are limited based on credit limits and amount owed.
|
||||||
|
// No account balance adjustments as we don't know how much is going to actually be pushed through yet.
|
||||||
// <-- tesSUCCESS or tepPATH_DRY
|
// <-- tesSUCCESS or tepPATH_DRY
|
||||||
TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality)
|
TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality)
|
||||||
{
|
{
|
||||||
@@ -1135,7 +1139,9 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
|
|||||||
return terResult;
|
return terResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When moving forward, we know the actual amount to push through so adjust balances.
|
// The reverse pass has been narrowing by credit available and inflating by fees as it worked backwards.
|
||||||
|
// Now, push through the actual amount to each node and adjust balances.
|
||||||
|
//
|
||||||
// Perform balance adjustments between previous and current node.
|
// Perform balance adjustments between previous and current node.
|
||||||
// - The previous node: specifies what to push through to current.
|
// - The previous node: specifies what to push through to current.
|
||||||
// - All of previous output is consumed.
|
// - All of previous output is consumed.
|
||||||
@@ -1204,46 +1210,39 @@ TER RippleCalc::calcNodeAccountFwd(
|
|||||||
|
|
||||||
if (bPrvAccount && bNxtAccount)
|
if (bPrvAccount && bNxtAccount)
|
||||||
{
|
{
|
||||||
|
// Next is an account, must be rippling.
|
||||||
|
|
||||||
if (!uIndex)
|
if (!uIndex)
|
||||||
{
|
{
|
||||||
// ^ --> ACCOUNT --> account
|
// ^ --> ACCOUNT --> account
|
||||||
|
|
||||||
// First node, calculate amount to send.
|
// First node, calculate amount to ripple based on what is available.
|
||||||
// XXX Limit by stamp/ripple balance
|
|
||||||
|
|
||||||
const STAmount& saCurSendMaxReq = pspCur->saInReq.isNegative()
|
// Limit by sendmax.
|
||||||
? pspCur->saInReq // Negative for no limit, doing a calculation.
|
const STAmount saCurSendMaxReq = pspCur->saInReq.isNegative()
|
||||||
|
? pspCur->saInReq // Negative for no limit, doing a calculation.
|
||||||
: pspCur->saInReq-pspCur->saInAct; // request - done.
|
: pspCur->saInReq-pspCur->saInAct; // request - done.
|
||||||
STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends.
|
STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends.
|
||||||
|
|
||||||
if (saCurRedeemReq)
|
saCurRedeemAct = saCurRedeemReq
|
||||||
{
|
// Redeem requested.
|
||||||
// Redeem requested.
|
? saCurRedeemReq.isNegative()
|
||||||
saCurRedeemAct = saCurRedeemReq.isNegative()
|
? saCurRedeemReq
|
||||||
? saCurRedeemReq
|
: std::min(saCurRedeemReq, saCurSendMaxReq)
|
||||||
: std::min(saCurRedeemReq, saCurSendMaxReq);
|
// No redeeming.
|
||||||
}
|
: saCurRedeemReq;
|
||||||
else
|
|
||||||
{
|
|
||||||
// No redeeming.
|
|
||||||
|
|
||||||
saCurRedeemAct = saCurRedeemReq;
|
|
||||||
}
|
|
||||||
saCurSendMaxPass = saCurRedeemAct;
|
saCurSendMaxPass = saCurRedeemAct;
|
||||||
|
|
||||||
if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxPass != saCurSendMaxReq))
|
saCurIssueAct = (saCurIssueReq // Issue wanted.
|
||||||
{
|
&& (saCurSendMaxReq.isNegative() // No limit.
|
||||||
// Issue requested and pass does not meet max.
|
|| saCurSendMaxPass != saCurSendMaxReq)) // Not yet satisfied.
|
||||||
saCurIssueAct = saCurSendMaxReq.isNegative()
|
// Issue requested and pass does not meet max.
|
||||||
? saCurIssueReq
|
? saCurSendMaxReq.isNegative()
|
||||||
: std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq);
|
? saCurIssueReq
|
||||||
}
|
: std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq)
|
||||||
else
|
// No issuing.
|
||||||
{
|
: STAmount(saCurIssueReq);
|
||||||
// No issuing.
|
|
||||||
|
|
||||||
saCurIssueAct = STAmount(saCurIssueReq);
|
|
||||||
}
|
|
||||||
saCurSendMaxPass += saCurIssueAct;
|
saCurSendMaxPass += saCurIssueAct;
|
||||||
|
|
||||||
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saInReq=%s saInAct=%s saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s saCurSendMaxPass=%s")
|
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saInReq=%s saInAct=%s saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s saCurSendMaxPass=%s")
|
||||||
@@ -1287,7 +1286,7 @@ TER RippleCalc::calcNodeAccountFwd(
|
|||||||
saCurIssueAct.zero(saCurIssueReq);
|
saCurIssueAct.zero(saCurIssueReq);
|
||||||
|
|
||||||
// Previous redeem part 1: redeem -> redeem
|
// Previous redeem part 1: redeem -> redeem
|
||||||
if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok.
|
if (saPrvRedeemReq && saCurRedeemReq) // Previous wants to redeem.
|
||||||
{
|
{
|
||||||
// Rate : 1.0 : quality out
|
// Rate : 1.0 : quality out
|
||||||
calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax);
|
calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax);
|
||||||
@@ -1302,25 +1301,23 @@ TER RippleCalc::calcNodeAccountFwd(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Previous redeem part 2: redeem -> issue.
|
// Previous redeem part 2: redeem -> issue.
|
||||||
// wants to redeem and current would and can issue.
|
|
||||||
// If redeeming cur to next is done, this implies can issue.
|
|
||||||
if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem.
|
if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem.
|
||||||
&& saCurRedeemReq == saCurRedeemAct // Current has no more to redeem to next.
|
&& saCurRedeemReq == saCurRedeemAct // Current redeeming is done can issue.
|
||||||
&& saCurIssueReq)
|
&& saCurIssueReq) // Current wants to issue.
|
||||||
{
|
{
|
||||||
// Rate : 1.0 : transfer_rate
|
// Rate : 1.0 : transfer_rate
|
||||||
calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax);
|
calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Previous issue part 2 : issue -> issue
|
// Previous issue part 2 : issue -> issue
|
||||||
if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok.
|
if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue.
|
||||||
|
&& saCurRedeemReq == saCurRedeemAct) // Current redeeming is done can issue.
|
||||||
{
|
{
|
||||||
// Rate: quality in : 1.0
|
// Rate: quality in : 1.0
|
||||||
calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax);
|
calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust prv --> cur balance : take all inbound
|
// Adjust prv --> cur balance : take all inbound
|
||||||
// XXX Currency must be in amount.
|
|
||||||
lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false);
|
lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1429,7 +1426,7 @@ bool PathState::lessPriority(PathState::ref lhs, PathState::ref rhs)
|
|||||||
return lhs->mIndex > rhs->mIndex; // Bigger is worse.
|
return lhs->mIndex > rhs->mIndex; // Bigger is worse.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID.
|
// Make sure last path node delivers to uAccountID: uCurrencyID from uIssuerID.
|
||||||
//
|
//
|
||||||
// If the unadded next node as specified by arguments would not work as is, then add the necessary nodes so it would work.
|
// If the unadded next node as specified by arguments would not work as is, then add the necessary nodes so it would work.
|
||||||
//
|
//
|
||||||
@@ -1651,7 +1648,40 @@ PathState::PathState(
|
|||||||
| STPathElement::typeIssuer,
|
| STPathElement::typeIssuer,
|
||||||
uSenderID,
|
uSenderID,
|
||||||
uInCurrencyID,
|
uInCurrencyID,
|
||||||
uInIssuerID);
|
uSenderID);
|
||||||
|
|
||||||
|
if (tesSUCCESS == terStatus
|
||||||
|
&& !!uInCurrencyID // First was not XRC
|
||||||
|
&& uInIssuerID != uSenderID) { // Issuer was not same as sender
|
||||||
|
// May have an implied node.
|
||||||
|
|
||||||
|
// Figure out next node properties for implied node.
|
||||||
|
const uint160 uNxtCurrencyID = spSourcePath.getElementCount()
|
||||||
|
? spSourcePath.getElement(0).getCurrency()
|
||||||
|
: uOutCurrencyID;
|
||||||
|
const uint160 uNxtAccountID = spSourcePath.getElementCount()
|
||||||
|
? spSourcePath.getElement(0).getAccountID()
|
||||||
|
: !!uOutCurrencyID
|
||||||
|
? uOutIssuerID == uReceiverID
|
||||||
|
? uReceiverID
|
||||||
|
: uOutIssuerID
|
||||||
|
: ACCOUNT_XNS;
|
||||||
|
|
||||||
|
// Can't just use push implied, because it can't compensate for next account.
|
||||||
|
if (!uNxtCurrencyID // Next is XRC - will have offer next
|
||||||
|
|| uInCurrencyID != uNxtCurrencyID // Next is different current - will have offer next
|
||||||
|
|| uInIssuerID != uNxtAccountID) // Next is not implied issuer
|
||||||
|
{
|
||||||
|
// Add implied account.
|
||||||
|
terStatus = pushNode(
|
||||||
|
STPathElement::typeAccount
|
||||||
|
| STPathElement::typeCurrency
|
||||||
|
| STPathElement::typeIssuer,
|
||||||
|
uInIssuerID,
|
||||||
|
uInCurrencyID,
|
||||||
|
uInIssuerID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_FOREACH(const STPathElement& speElement, spSourcePath)
|
BOOST_FOREACH(const STPathElement& speElement, spSourcePath)
|
||||||
{
|
{
|
||||||
@@ -1659,21 +1689,35 @@ PathState::PathState(
|
|||||||
terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID());
|
terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PaymentNode& pnPrv = vpnNodes.back();
|
||||||
|
|
||||||
|
if (tesSUCCESS == terStatus
|
||||||
|
&& !!uOutCurrencyID // Next is not XRC
|
||||||
|
&& uOutIssuerID != uReceiverID // Out issuer is not reciever
|
||||||
|
&& (pnPrv.uCurrencyID != uOutCurrencyID // Previous will be an offer.
|
||||||
|
|| pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer.
|
||||||
|
{
|
||||||
|
// Add implied account.
|
||||||
|
terStatus = pushNode(
|
||||||
|
STPathElement::typeAccount
|
||||||
|
| STPathElement::typeCurrency
|
||||||
|
| STPathElement::typeIssuer,
|
||||||
|
uOutIssuerID,
|
||||||
|
uInCurrencyID,
|
||||||
|
uOutIssuerID);
|
||||||
|
}
|
||||||
|
|
||||||
if (tesSUCCESS == terStatus)
|
if (tesSUCCESS == terStatus)
|
||||||
{
|
{
|
||||||
// Create receiver node.
|
// Create receiver node.
|
||||||
|
|
||||||
terStatus = pushImply(uReceiverID, uOutCurrencyID, uOutIssuerID);
|
terStatus = pushNode(
|
||||||
if (tesSUCCESS == terStatus)
|
STPathElement::typeAccount // Last node is always an account.
|
||||||
{
|
| STPathElement::typeCurrency
|
||||||
terStatus = pushNode(
|
| STPathElement::typeIssuer,
|
||||||
STPathElement::typeAccount // Last node is always an account.
|
uReceiverID, // Receive to output
|
||||||
| STPathElement::typeCurrency
|
uOutCurrencyID, // Desired currency
|
||||||
| STPathElement::typeIssuer,
|
!!uOutCurrencyID ? uReceiverID : ACCOUNT_XNS);
|
||||||
uReceiverID, // Receive to output
|
|
||||||
uOutCurrencyID, // Desired currency
|
|
||||||
uOutIssuerID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tesSUCCESS == terStatus)
|
if (tesSUCCESS == terStatus)
|
||||||
@@ -2065,8 +2109,8 @@ int iPass = 0;
|
|||||||
assert(!!pspCur->saInPass && !!pspCur->saOutPass);
|
assert(!!pspCur->saInPass && !!pspCur->saOutPass);
|
||||||
|
|
||||||
if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality.
|
if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality.
|
||||||
|| !pspBest // Best is not yet set.
|
&& (!pspBest // Best is not yet set.
|
||||||
|| PathState::lessPriority(pspBest, pspCur)) // Current is better than set.
|
|| PathState::lessPriority(pspBest, pspCur))) // Current is better than set.
|
||||||
{
|
{
|
||||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: better: uQuality=%s saInPass=%s saOutPass=%s")
|
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: better: uQuality=%s saInPass=%s saOutPass=%s")
|
||||||
% STAmount::saFromRate(pspCur->uQuality)
|
% STAmount::saFromRate(pspCur->uQuality)
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
|
|||||||
if (childHash != d->getNodeHash())
|
if (childHash != d->getNodeHash())
|
||||||
{
|
{
|
||||||
cLog(lsERROR) << "Wrong hash from cached object";
|
cLog(lsERROR) << "Wrong hash from cached object";
|
||||||
d = SHAMapTreeNode::pointer();
|
d.reset();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -125,22 +125,22 @@
|
|||||||
|
|
||||||
// inner object
|
// inner object
|
||||||
// OBJECT/1 is reserved for end of object
|
// OBJECT/1 is reserved for end of object
|
||||||
FIELD(TemplateEntry, OBJECT, 1)
|
|
||||||
FIELD(TransactionMetaData, OBJECT, 2)
|
FIELD(TransactionMetaData, OBJECT, 2)
|
||||||
FIELD(CreatedNode, OBJECT, 3)
|
FIELD(CreatedNode, OBJECT, 3)
|
||||||
FIELD(DeletedNode, OBJECT, 4)
|
FIELD(DeletedNode, OBJECT, 4)
|
||||||
FIELD(ModifiedNode, OBJECT, 5)
|
FIELD(ModifiedNode, OBJECT, 5)
|
||||||
FIELD(PreviousFields, OBJECT, 6)
|
FIELD(PreviousFields, OBJECT, 6)
|
||||||
FIELD(FinalFields, OBJECT, 7)
|
FIELD(FinalFields, OBJECT, 7)
|
||||||
|
FIELD(TemplateEntry, OBJECT, 8)
|
||||||
|
|
||||||
// array of objects
|
// array of objects
|
||||||
// ARRAY/1 is reserved for end of array
|
// ARRAY/1 is reserved for end of array
|
||||||
FIELD(AffectedNodes, ARRAY, 1)
|
|
||||||
FIELD(SigningAccounts, ARRAY, 2)
|
FIELD(SigningAccounts, ARRAY, 2)
|
||||||
FIELD(TxnSignatures, ARRAY, 3)
|
FIELD(TxnSignatures, ARRAY, 3)
|
||||||
FIELD(Signatures, ARRAY, 4)
|
FIELD(Signatures, ARRAY, 4)
|
||||||
FIELD(Template, ARRAY, 5)
|
FIELD(Template, ARRAY, 5)
|
||||||
FIELD(Necessary, ARRAY, 6)
|
FIELD(Necessary, ARRAY, 6)
|
||||||
FIELD(Sufficient, ARRAY, 7)
|
FIELD(Sufficient, ARRAY, 7)
|
||||||
|
FIELD(AffectedNodes, ARRAY, 8)
|
||||||
|
|
||||||
// vim:ts=4
|
// vim:ts=4
|
||||||
|
|||||||
@@ -283,13 +283,8 @@ void STObject::add(Serializer& s, bool withSigningFields) const
|
|||||||
|
|
||||||
BOOST_FOREACH(const SerializedType& it, mData)
|
BOOST_FOREACH(const SerializedType& it, mData)
|
||||||
{ // pick out the fields and sort them
|
{ // pick out the fields and sort them
|
||||||
if ((it.getSType() != STI_NOTPRESENT) && it.getFName().isBinary())
|
if ((it.getSType() != STI_NOTPRESENT) && it.getFName().shouldInclude(withSigningFields))
|
||||||
{
|
|
||||||
SField::ref fName = it.getFName();
|
|
||||||
if (withSigningFields ||
|
|
||||||
((fName != sfTxnSignature) && (fName != sfTxnSignatures) && (fName != sfSignature)))
|
|
||||||
fields.insert(std::make_pair(it.getFName().fieldCode, &it));
|
fields.insert(std::make_pair(it.getFName().fieldCode, &it));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -603,7 +603,7 @@ public:
|
|||||||
int getElementCount() const { return mPath.size(); }
|
int getElementCount() const { return mPath.size(); }
|
||||||
bool isEmpty() const { return mPath.empty(); }
|
bool isEmpty() const { return mPath.empty(); }
|
||||||
const STPathElement& getElement(int offset) const { return mPath[offset]; }
|
const STPathElement& getElement(int offset) const { return mPath[offset]; }
|
||||||
const STPathElement& getElemet(int offset) { return mPath[offset]; }
|
const STPathElement& getElement(int offset) { return mPath[offset]; }
|
||||||
void addElement(const STPathElement &e) { mPath.push_back(e); }
|
void addElement(const STPathElement &e) { mPath.push_back(e); }
|
||||||
void clear() { mPath.clear(); }
|
void clear() { mPath.clear(); }
|
||||||
bool hasSeen(const uint160 &acct);
|
bool hasSeen(const uint160 &acct);
|
||||||
|
|||||||
@@ -462,7 +462,11 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac
|
|||||||
const bool bMax = txn.isFieldPresent(sfSendMax);
|
const bool bMax = txn.isFieldPresent(sfSendMax);
|
||||||
const uint160 uDstAccountID = txn.getFieldAccount160(sfDestination);
|
const uint160 uDstAccountID = txn.getFieldAccount160(sfDestination);
|
||||||
const STAmount saDstAmount = txn.getFieldAmount(sfAmount);
|
const STAmount saDstAmount = txn.getFieldAmount(sfAmount);
|
||||||
const STAmount saMaxAmount = bMax ? txn.getFieldAmount(sfSendMax) : saDstAmount;
|
const STAmount saMaxAmount = bMax
|
||||||
|
? txn.getFieldAmount(sfSendMax)
|
||||||
|
: saDstAmount.isNative()
|
||||||
|
? saDstAmount
|
||||||
|
: STAmount(saDstAmount.getCurrency(), mTxnAccountID, saDstAmount.getMantissa(), saDstAmount.getExponent(), saDstAmount.isNegative());
|
||||||
const uint160 uSrcCurrency = saMaxAmount.getCurrency();
|
const uint160 uSrcCurrency = saMaxAmount.getCurrency();
|
||||||
const uint160 uDstCurrency = saDstAmount.getCurrency();
|
const uint160 uDstCurrency = saDstAmount.getCurrency();
|
||||||
|
|
||||||
|
|||||||
@@ -464,24 +464,23 @@ buster.testCase("Indirect ripple", {
|
|||||||
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
|
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Set alice's limit.";
|
self.what = "Set credit limits.";
|
||||||
|
|
||||||
testutils.credit_limit(self.remote, "alice", "600/USD/mtgox", callback);
|
testutils.credit_limits(self.remote,
|
||||||
|
{
|
||||||
|
"alice" : "600/USD/mtgox",
|
||||||
|
"bob" : "700/USD/mtgox",
|
||||||
|
},
|
||||||
|
callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Set bob's limit.";
|
self.what = "Distribute funds.";
|
||||||
|
|
||||||
testutils.credit_limit(self.remote, "bob", "700/USD/mtgox", callback);
|
testutils.payments(self.remote,
|
||||||
},
|
{
|
||||||
function (callback) {
|
"mtgox" : [ "70/USD/alice", "50/USD/bob" ],
|
||||||
self.what = "Give alice some mtgox.";
|
},
|
||||||
|
callback);
|
||||||
testutils.payment(self.remote, "mtgox", "alice", "70/USD/mtgox", callback);
|
|
||||||
},
|
|
||||||
function (callback) {
|
|
||||||
self.what = "Give bob some mtgox.";
|
|
||||||
|
|
||||||
testutils.payment(self.remote, "mtgox", "bob", "50/USD/mtgox", callback);
|
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Verify alice balance with mtgox.";
|
self.what = "Verify alice balance with mtgox.";
|
||||||
@@ -534,24 +533,23 @@ buster.testCase("Indirect ripple", {
|
|||||||
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
|
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Set alice's limit.";
|
self.what = "Set credit limits.";
|
||||||
|
|
||||||
testutils.credit_limit(self.remote, "alice", "600/USD/mtgox", callback);
|
testutils.credit_limits(self.remote,
|
||||||
|
{
|
||||||
|
"alice" : "600/USD/mtgox",
|
||||||
|
"bob" : "700/USD/mtgox",
|
||||||
|
},
|
||||||
|
callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Set bob's limit.";
|
self.what = "Distribute funds.";
|
||||||
|
|
||||||
testutils.credit_limit(self.remote, "bob", "700/USD/mtgox", callback);
|
testutils.payments(self.remote,
|
||||||
},
|
{
|
||||||
function (callback) {
|
"mtgox" : [ "70/USD/alice", "50/USD/bob" ],
|
||||||
self.what = "Give alice some mtgox.";
|
},
|
||||||
|
callback);
|
||||||
testutils.payment(self.remote, "mtgox", "alice", "70/USD/mtgox", callback);
|
|
||||||
},
|
|
||||||
function (callback) {
|
|
||||||
self.what = "Give bob some mtgox.";
|
|
||||||
|
|
||||||
testutils.payment(self.remote, "mtgox", "bob", "50/USD/mtgox", callback);
|
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Alice sends via a path";
|
self.what = "Alice sends via a path";
|
||||||
@@ -593,39 +591,24 @@ buster.testCase("Indirect ripple", {
|
|||||||
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "carol", "amazon", "mtgox"], callback);
|
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "carol", "amazon", "mtgox"], callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Set alice's limit with bob.";
|
self.what = "Set credit limits.";
|
||||||
|
|
||||||
testutils.credit_limit(self.remote, "bob", "600/USD/alice", callback);
|
testutils.credit_limits(self.remote,
|
||||||
|
{
|
||||||
|
"amazon" : "2000/USD/mtgox",
|
||||||
|
"bob" : [ "600/USD/alice", "1000/USD/mtgox" ],
|
||||||
|
"carol" : [ "700/USD/alice", "1000/USD/mtgox" ],
|
||||||
|
},
|
||||||
|
callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Set alice's limit with carol.";
|
self.what = "Distribute funds.";
|
||||||
|
|
||||||
testutils.credit_limit(self.remote, "carol", "700/USD/alice", callback);
|
testutils.payments(self.remote,
|
||||||
},
|
{
|
||||||
function (callback) {
|
"mtgox" : [ "100/USD/bob", "100/USD/carol" ],
|
||||||
self.what = "Set bob's mtgox limit.";
|
},
|
||||||
|
callback);
|
||||||
testutils.credit_limit(self.remote, "bob", "1000/USD/mtgox", callback);
|
|
||||||
},
|
|
||||||
function (callback) {
|
|
||||||
self.what = "Set carol's mtgox limit.";
|
|
||||||
|
|
||||||
testutils.credit_limit(self.remote, "carol", "1000/USD/mtgox", callback);
|
|
||||||
},
|
|
||||||
function (callback) {
|
|
||||||
self.what = "Set amazon's mtgox limit.";
|
|
||||||
|
|
||||||
testutils.credit_limit(self.remote, "amazon", "2000/USD/mtgox", callback);
|
|
||||||
},
|
|
||||||
function (callback) {
|
|
||||||
self.what = "Give bob some mtgox.";
|
|
||||||
|
|
||||||
testutils.payment(self.remote, "mtgox", "bob", "100/USD/mtgox", callback);
|
|
||||||
},
|
|
||||||
function (callback) {
|
|
||||||
self.what = "Give carol some mtgox.";
|
|
||||||
|
|
||||||
testutils.payment(self.remote, "mtgox", "carol", "100/USD/mtgox", callback);
|
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Alice pays amazon via multiple paths";
|
self.what = "Alice pays amazon via multiple paths";
|
||||||
@@ -642,29 +625,84 @@ buster.testCase("Indirect ripple", {
|
|||||||
.submit();
|
.submit();
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Verify amazon balance with mtgox.";
|
self.what = "Verify balances.";
|
||||||
|
|
||||||
testutils.verify_balance(self.remote, "amazon", "150/USD/mtgox", callback);
|
testutils.verify_balances(self.remote,
|
||||||
|
{
|
||||||
|
"alice" : [ "-100/USD/bob", "-50/USD/carol" ],
|
||||||
|
"amazon" : "150/USD/mtgox",
|
||||||
|
"bob" : "0/USD/mtgox",
|
||||||
|
"carol" : "50/USD/mtgox",
|
||||||
|
},
|
||||||
|
callback);
|
||||||
|
},
|
||||||
|
], function (error) {
|
||||||
|
buster.refute(error, self.what);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
"indirect ripple with path and transfer fee" :
|
||||||
|
function (done) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
function (callback) {
|
||||||
|
self.what = "Create accounts.";
|
||||||
|
|
||||||
|
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "carol", "amazon", "mtgox"], callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Verify alice balance with bob.";
|
self.what = "Set mtgox transfer rate.";
|
||||||
|
|
||||||
testutils.verify_balance(self.remote, "alice", "-50/USD/bob", callback);
|
testutils.transfer_rate(self.remote, "mtgox", 1.1e9, callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Verify alice balance with carol.";
|
self.what = "Set credit limits.";
|
||||||
|
|
||||||
testutils.verify_balance(self.remote, "alice", "-100/USD/carol", callback);
|
testutils.credit_limits(self.remote,
|
||||||
|
{
|
||||||
|
"amazon" : "2000/USD/mtgox",
|
||||||
|
"bob" : [ "600/USD/alice", "1000/USD/mtgox" ],
|
||||||
|
"carol" : [ "700/USD/alice", "1000/USD/mtgox" ],
|
||||||
|
},
|
||||||
|
callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Verify bob balance with mtgox.";
|
self.what = "Distribute funds.";
|
||||||
|
|
||||||
testutils.verify_balance(self.remote, "bob", "50/USD/mtgox", callback);
|
testutils.payments(self.remote,
|
||||||
|
{
|
||||||
|
"mtgox" : [ "100/USD/bob", "100/USD/carol" ],
|
||||||
|
},
|
||||||
|
callback);
|
||||||
},
|
},
|
||||||
function (callback) {
|
function (callback) {
|
||||||
self.what = "Verify carol balance with mtgox.";
|
self.what = "Alice pays amazon via multiple paths";
|
||||||
|
|
||||||
testutils.verify_balance(self.remote, "carol", "0/USD/mtgox", callback);
|
self.remote.transaction()
|
||||||
|
.payment("alice", "amazon", "150/USD/mtgox")
|
||||||
|
.send_max("200/USD/alice")
|
||||||
|
.path_add( [ { account: "bob" } ])
|
||||||
|
.path_add( [ { account: "carol" } ])
|
||||||
|
.on('proposed', function (m) {
|
||||||
|
// console.log("proposed: %s", JSON.stringify(m));
|
||||||
|
|
||||||
|
callback(m.result != 'tesSUCCESS');
|
||||||
|
})
|
||||||
|
.submit();
|
||||||
|
},
|
||||||
|
function (callback) {
|
||||||
|
self.what = "Verify balances.";
|
||||||
|
|
||||||
|
testutils.verify_balances(self.remote,
|
||||||
|
{
|
||||||
|
"alice" : [ "-100/USD/bob", "-65.00000000000001/USD/carol" ],
|
||||||
|
"amazon" : "150/USD/mtgox",
|
||||||
|
"bob" : "0/USD/mtgox",
|
||||||
|
"carol" : "35/USD/mtgox",
|
||||||
|
},
|
||||||
|
callback);
|
||||||
},
|
},
|
||||||
], function (error) {
|
], function (error) {
|
||||||
buster.refute(error, self.what);
|
buster.refute(error, self.what);
|
||||||
@@ -672,9 +710,6 @@ buster.testCase("Indirect ripple", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
// Direct ripple without no liqudity.
|
// Direct ripple without no liqudity.
|
||||||
// Ripple without credit path.
|
// Test with XRC at start and end.
|
||||||
// Ripple with one-way credit path.
|
|
||||||
// Transfer Fees
|
|
||||||
// Use multiple paths.
|
|
||||||
});
|
});
|
||||||
// vim:sw=2:sts=2:ts=8
|
// vim:sw=2:sts=2:ts=8
|
||||||
|
|||||||
@@ -129,6 +129,30 @@ var credit_limit = function (remote, src, amount, callback) {
|
|||||||
.submit();
|
.submit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var credit_limits = function (remote, balances, callback) {
|
||||||
|
assert(3 === arguments.length);
|
||||||
|
|
||||||
|
var limits = [];
|
||||||
|
|
||||||
|
for (var src in balances) {
|
||||||
|
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] } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async.every(limits,
|
||||||
|
function (limit, callback) {
|
||||||
|
credit_limit(remote, limit.source, limit.amount,
|
||||||
|
function (mismatch) { callback(!mismatch); });
|
||||||
|
},
|
||||||
|
function (every) {
|
||||||
|
callback(!every);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
var payment = function (remote, src, dst, amount, callback) {
|
var payment = function (remote, src, dst, amount, callback) {
|
||||||
assert(5 === arguments.length);
|
assert(5 === arguments.length);
|
||||||
|
|
||||||
@@ -147,27 +171,110 @@ var payment = function (remote, src, dst, amount, callback) {
|
|||||||
.submit();
|
.submit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var payments = function (remote, balances, callback) {
|
||||||
|
assert(3 === arguments.length);
|
||||||
|
|
||||||
|
var sends = [];
|
||||||
|
|
||||||
|
for (var src in balances) {
|
||||||
|
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];
|
||||||
|
var amount = Amount.from_json(amount_json);
|
||||||
|
|
||||||
|
sends.push( { "source" : src, "destination" : amount.issuer.to_json(), "amount" : amount_json } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async.every(sends,
|
||||||
|
function (send, callback) {
|
||||||
|
payment(remote, send.source, send.destination, send.amount,
|
||||||
|
function (mismatch) { callback(!mismatch); });
|
||||||
|
},
|
||||||
|
function (every) {
|
||||||
|
callback(!every);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var transfer_rate = function (remote, src, billionths, callback) {
|
||||||
|
assert(4 === arguments.length);
|
||||||
|
|
||||||
|
remote.transaction()
|
||||||
|
.account_set(src)
|
||||||
|
.transfer_rate(billionths)
|
||||||
|
.on('proposed', function (m) {
|
||||||
|
// console.log("proposed: %s", JSON.stringify(m));
|
||||||
|
|
||||||
|
callback(m.result != 'tesSUCCESS');
|
||||||
|
})
|
||||||
|
.on('error', function (m) {
|
||||||
|
// console.log("error: %s", JSON.stringify(m));
|
||||||
|
|
||||||
|
callback(m);
|
||||||
|
})
|
||||||
|
.submit();
|
||||||
|
};
|
||||||
|
|
||||||
var verify_balance = function (remote, src, amount_json, callback) {
|
var verify_balance = function (remote, src, amount_json, callback) {
|
||||||
assert(4 === arguments.length);
|
assert(4 === arguments.length);
|
||||||
var amount = Amount.from_json(amount_json);
|
var amount = Amount.from_json(amount_json);
|
||||||
|
|
||||||
remote.request_ripple_balance(src, amount.issuer.to_json(), amount.currency.to_json(), 'CURRENT')
|
if (amount.is_native()) {
|
||||||
.once('ripple_state', function (m) {
|
// XXX Not implemented.
|
||||||
// console.log("BALANCE: %s", JSON.stringify(m));
|
callback(false);
|
||||||
// console.log("account_balance: %s", m.account_balance.to_text_full());
|
}
|
||||||
// console.log("account_limit: %s", m.account_limit.to_text_full());
|
else {
|
||||||
// console.log("issuer_balance: %s", m.issuer_balance.to_text_full());
|
remote.request_ripple_balance(src, amount.issuer.to_json(), amount.currency.to_json(), 'CURRENT')
|
||||||
// console.log("issuer_limit: %s", m.issuer_limit.to_text_full());
|
.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());
|
||||||
|
|
||||||
callback(!m.account_balance.equals(amount));
|
if (!m.account_balance.equals(amount)) {
|
||||||
})
|
console.log("verify_balance: failed: %s vs %s is %s", src, amount_json, amount.to_text_full());
|
||||||
.request();
|
}
|
||||||
|
|
||||||
|
callback(!m.account_balance.equals(amount));
|
||||||
|
})
|
||||||
|
.request();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (var index in values) {
|
||||||
|
tests.push( { "source" : src, "amount" : values[index] } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async.every(tests,
|
||||||
|
function (check, callback) {
|
||||||
|
verify_balance(remote, check.source, check.amount,
|
||||||
|
function (mismatch) { callback(!mismatch); });
|
||||||
|
},
|
||||||
|
function (every) {
|
||||||
|
callback(!every);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
exports.build_setup = build_setup;
|
exports.build_setup = build_setup;
|
||||||
exports.create_accounts = create_accounts;
|
exports.create_accounts = create_accounts;
|
||||||
exports.credit_limit = credit_limit;
|
exports.credit_limit = credit_limit;
|
||||||
|
exports.credit_limits = credit_limits;
|
||||||
exports.payment = payment;
|
exports.payment = payment;
|
||||||
|
exports.payments = payments;
|
||||||
exports.build_teardown = build_teardown;
|
exports.build_teardown = build_teardown;
|
||||||
|
exports.transfer_rate = transfer_rate;
|
||||||
exports.verify_balance = verify_balance;
|
exports.verify_balance = verify_balance;
|
||||||
|
exports.verify_balances = verify_balances;
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8
|
// vim:sw=2:sts=2:ts=8
|
||||||
|
|||||||
Reference in New Issue
Block a user