mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
@@ -232,6 +232,11 @@ var Currency = function () {
|
||||
this.value = NaN;
|
||||
}
|
||||
|
||||
// Given "USD" return the json.
|
||||
Currency.json_rewrite = function(j) {
|
||||
return Currency.from_json(j).to_json();
|
||||
};
|
||||
|
||||
Currency.from_json = function (j) {
|
||||
return (new Currency()).parse_json(j);
|
||||
};
|
||||
|
||||
46
js/remote.js
46
js/remote.js
@@ -980,6 +980,43 @@ Transaction.prototype.submit = function () {
|
||||
// Set options for Transactions
|
||||
//
|
||||
|
||||
Transaction._path_rewrite = function (path) {
|
||||
var path_new = [];
|
||||
|
||||
for (var index in path) {
|
||||
var node = path[index];
|
||||
var node_new = {};
|
||||
|
||||
if ('account' in node)
|
||||
node_new.account = UInt160.json_rewrite(node.account);
|
||||
if ('issuer' in node)
|
||||
node_new.issuer = UInt160.json_rewrite(node.issuer);
|
||||
if ('currency' in node)
|
||||
node_new.currency = Currency.json_rewrite(node.currency);
|
||||
|
||||
path_new.push(node_new);
|
||||
}
|
||||
|
||||
return path_new;
|
||||
}
|
||||
|
||||
Transaction.prototype.path_add = function (path) {
|
||||
this.transaction.Paths = this.transaction.Paths || []
|
||||
this.transaction.Paths.push(Transaction._path_rewrite(path));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// --> paths: undefined or array of path
|
||||
// A path is an array of objects containing some combination of: account, currency, issuer
|
||||
Transaction.prototype.paths = function (paths) {
|
||||
for (var index in paths) {
|
||||
this.path_add(paths[index]);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// If the secret is in the config object, it does not need to be provided.
|
||||
Transaction.prototype.secret = function (secret) {
|
||||
this.secret = secret;
|
||||
@@ -987,7 +1024,7 @@ Transaction.prototype.secret = function (secret) {
|
||||
|
||||
Transaction.prototype.send_max = function (send_max) {
|
||||
if (send_max)
|
||||
this.transaction.SendMax = send_max.to_json();
|
||||
this.transaction.SendMax = Amount.json_rewrite(send_max);
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -1105,6 +1142,13 @@ Transaction.prototype.password_set = function (src, authorized_key, generator, p
|
||||
// --> src : UInt160 or String
|
||||
// --> dst : UInt160 or String
|
||||
// --> deliver_amount : Amount or String.
|
||||
//
|
||||
// Options:
|
||||
// .paths()
|
||||
// .path_add()
|
||||
// .secret()
|
||||
// .send_max()
|
||||
// .set_flags()
|
||||
Transaction.prototype.payment = function (src, dst, deliver_amount) {
|
||||
this.secret = this._account_secret(src);
|
||||
this.transaction.TransactionType = 'Payment';
|
||||
|
||||
@@ -1421,6 +1421,8 @@ bool PathState::lessPriority(PathState::ref lhs, PathState::ref rhs)
|
||||
|
||||
// Make sure the path 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.
|
||||
//
|
||||
// Rules:
|
||||
// - Currencies must be converted via an offer.
|
||||
// - A node names it's output.
|
||||
@@ -1449,13 +1451,14 @@ TER PathState::pushImply(
|
||||
ACCOUNT_ONE, // Placeholder for offers.
|
||||
uCurrencyID, // The offer's output is what is now wanted.
|
||||
uIssuerID);
|
||||
|
||||
}
|
||||
|
||||
const PaymentNode& pnBck = vpnNodes.back();
|
||||
|
||||
// For ripple, non-stamps, ensure the issuer is on at least one side of the transaction.
|
||||
if (tesSUCCESS == terResult
|
||||
&& !!uCurrencyID // Not stamps.
|
||||
&& (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs.
|
||||
&& (pnBck.uAccountID != uIssuerID // Previous is not issuing own IOUs.
|
||||
&& uAccountID != uIssuerID)) // Current is not receiving own IOUs.
|
||||
{
|
||||
// Need to ripple through uIssuerID's account.
|
||||
@@ -1514,13 +1517,19 @@ TER PathState::pushNode(
|
||||
pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID);
|
||||
pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID);
|
||||
|
||||
if (!bFirst)
|
||||
if (bFirst)
|
||||
{
|
||||
// The first node is always correct as is.
|
||||
|
||||
nothing();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add required intermediate nodes to deliver to current account.
|
||||
terResult = pushImply(
|
||||
pnCur.uAccountID, // Current account.
|
||||
pnCur.uCurrencyID, // Wanted currency.
|
||||
!!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer.
|
||||
!!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as wanted issuer.
|
||||
|
||||
// Note: pnPrv may no longer be the immediately previous node.
|
||||
}
|
||||
@@ -1532,7 +1541,7 @@ TER PathState::pushNode(
|
||||
|
||||
if (bBckAccount)
|
||||
{
|
||||
SLE::pointer sleRippleState = mLedger->getSLE(Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID));
|
||||
SLE::pointer sleRippleState = lesEntries.entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID));
|
||||
|
||||
if (!sleRippleState)
|
||||
{
|
||||
@@ -1541,7 +1550,7 @@ TER PathState::pushNode(
|
||||
<< " and "
|
||||
<< RippleAddress::createHumanAccountID(pnCur.uAccountID)
|
||||
<< " for "
|
||||
<< STAmount::createHumanCurrency(pnPrv.uCurrencyID)
|
||||
<< STAmount::createHumanCurrency(pnCur.uCurrencyID)
|
||||
<< "." ;
|
||||
|
||||
cLog(lsINFO) << getJson();
|
||||
@@ -1555,12 +1564,12 @@ TER PathState::pushNode(
|
||||
<< " and "
|
||||
<< RippleAddress::createHumanAccountID(pnCur.uAccountID)
|
||||
<< " for "
|
||||
<< STAmount::createHumanCurrency(pnPrv.uCurrencyID)
|
||||
<< STAmount::createHumanCurrency(pnCur.uCurrencyID)
|
||||
<< "." ;
|
||||
|
||||
STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, uCurrencyID);
|
||||
STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID);
|
||||
|
||||
if (!saOwed.isPositive() && *saOwed.negate() >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, uCurrencyID))
|
||||
if (!saOwed.isPositive() && *saOwed.negate() >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID))
|
||||
{
|
||||
terResult = tepPATH_DRY;
|
||||
}
|
||||
|
||||
@@ -1112,23 +1112,24 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
|
||||
data.push_back(new STPathSet(field));
|
||||
STPathSet* tail = dynamic_cast<STPathSet*>(&data.back());
|
||||
assert(tail);
|
||||
for (Json::UInt i = 0; !object.isValidIndex(i); ++i)
|
||||
for (Json::UInt i = 0; value.isValidIndex(i); ++i)
|
||||
{
|
||||
STPath p;
|
||||
if (!object[i].isArray())
|
||||
if (!value[i].isArray())
|
||||
throw std::runtime_error("Path must be array");
|
||||
for (Json::UInt j = 0; !object[i].isValidIndex(j); ++j)
|
||||
for (Json::UInt j = 0; value[i].isValidIndex(j); ++j)
|
||||
{ // each element in this path has some combination of account, currency, or issuer
|
||||
|
||||
Json::Value pathEl = object[i][j];
|
||||
Json::Value pathEl = value[i][j];
|
||||
if (!pathEl.isObject())
|
||||
throw std::runtime_error("Path elements must be objects");
|
||||
const Json::Value& account = pathEl["account"];
|
||||
const Json::Value& currency = pathEl["currency"];
|
||||
const Json::Value& issuer = pathEl["issuer"];
|
||||
|
||||
const Json::Value& account = pathEl["account"];
|
||||
const Json::Value& currency = pathEl["currency"];
|
||||
const Json::Value& issuer = pathEl["issuer"];
|
||||
bool hasCurrency = false;
|
||||
uint160 uAccount, uCurrency, uIssuer;
|
||||
bool hasCurrency;
|
||||
|
||||
if (!account.isNull())
|
||||
{ // human account id
|
||||
if (!account.isString())
|
||||
@@ -1138,7 +1139,7 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
|
||||
uAccount.SetHex(strValue);
|
||||
{
|
||||
RippleAddress a;
|
||||
if (!a.setAccountPublic(strValue))
|
||||
if (!a.setAccountID(strValue))
|
||||
throw std::runtime_error("Account in path element invalid");
|
||||
uAccount = a.getAccountID();
|
||||
}
|
||||
@@ -1162,7 +1163,7 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
|
||||
else
|
||||
{
|
||||
RippleAddress a;
|
||||
if (!a.setAccountPublic(issuer.asString()))
|
||||
if (!a.setAccountID(issuer.asString()))
|
||||
throw std::runtime_error("path element issuer invalid");
|
||||
uIssuer = a.getAccountID();
|
||||
}
|
||||
|
||||
@@ -523,6 +523,65 @@ buster.testCase("Indirect ripple", {
|
||||
});
|
||||
},
|
||||
|
||||
"indirect ripple with path" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
async.waterfall([
|
||||
function (callback) {
|
||||
self.what = "Create accounts.";
|
||||
|
||||
testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set alice's limit.";
|
||||
|
||||
testutils.credit_limit(self.remote, "alice", "600/USD/mtgox", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set bob's limit.";
|
||||
|
||||
testutils.credit_limit(self.remote, "bob", "700/USD/mtgox", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Give alice some mtgox.";
|
||||
|
||||
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) {
|
||||
self.what = "Alice sends via a path";
|
||||
|
||||
self.remote.transaction()
|
||||
.payment("alice", "bob", "5/USD/mtgox")
|
||||
.path_add( [ { account: "mtgox" } ])
|
||||
.on('proposed', function (m) {
|
||||
// console.log("proposed: %s", JSON.stringify(m));
|
||||
|
||||
callback(m.result != 'tesSUCCESS');
|
||||
})
|
||||
.submit();
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify alice balance with mtgox.";
|
||||
|
||||
testutils.verify_balance(self.remote, "alice", "65/USD/mtgox", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify bob balance with mtgox.";
|
||||
|
||||
testutils.verify_balance(self.remote, "bob", "55/USD/mtgox", callback);
|
||||
},
|
||||
], function (error) {
|
||||
buster.refute(error, self.what);
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
// Direct ripple without no liqudity.
|
||||
// Ripple without credit path.
|
||||
// Ripple with one-way credit path.
|
||||
|
||||
Reference in New Issue
Block a user